Update valid device name pattern

PiperOrigin-RevId: 803371244
diff --git a/ui_automator/ui_automator.py b/ui_automator/ui_automator.py
index 96d9222..aacd2df 100644
--- a/ui_automator/ui_automator.py
+++ b/ui_automator/ui_automator.py
@@ -123,6 +123,13 @@
 _NO_DEVICE_CONNECTED_ERROR_MESSAGE = (
     'No Android device connected to the host computer.'
 )
+# Aligned with
+# http://google3/java/com/google/assistant/verticals/homeautomation/partners/testsuite/client/constants.ts?q=symbol:%5CbVALID_DEVICE_NAME_ON_GHA_PATTERN%5Cb.
+_VALID_DEVICE_NAME_PATTERN = r'^(?=.*[a-zA-Z0-9])[a-zA-Z0-9 \']{1,24}$'
+_INVALID_DEVICE_NAME_ERROR_MESSAGE = (
+    'Value of DeviceName is invalid. Device name should be no more than'
+    ' 24 characters and no special characters.'
+)
 
 
 class RegTestSuiteType(enum.Enum):
@@ -143,7 +150,7 @@
   Raises:
       ValueError: When any of passed arguments is invalid.
   """
-  device_name_match = re.fullmatch(r'\S{1,24}', device_name)
+  device_name_match = re.fullmatch(_VALID_DEVICE_NAME_PATTERN, device_name)
   pairing_code_match = re.fullmatch(r'^(\d{11}|\d{21})$', pairing_code)
   gha_room_match = re.fullmatch(
       r'Attic|Back door|Backyard|Basement|Bathroom|Bedroom|Den|Dining'
@@ -154,10 +161,7 @@
   )
 
   if not device_name_match:
-    raise ValueError(
-        'Value of DeviceName is invalid. Device name should be no more than 24'
-        ' characters.'
-    )
+    raise ValueError(_INVALID_DEVICE_NAME_ERROR_MESSAGE)
   if not pairing_code_match:
     raise ValueError(
         'Value of PairingCode is invalid. Paring code should be 11-digit or'
@@ -358,11 +362,8 @@
         MoblySnippetError: When running `removeDeviceFromGha` method in snippet
         apk encountered an error.
     """
-    if not re.fullmatch(r'\S{1,24}', device_name):
-      raise ValueError(
-          'Value of DeviceName is invalid. Device name should be no more than'
-          ' 24 characters.'
-      )
+    if not re.fullmatch(_VALID_DEVICE_NAME_PATTERN, device_name):
+      raise ValueError(_INVALID_DEVICE_NAME_ERROR_MESSAGE)
 
     self._logger.info('Start removing the device.')
     try:
diff --git a/ui_automator/ui_automator_test.py b/ui_automator/ui_automator_test.py
index f01b0f4..0236b66 100644
--- a/ui_automator/ui_automator_test.py
+++ b/ui_automator/ui_automator_test.py
@@ -35,8 +35,9 @@
 from ui_automator import ui_automator
 from ui_automator import unit_test_utils
 from ui_automator import version
+from google3.testing.pybase import parameterized
 
-_FAKE_MATTER_DEVICE_NAME = 'fake-matter-device-name'
+_FAKE_MATTER_DEVICE_NAME = 'fake matter device name'
 _FAKE_GHA_ROOM = 'Office'
 _FAKE_PAIRING_CODE = '34970112332'
 _PYTHON_PATH = subprocess.check_output(['which', 'python']).decode('utf-8')
@@ -79,7 +80,7 @@
 _FAKE_GOOGLE_ACCOUNT = 'fake_google_account'
 
 
-class UIAutomatorTest(unittest.TestCase):
+class UIAutomatorTest(parameterized.TestCase):
 
   def setUp(self):
     """This method will be run before each of the test methods in the class."""
@@ -502,18 +503,30 @@
 
     self.assertIn(expected_error_message, str(exc.exception))
 
+  @parameterized.named_parameters(
+      dict(
+          testcase_name='device_name_exceeds_limit',
+          invalid_device_name='fakeDeviceNameWith25Chars',
+          expected_error_message=ui_automator._INVALID_DEVICE_NAME_ERROR_MESSAGE,
+      ),
+      dict(
+          testcase_name='device_name_contains_only_spaces',
+          invalid_device_name='   ',
+          expected_error_message=ui_automator._INVALID_DEVICE_NAME_ERROR_MESSAGE,
+      ),
+      dict(
+          testcase_name='device_name_contains_special_characters',
+          invalid_device_name='test_device',
+          expected_error_message=ui_automator._INVALID_DEVICE_NAME_ERROR_MESSAGE,
+      ),
+  )
   @mock.patch.object(android_device, 'get_all_instances', autospec=True)
-  def test_commission_device_raises_an_error_when_device_name_exceeds_limit(
-      self, mock_get_all_instances
+  def test_commission_device_raises_an_error_when(
+      self, mock_get_all_instances, invalid_device_name, expected_error_message
   ):
-    invalid_device_name = 'fakeDeviceNameWith25Chars'
     mock_get_all_instances.return_value = [self.mock_android_device]
 
-    with self.assertRaisesRegex(
-        ValueError,
-        'Value of DeviceName is invalid. Device name should be no more than 24'
-        ' characters.',
-    ):
+    with self.assertRaisesRegex(ValueError, expected_error_message):
       self.ui_automator.commission_device(
           invalid_device_name,
           _FAKE_PAIRING_CODE,