Camera: Add bokeh mode tags in camera metadata

Introduce new bokeh mode metadata tags for camera device to enable bokeh
effect.

Test: Build and read docs
Bug: 118258123
Change-Id: I99b85fe60ee8af008592922ae2cce64be33e88a2
diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal
index 0fec947..b9451c8 100644
--- a/camera/metadata/3.5/types.hal
+++ b/camera/metadata/3.5/types.hal
@@ -28,10 +28,43 @@
 
 // No new metadata sections added in this revision
 
+/**
+ * Main enumeration for defining camera metadata tags added in this revision
+ *
+ * <p>Partial documentation is included for each tag; for complete documentation, reference
+ * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
+ */
+enum CameraMetadataTag : @3.4::CameraMetadataTag {
+    /** android.control.availableBokehCapabilities [static, int32[], public]
+     *
+     * <p>The list of bokeh modes that are supported by this camera device, and each bokeh mode's
+     * maximum streaming (non-stall) size with bokeh effect.</p>
+     */
+    ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+
+    /** android.control.bokehMode [dynamic, enum, public]
+     *
+     * <p>Whether bokeh mode is enabled for a particular capture request.</p>
+     */
+    ANDROID_CONTROL_BOKEH_MODE,
+
+    ANDROID_CONTROL_END_3_5,
+
+};
+
 /*
  * Enumeration definitions for the various entries that need them
  */
 
+/** android.control.bokehMode enumeration values
+ * @see ANDROID_CONTROL_BOKEH_MODE
+ */
+enum CameraMetadataEnumAndroidControlBokehMode : uint32_t {
+    ANDROID_CONTROL_BOKEH_MODE_OFF,
+    ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE,
+    ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS,
+};
+
 /** android.request.availableCapabilities enumeration values added since v3.4
  * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
  */
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 67d5bbe..1b0d7cb 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -778,6 +778,7 @@
             const CameraMetadata& chars, int deviceVersion,
             const hidl_vec<hidl_string>& deviceNames);
     void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
+    void verifyBokehCharacteristics(const camera_metadata_t* metadata);
     void verifyRecommendedConfigs(const CameraMetadata& metadata);
     void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
     void verifyMonochromeCameraResult(
@@ -801,7 +802,7 @@
 
     bool isDepthOnly(camera_metadata_t* staticMeta);
 
-    static Status getAvailableOutputStreams(camera_metadata_t *staticMeta,
+    static Status getAvailableOutputStreams(const camera_metadata_t *staticMeta,
             std::vector<AvailableStream> &outputStreams,
             const AvailableStream *threshold = nullptr);
     static Status getJpegBufferSize(camera_metadata_t *staticMeta,
@@ -4856,7 +4857,7 @@
 
 // Retrieve all valid output stream resolutions from the camera
 // static characteristics.
-Status CameraHidlTest::getAvailableOutputStreams(camera_metadata_t *staticMeta,
+Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t *staticMeta,
         std::vector<AvailableStream> &outputStreams,
         const AvailableStream *threshold) {
     AvailableStream depthPreviewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -5839,6 +5840,101 @@
             ADD_FAILURE() << "Get Heic maxJpegAppSegmentsCount failed!";
         }
     }
+
+    verifyBokehCharacteristics(metadata);
+}
+
+void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadata) {
+    camera_metadata_ro_entry entry;
+    int retcode = 0;
+
+    // Check key availability in capabilities, request and result.
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+    bool hasBokehRequestKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasBokehRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_BOKEH_MODE) != entry.data.i32+entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+    bool hasBokehResultKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasBokehResultKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_BOKEH_MODE) != entry.data.i32+entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableResultKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+    bool hasBokehCharacteristicsKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasBokehCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES) != entry.data.i32+entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
+    }
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES, &entry);
+    bool hasAvailableBokehCaps = (0 == retcode && entry.count > 0);
+
+    // Bokeh keys must all be available, or all be unavailable.
+    bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehCharacteristicsKey &&
+            !hasAvailableBokehCaps;
+    if (noBokeh) {
+        return;
+    }
+    bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehCharacteristicsKey &&
+            hasAvailableBokehCaps;
+    ASSERT_TRUE(hasBokeh);
+
+    // Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS.
+    ASSERT_TRUE(entry.count == 6 || entry.count == 9);
+    bool hasOffMode = false;
+    bool hasStillCaptureMode = false;
+    bool hasContinuousMode = false;
+    std::vector<AvailableStream> outputStreams;
+    ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams));
+    for (int i = 0; i < entry.count; i += 3) {
+        int32_t mode = entry.data.i32[i];
+        int32_t maxWidth = entry.data.i32[i+1];
+        int32_t maxHeight = entry.data.i32[i+2];
+        switch (mode) {
+            case ANDROID_CONTROL_BOKEH_MODE_OFF:
+                hasOffMode = true;
+                ASSERT_TRUE(maxWidth == 0 && maxHeight == 0);
+                break;
+            case ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE:
+                hasStillCaptureMode = true;
+                break;
+            case ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS:
+                hasContinuousMode = true;
+                break;
+            default:
+                ADD_FAILURE() << "Invalid bokehMode advertised: " << mode;
+                break;
+        }
+
+        if (mode != ANDROID_CONTROL_BOKEH_MODE_OFF) {
+            bool sizeSupported = false;
+            for (const auto& stream : outputStreams) {
+                if ((stream.format == static_cast<int32_t>(PixelFormat::YCBCR_420_888) ||
+                        stream.format == static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED))
+                        && stream.width == maxWidth && stream.height == maxHeight) {
+                    sizeSupported = true;
+                    break;
+                }
+            }
+            ASSERT_TRUE(sizeSupported);
+        }
+    }
+    ASSERT_TRUE(hasOffMode);
+    ASSERT_TRUE(hasStillCaptureMode || hasContinuousMode);
 }
 
 void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars,