chromeos-config: Add flags and ids to camera schema

Following crrev.com/c/2413928 that removes camera id, this CL adds below
fields to camera config:
- flags: characterizes a camera by capabilities
- ids: narrows down selectable camera modules

BUG=b:163436311
TEST=cros_config_host/cros_config_schema_unittest.py

Cq-Depend: chromium:2435136
Change-Id: I389609d80b8734490468adaf32b19775b3910d79
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2434716
Tested-by: Ren-Pei Zeng <kamesan@chromium.org>
Commit-Queue: Ren-Pei Zeng <kamesan@chromium.org>
Reviewed-by: Shik Chen <shik@chromium.org>
Reviewed-by: David Burger <dburger@chromium.org>
(cherry picked from commit 0eaa1138c66e766ffea0104d2c0437f5c6183a54)
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2570889
Reviewed-by: Pin-yen Lin <treapking@chromium.org>
Commit-Queue: Pin-yen Lin <treapking@chromium.org>
Tested-by: Pin-yen Lin <treapking@chromium.org>
diff --git a/chromeos-config/README.md b/chromeos-config/README.md
index 2106195..6e6dbbd 100644
--- a/chromeos-config/README.md
+++ b/chromeos-config/README.md
@@ -424,9 +424,17 @@
 | Attribute | Type   | RegEx     | Required | Oneof Group | Build-only | Description |
 | --------- | ------ | --------- | -------- | ----------- | ---------- | ----------- |
 | facing | string |  | True |  | False | Direction the camera faces relative to device screen. |
+| flags | [flags](#flags) |  | True |  | False | Bit flags representing camera capabilities of this device. A camera module can be mounted on this slot only if all the flags match. |
+| ids | array - string |  | False |  | False | An identifier string of camera module. For USB cameras this must be 4-digit hexadecimal VID and PID separated by a colon, e.g. 0123:abcd. For MIPI cameras it depends on vendor software usage. |
 | interface | string |  | True |  | False | The interface type of the camera device. |
 | orientation | integer |  | True |  | False | Clockwise angle through which the output image needs to be rotated to be upright on the device screen in its native orientation. |
 
+### flags
+| Attribute | Type   | RegEx     | Required | Oneof Group | Build-only | Description |
+| --------- | ------ | --------- | -------- | ----------- | ---------- | ----------- |
+| support-1080p | boolean |  | True |  | False | Supports 1920x1080 resolution. |
+| support-autofocus | boolean |  | True |  | False | Supports auto-focus. |
+
 ### cros-healthd
 | Attribute | Type   | RegEx     | Required | Oneof Group | Build-only | Description |
 | --------- | ------ | --------- | -------- | ----------- | ---------- | ----------- |
diff --git a/chromeos-config/cros_config_host/cros_config_schema.yaml b/chromeos-config/cros_config_host/cros_config_schema.yaml
index 6e0b05b..9021a72 100644
--- a/chromeos-config/cros_config_host/cros_config_schema.yaml
+++ b/chromeos-config/cros_config_host/cros_config_schema.yaml
@@ -381,10 +381,47 @@
                         - 90
                         - 180
                         - 270
+                      flags:
+                        type: object
+                        description: Bit flags representing camera capabilities
+                          of this device. A camera module can be mounted on this
+                          slot only if all the flags match.
+                        properties:
+                          support-1080p:
+                            type: boolean
+                            description: Supports 1920x1080 resolution.
+                          support-autofocus:
+                            type: boolean
+                            description: Supports auto-focus.
+                        required:
+                        - support-1080p
+                        - support-autofocus
+                        additionalProperties: false
+                      ids:
+                        type: array
+                        description: List of strings each identifies a possible
+                          camera module on this slot. An empty list means this
+                          information is not available.
+                        items:
+                          type: string
+                          description: An identifier string of camera module.
+                            For USB cameras this must be 4-digit hexadecimal VID
+                            and PID separated by a colon, e.g. 0123:abcd. For
+                            MIPI cameras it depends on vendor software usage.
+                    if:
+                      properties:
+                        interface:
+                          const: usb
+                    then:
+                      properties:
+                        ids:
+                          items:
+                            pattern: "[0-9a-f]{4}:[0-9a-f]{4}"
                     required:
                     - interface
                     - facing
                     - orientation
+                    - flags
                     additionalProperties: false
               additionalProperties: false
             fingerprint:
diff --git a/chromeos-config/cros_config_host/cros_config_schema_unittest.py b/chromeos-config/cros_config_host/cros_config_schema_unittest.py
index ccf17ff..c6d2afb 100755
--- a/chromeos-config/cros_config_host/cros_config_schema_unittest.py
+++ b/chromeos-config/cros_config_host/cros_config_schema_unittest.py
@@ -315,11 +315,20 @@
                                 'interface': 'usb',
                                 'facing': 'front',
                                 'orientation': 180,
+                                'flags': {
+                                    'support-1080p': False,
+                                    'support-autofocus': False,
+                                },
+                                'ids': ['0123:abcd', '4567:efef'],
                             },
                             {
                                 'interface': 'mipi',
                                 'facing': 'back',
                                 'orientation': 0,
+                                'flags': {
+                                    'support-1080p': True,
+                                    'support-autofocus': True,
+                                },
                             },
                         ],
                     }
@@ -330,6 +339,41 @@
     libcros_schema.ValidateConfigSchema(self._schema,
                                         libcros_schema.FormatJson(config))
 
+  def testInvalidUsbId(self):
+    if version.parse(jsonschema.__version__) < version.Version('3.0.0'):
+      self.skipTest('jsonschema needs upgrade to support conditionals')
+
+    for invalid_usb_id in ('0123-abcd', '0123:Abcd', '123:abcd'):
+      config = {
+          'chromeos': {
+              'configs': [
+                  {
+                      'identity': {'platform-name': 'foo', 'sku-id': 1},
+                      'name': 'foo',
+                      'camera': {
+                          'count': 1,
+                          'devices': [
+                              {
+                                  'interface': 'usb',
+                                  'facing': 'front',
+                                  'orientation': 0,
+                                  'flags': {
+                                      'support-1080p': False,
+                                      'support-autofocus': True,
+                                  },
+                                  'ids': [invalid_usb_id],
+                              },
+                          ],
+                      }
+                  },
+              ],
+          },
+      }
+      with self.assertRaises(jsonschema.ValidationError) as ctx:
+        libcros_schema.ValidateConfigSchema(self._schema,
+                                            libcros_schema.FormatJson(config))
+      self.assertIn('%r does not match' % invalid_usb_id, str(ctx.exception))
+
 
 WHITELABEL_CONFIG = """
 chromeos: