Add V4L2EnumControls to V4L2Metadata.

Add all current enum controls and their mappings
to the metadata constructor.

BUG: https://b/30140438

Change-Id: Ie4a5b89d8bc4bc75531425e5fc8bfb4a181b0a03
diff --git a/modules/camera/3_4/metadata/v4l2_enum_control.cpp b/modules/camera/3_4/metadata/v4l2_enum_control.cpp
index 21ca22b..58e1b6b 100644
--- a/modules/camera/3_4/metadata/v4l2_enum_control.cpp
+++ b/modules/camera/3_4/metadata/v4l2_enum_control.cpp
@@ -32,10 +32,11 @@
     HAL_LOGE("Failed to query control %d.", v4l2_control);
     return nullptr;
   }
-  if (control_query.type != V4L2_CTRL_TYPE_MENU) {
+  if (control_query.type != V4L2_CTRL_TYPE_MENU &&
+      control_query.type != V4L2_CTRL_TYPE_BOOLEAN) {
     HAL_LOGE(
-        "Enum controls can only be constructed from V4L2 menu controls (%d is "
-        "of type %d)",
+        "Enum controls can only be constructed from V4L2 menu and boolean "
+        "controls (%d is of type %d)",
         v4l2_control, control_query.type);
     return nullptr;
   }
diff --git a/modules/camera/3_4/metadata/v4l2_enum_control_test.cpp b/modules/camera/3_4/metadata/v4l2_enum_control_test.cpp
index 6df7321..54f78f3 100644
--- a/modules/camera/3_4/metadata/v4l2_enum_control_test.cpp
+++ b/modules/camera/3_4/metadata/v4l2_enum_control_test.cpp
@@ -77,7 +77,7 @@
   v4l2_query_ext_ctrl query_result;
   query_result.type = V4L2_CTRL_TYPE_MENU;
   query_result.minimum = 1;
-  query_result.maximum = 5;
+  query_result.maximum = 7;
   query_result.step = 2;
   EXPECT_CALL(*device_, QueryControl(v4l2_control_, _))
       .WillOnce(DoAll(SetArgPointee<1>(query_result), Return(0)));
@@ -104,7 +104,8 @@
   // Should populate the options according to capabilities returned.
   android::CameraMetadata metadata;
   ASSERT_EQ(test_control->PopulateStaticFields(&metadata), 0);
-  // Min 1, max 5, step 2 means {1,3,5} converted to metadata values.
+  // Min 1, max 7, step 2 means {1,3,5} converted to metadata values.
+  // There is no 7 in the map, so it shouldn't be present.
   std::vector<uint8_t> expected_options;
   expected_options.push_back(V4L2ToMetadata(1));
   expected_options.push_back(V4L2ToMetadata(3));
diff --git a/modules/camera/3_4/v4l2_metadata.cpp b/modules/camera/3_4/v4l2_metadata.cpp
index 1ebd9c0..9ec892f 100644
--- a/modules/camera/3_4/v4l2_metadata.cpp
+++ b/modules/camera/3_4/v4l2_metadata.cpp
@@ -21,15 +21,21 @@
 #include "common.h"
 #include "metadata/fixed_property.h"
 #include "metadata/ignored_control.h"
+#include "metadata/v4l2_enum_control.h"
 
 namespace v4l2_camera_hal {
 
-V4L2Metadata::V4L2Metadata(V4L2Wrapper* device) : device_(device) {
+V4L2Metadata::V4L2Metadata(std::shared_ptr<V4L2Wrapper> device)
+    : device_(std::move(device)) {
   HAL_LOG_ENTER();
 
+  // TODO: Temporarily connect to the device so that V4L2-specific components
+  // can make any necessary queries.
+
   // TODO(b/30140438): Add all metadata components used by V4L2Camera here.
-  // Currently these are all the fixed properties. Will add the other properties
-  // as more PartialMetadata subclasses get implemented.
+  // Currently these are all the fixed properties, ignored controls, and
+  // V4L2 enum controls. Will add the other properties as more PartialMetadata
+  // subclasses get implemented.
 
   AddComponent(
       std::unique_ptr<PartialMetadataInterface>(new IgnoredControl<uint8_t>(
@@ -40,9 +46,92 @@
           ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST)));
 
   // TODO(b/30510395): subcomponents of 3A.
+  // In general, default to ON/AUTO since they imply pretty much nothing,
+  // while OFF implies guarantees about not hindering performance.
   AddComponent(std::unique_ptr<PartialMetadataInterface>(
       new FixedProperty<std::array<int32_t, 3>>(
           ANDROID_CONTROL_MAX_REGIONS, {{/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0}})));
+  AddEnumControlOrDefault(V4L2_CID_EXPOSURE_AUTO, ANDROID_CONTROL_AE_MODE,
+                          ANDROID_CONTROL_AE_AVAILABLE_MODES,
+                          {{V4L2_EXPOSURE_AUTO, ANDROID_CONTROL_AE_MODE_ON},
+                           {V4L2_EXPOSURE_MANUAL, ANDROID_CONTROL_AE_MODE_OFF}},
+                          ANDROID_CONTROL_AE_MODE_ON);
+  AddEnumControlOrDefault(V4L2_CID_POWER_LINE_FREQUENCY,
+                          ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+                          ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+                          {{V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
+                            ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF},
+                           {V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
+                            ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ},
+                           {V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+                            ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ},
+                           {V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
+                            ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO}},
+                          ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO);
+  // V4L2 offers multiple white balance interfaces. Try the advanced one before
+  // falling
+  // back to the simpler version.
+  // Modes from each API that don't match up:
+  // Android: WARM_FLUORESCENT, TWILIGHT.
+  // V4L2: FLUORESCENT_H, HORIZON, FLASH.
+  std::unique_ptr<PartialMetadataInterface> awb(
+      V4L2EnumControl::NewV4L2EnumControl(
+          device_, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+          ANDROID_CONTROL_AWB_MODE, ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+          {{V4L2_WHITE_BALANCE_MANUAL, ANDROID_CONTROL_AWB_MODE_OFF},
+           {V4L2_WHITE_BALANCE_AUTO, ANDROID_CONTROL_AWB_MODE_AUTO},
+           {V4L2_WHITE_BALANCE_INCANDESCENT,
+            ANDROID_CONTROL_AWB_MODE_INCANDESCENT},
+           {V4L2_WHITE_BALANCE_FLUORESCENT,
+            ANDROID_CONTROL_AWB_MODE_FLUORESCENT},
+           {V4L2_WHITE_BALANCE_DAYLIGHT, ANDROID_CONTROL_AWB_MODE_DAYLIGHT},
+           {V4L2_WHITE_BALANCE_CLOUDY,
+            ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT},
+           {V4L2_WHITE_BALANCE_SHADE, ANDROID_CONTROL_AWB_MODE_SHADE}}));
+  if (awb) {
+    AddComponent(std::move(awb));
+  } else {
+    // Fall back to simpler AWB or even just an ignored control.
+    AddEnumControlOrDefault(
+        V4L2_CID_AUTO_WHITE_BALANCE, ANDROID_CONTROL_AWB_MODE,
+        ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+        {{0, ANDROID_CONTROL_AWB_MODE_OFF}, {1, ANDROID_CONTROL_AWB_MODE_AUTO}},
+        ANDROID_CONTROL_AWB_MODE_AUTO);
+  }
+  // TODO(b/30510395): subcomponents of scene modes
+  // (may itself be a subcomponent of 3A).
+  // Modes from each API that don't match up:
+  // Android: FACE_PRIORITY, ACTION, NIGHT_PORTRAIT, THEATRE, STEADYPHOTO,
+  // BARCODE, HIGH_SPEED_VIDEO, SNOW (combined with BEACH in V4L2. Only BEACH
+  // is reported to avoid ambiguity).
+  // V4L2: BACKLIGHT, DAWN_DUSK, FALL_COLORS, TEXT.
+  AddEnumControlOrDefault(
+      V4L2_CID_SCENE_MODE, ANDROID_CONTROL_SCENE_MODE,
+      ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
+      {{V4L2_SCENE_MODE_NONE, ANDROID_CONTROL_SCENE_MODE_DISABLED},
+       {V4L2_SCENE_MODE_BEACH_SNOW, ANDROID_CONTROL_SCENE_MODE_BEACH},
+       {V4L2_SCENE_MODE_CANDLE_LIGHT, ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT},
+       {V4L2_SCENE_MODE_FIREWORKS, ANDROID_CONTROL_SCENE_MODE_FIREWORKS},
+       {V4L2_SCENE_MODE_LANDSCAPE, ANDROID_CONTROL_SCENE_MODE_LANDSCAPE},
+       {V4L2_SCENE_MODE_NIGHT, ANDROID_CONTROL_SCENE_MODE_NIGHT},
+       {V4L2_SCENE_MODE_PARTY_INDOOR, ANDROID_CONTROL_SCENE_MODE_PARTY},
+       {V4L2_SCENE_MODE_SPORTS, ANDROID_CONTROL_SCENE_MODE_SPORTS},
+       {V4L2_SCENE_MODE_SUNSET, ANDROID_CONTROL_SCENE_MODE_SUNSET}},
+      ANDROID_CONTROL_SCENE_MODE_DISABLED);
+  // Modes from each API that don't match up:
+  // Android: POSTERIZE, WHITEBOARD, BLACKBOARD.
+  // V4L2: ANTIQUE, ART_FREEZE, EMBOSS, GRASS_GREEN, SKETCH, SKIN_WHITEN,
+  // SKY_BLUE, SILHOUETTE, VIVID, SET_CBCR.
+  AddEnumControlOrDefault(
+      V4L2_CID_COLORFX, ANDROID_CONTROL_EFFECT_MODE,
+      ANDROID_CONTROL_AVAILABLE_EFFECTS,
+      {{V4L2_COLORFX_NONE, ANDROID_CONTROL_EFFECT_MODE_OFF},
+       {V4L2_COLORFX_BW, ANDROID_CONTROL_EFFECT_MODE_MONO},
+       {V4L2_COLORFX_NEGATIVE, ANDROID_CONTROL_EFFECT_MODE_NEGATIVE},
+       {V4L2_COLORFX_SOLARIZATION, ANDROID_CONTROL_EFFECT_MODE_SOLARIZE},
+       {V4L2_COLORFX_SEPIA, ANDROID_CONTROL_EFFECT_MODE_SEPIA},
+       {V4L2_COLORFX_AQUA, ANDROID_CONTROL_EFFECT_MODE_AQUA}},
+      ANDROID_CONTROL_EFFECT_MODE_OFF);
 
   // Not sure if V4L2 does or doesn't do this, but HAL documentation says
   // all devices must support FAST, and FAST can be equivalent to OFF, so
@@ -105,6 +194,20 @@
           ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
           {ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF},
           ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF)));
+  // V4L2 doesn't differentiate between OPTICAL and VIDEO stabilization,
+  // so only report one (and report the other as OFF).
+  AddEnumControlOrDefault(V4L2_CID_IMAGE_STABILIZATION,
+                          ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+                          ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+                          {{0, ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF},
+                           {1, ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON}},
+                          ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF);
+  AddComponent(
+      std::unique_ptr<PartialMetadataInterface>(new IgnoredControl<uint8_t>(
+          ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+          ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
+          {ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF},
+          ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF)));
 
   // Unable to control noise reduction in V4L2 devices,
   // but FAST is allowed to be the same as OFF.
@@ -195,4 +298,21 @@
 
 V4L2Metadata::~V4L2Metadata() { HAL_LOG_ENTER(); }
 
+void V4L2Metadata::AddEnumControlOrDefault(
+    int v4l2_control, int32_t control_tag, int32_t options_tag,
+    const std::map<int32_t, uint8_t>& v4l2_to_metadata, uint8_t default_value) {
+  HAL_LOG_ENTER();
+
+  std::unique_ptr<PartialMetadataInterface> control(
+      V4L2EnumControl::NewV4L2EnumControl(device_, v4l2_control, control_tag,
+                                          options_tag, v4l2_to_metadata));
+
+  if (!control) {
+    control.reset(new IgnoredControl<uint8_t>(control_tag, options_tag,
+                                              {default_value}, default_value));
+  }
+
+  AddComponent(std::move(control));
+}
+
 }  // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/v4l2_metadata.h b/modules/camera/3_4/v4l2_metadata.h
index ff157c0..f99ceac 100644
--- a/modules/camera/3_4/v4l2_metadata.h
+++ b/modules/camera/3_4/v4l2_metadata.h
@@ -17,21 +17,32 @@
 #ifndef V4L2_CAMERA_HAL_V4L2_METADATA_H_
 #define V4L2_CAMERA_HAL_V4L2_METADATA_H_
 
+#include <map>
+#include <memory>
+
 #include <hardware/camera3.h>
 
 #include "common.h"
+#include "metadata/control.h"
 #include "metadata/metadata.h"
 #include "v4l2_wrapper.h"
 
 namespace v4l2_camera_hal {
 class V4L2Metadata : public Metadata {
  public:
-  V4L2Metadata(V4L2Wrapper* device);
+  V4L2Metadata(std::shared_ptr<V4L2Wrapper> device);
   virtual ~V4L2Metadata();
 
  private:
+  // Attempt to construct and add an enum control. If construction fails,
+  // use an IgnoredControl with only the default value instead.
+  void AddEnumControlOrDefault(
+      int v4l2_control, int32_t control_tag, int32_t options_tag,
+      const std::map<int32_t, uint8_t>& v4l2_to_metadata,
+      uint8_t default_value);
+
   // Access to the device.
-  V4L2Wrapper* device_;
+  std::shared_ptr<V4L2Wrapper> device_;
 
   DISALLOW_COPY_AND_ASSIGN(V4L2Metadata);
 };