Dynamic default metadata based on templates

Instead of controls picking their own defaults,
a delegate taking a mapping of template : desired default
is taken instead. These defaults are honored if able.

BUG: b/31017806
TEST: unit tests pass, multiple CTS tests fixed, test app runs.
Change-Id: I8212580c9aee1d7fe223fa6b3ff17a6cfb97552f
diff --git a/modules/camera/3_4/Android.mk b/modules/camera/3_4/Android.mk
index 1211a08..8e3c85a 100644
--- a/modules/camera/3_4/Android.mk
+++ b/modules/camera/3_4/Android.mk
@@ -57,6 +57,7 @@
 v4l2_test_files := \
   format_metadata_factory_test.cpp \
   metadata/control_test.cpp \
+  metadata/default_option_delegate_test.cpp \
   metadata/enum_converter_test.cpp \
   metadata/ignored_control_delegate_test.cpp \
   metadata/map_converter_test.cpp \
diff --git a/modules/camera/3_4/format_metadata_factory.cpp b/modules/camera/3_4/format_metadata_factory.cpp
index 673477b..9ec15ed 100644
--- a/modules/camera/3_4/format_metadata_factory.cpp
+++ b/modules/camera/3_4/format_metadata_factory.cpp
@@ -186,6 +186,15 @@
   fps_ranges.push_back({{min_fps, max_yuv_fps}});
   fps_ranges.push_back({{max_yuv_fps, max_yuv_fps}});
 
+  std::array<int32_t, 2> video_fps_range;
+  int32_t video_fps = 30;
+  if (video_fps >= max_yuv_fps) {
+    video_fps_range = {{max_yuv_fps, max_yuv_fps}};
+  } else {
+    video_fps_range = {{video_fps, video_fps}};
+    fps_ranges.push_back(video_fps_range);
+  }
+
   // Construct the metadata components.
   insertion_point = std::make_unique<Property<ArrayVector<int32_t, 4>>>(
       ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
@@ -201,7 +210,9 @@
   insertion_point = NoEffectMenuControl<std::array<int32_t, 2>>(
       ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
       ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
-      fps_ranges);
+      fps_ranges,
+      {{CAMERA3_TEMPLATE_VIDEO_RECORD, video_fps_range},
+       {OTHER_TEMPLATES, fps_ranges[0]}});
 
   return 0;
 }
diff --git a/modules/camera/3_4/format_metadata_factory_test.cpp b/modules/camera/3_4/format_metadata_factory_test.cpp
index a9603e8..d37b09f 100644
--- a/modules/camera/3_4/format_metadata_factory_test.cpp
+++ b/modules/camera/3_4/format_metadata_factory_test.cpp
@@ -64,7 +64,8 @@
 
   // Device must support IMPLEMENTATION_DEFINED (as well as JPEG & YUV).
   // Just duplicate the values from another format.
-  uint32_t imp_defined_format = StreamFormat::HalToV4L2PixelFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+  uint32_t imp_defined_format = StreamFormat::HalToV4L2PixelFormat(
+      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
   formats.insert(imp_defined_format);
   sizes[imp_defined_format] = sizes[V4L2_PIX_FMT_YUV420];
   durations[imp_defined_format] = durations[V4L2_PIX_FMT_YUV420];
@@ -119,7 +120,8 @@
 }
 
 TEST_F(FormatMetadataFactoryTest, GetFormatMetadataMissingJpeg) {
-  uint32_t imp_defined_format = StreamFormat::HalToV4L2PixelFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+  uint32_t imp_defined_format = StreamFormat::HalToV4L2PixelFormat(
+      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
   std::set<uint32_t> formats{V4L2_PIX_FMT_YUV420, imp_defined_format};
   EXPECT_CALL(*mock_device_, GetFormats(_))
       .WillOnce(DoAll(SetArgPointee<0>(formats), Return(0)));
@@ -127,11 +129,11 @@
   ASSERT_EQ(AddFormatComponents(mock_device_,
                                 std::inserter(components, components.end())),
             -ENODEV);
-
 }
 
 TEST_F(FormatMetadataFactoryTest, GetFormatMetadataMissingYuv) {
-  uint32_t imp_defined_format = StreamFormat::HalToV4L2PixelFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+  uint32_t imp_defined_format = StreamFormat::HalToV4L2PixelFormat(
+      HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
   std::set<uint32_t> formats{V4L2_PIX_FMT_JPEG, imp_defined_format};
   EXPECT_CALL(*mock_device_, GetFormats(_))
       .WillOnce(DoAll(SetArgPointee<0>(formats), Return(0)));
@@ -139,10 +141,10 @@
   ASSERT_EQ(AddFormatComponents(mock_device_,
                                 std::inserter(components, components.end())),
             -ENODEV);
-
 }
 
-TEST_F(FormatMetadataFactoryTest, GetFormatMetadataMissingImplementationDefined) {
+TEST_F(FormatMetadataFactoryTest,
+       GetFormatMetadataMissingImplementationDefined) {
   std::set<uint32_t> formats{V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420};
   EXPECT_CALL(*mock_device_, GetFormats(_))
       .WillOnce(DoAll(SetArgPointee<0>(formats), Return(0)));
@@ -150,7 +152,6 @@
   ASSERT_EQ(AddFormatComponents(mock_device_,
                                 std::inserter(components, components.end())),
             -ENODEV);
-
 }
 
 }  // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/control.h b/modules/camera/3_4/metadata/control.h
index ed86d39..ad3f87b 100644
--- a/modules/camera/3_4/metadata/control.h
+++ b/modules/camera/3_4/metadata/control.h
@@ -69,7 +69,7 @@
 template <typename T>
 std::vector<int32_t> Control<T>::StaticTags() const {
   std::vector<int32_t> result;
-  if (options_) {
+  if (options_ && options_->tag() != DO_NOT_REPORT_OPTIONS) {
     result.push_back(options_->tag());
   }
   return result;
@@ -88,7 +88,14 @@
 template <typename T>
 int Control<T>::PopulateStaticFields(android::CameraMetadata* metadata) const {
   if (!options_) {
-    HAL_LOGV("No options for control, nothing to populate.");
+    HAL_LOGV("No options for control %d, nothing to populate.",
+             delegate_->tag());
+    return 0;
+  } else if (options_->tag() == DO_NOT_REPORT_OPTIONS) {
+    HAL_LOGV(
+        "Options for control %d are not reported, "
+        "probably are set values defined and already known by the API.",
+        delegate_->tag());
     return 0;
   }
 
diff --git a/modules/camera/3_4/metadata/control_test.cpp b/modules/camera/3_4/metadata/control_test.cpp
index 572f25f..f76376c 100644
--- a/modules/camera/3_4/metadata/control_test.cpp
+++ b/modules/camera/3_4/metadata/control_test.cpp
@@ -44,7 +44,7 @@
     control_.reset();
   }
 
-  virtual void PrepareControl(bool with_options = true) {
+  virtual void PrepareControl() {
     // Use this method after all the EXPECT_CALLs to pass ownership of the mocks
     // to the device.
     std::unique_ptr<TaggedControlDelegate<uint8_t>> delegate =
@@ -52,8 +52,9 @@
             delegate_tag_, std::move(mock_delegate_));
     std::unique_ptr<TaggedControlOptions<uint8_t>> options =
         std::make_unique<TaggedControlOptions<uint8_t>>(
-            options_tag_, std::move(mock_options_));
-    if (with_options) {
+            report_options_ ? options_tag_ : DO_NOT_REPORT_OPTIONS,
+            std::move(mock_options_));
+    if (use_options_) {
       control_.reset(
           new Control<uint8_t>(std::move(delegate), std::move(options)));
     } else {
@@ -61,8 +62,8 @@
     }
   }
 
-  virtual void ExpectTags(bool with_options = true) {
-    if (with_options) {
+  virtual void ExpectTags() {
+    if (use_options_ && report_options_) {
       ASSERT_EQ(control_->StaticTags().size(), 1);
       EXPECT_EQ(control_->StaticTags()[0], options_tag_);
     } else {
@@ -79,8 +80,14 @@
     // Options should be available.
     android::CameraMetadata metadata;
     ASSERT_EQ(control_->PopulateStaticFields(&metadata), 0);
-    EXPECT_EQ(metadata.entryCount(), 1);
-    ExpectMetadataEq(metadata, options_tag_, options);
+    if (use_options_ && report_options_) {
+      EXPECT_EQ(metadata.entryCount(), 1);
+      ExpectMetadataEq(metadata, options_tag_, options);
+    } else {
+      EXPECT_EQ(metadata.entryCount(), 0);
+      // Shouldn't be expecting any options.
+      EXPECT_TRUE(options.empty());
+    }
   }
 
   virtual void ExpectValue(uint8_t value) {
@@ -93,6 +100,8 @@
   std::unique_ptr<Control<uint8_t>> control_;
   std::unique_ptr<ControlDelegateInterfaceMock<uint8_t>> mock_delegate_;
   std::unique_ptr<ControlOptionsInterfaceMock<uint8_t>> mock_options_;
+  bool use_options_ = true;
+  bool report_options_ = true;
 
   // Need tags that match the data type (uint8_t) being passed.
   const int32_t delegate_tag_ = ANDROID_COLOR_CORRECTION_ABERRATION_MODE;
@@ -106,8 +115,15 @@
 }
 
 TEST_F(ControlTest, TagsNoOptions) {
-  PrepareControl(false);
-  ExpectTags(false);
+  use_options_ = false;
+  PrepareControl();
+  ExpectTags();
+}
+
+TEST_F(ControlTest, TagsUnreportedOptions) {
+  report_options_ = false;
+  PrepareControl();
+  ExpectTags();
 }
 
 TEST_F(ControlTest, PopulateStatic) {
@@ -119,11 +135,15 @@
 }
 
 TEST_F(ControlTest, PopulateStaticNoOptions) {
-  PrepareControl(false);
-  android::CameraMetadata metadata;
-  ASSERT_EQ(control_->PopulateStaticFields(&metadata), 0);
-  // Should not have added any entry.
-  EXPECT_TRUE(metadata.isEmpty());
+  use_options_ = false;
+  PrepareControl();
+  ExpectOptions({});
+}
+
+TEST_F(ControlTest, PopulateStaticUnreportedOptions) {
+  report_options_ = false;
+  PrepareControl();
+  ExpectOptions({});
 }
 
 TEST_F(ControlTest, PopulateDynamic) {
@@ -136,10 +156,21 @@
 
 TEST_F(ControlTest, PopulateDynamicNoOptions) {
   // Lack of options shouldn't change anything for PopulateDynamic.
+  use_options_ = false;
   uint8_t test_option = 99;
   EXPECT_CALL(*mock_delegate_, GetValue(_))
       .WillOnce(DoAll(SetArgPointee<0>(test_option), Return(0)));
-  PrepareControl(false);
+  PrepareControl();
+  ExpectValue(test_option);
+}
+
+TEST_F(ControlTest, PopulateDynamicUnreportedOptions) {
+  // Lack of reported options shouldn't change anything for PopulateDynamic.
+  report_options_ = false;
+  uint8_t test_option = 99;
+  EXPECT_CALL(*mock_delegate_, GetValue(_))
+      .WillOnce(DoAll(SetArgPointee<0>(test_option), Return(0)));
+  PrepareControl();
   ExpectValue(test_option);
 }
 
@@ -179,12 +210,13 @@
 }
 
 TEST_F(ControlTest, PopulateTemplateOptionless) {
+  use_options_ = false;
   int template_type = 3;
   uint8_t value = 12;
   // Should use delegate instead of options if no options.
   EXPECT_CALL(*mock_delegate_, GetValue(_))
       .WillOnce(DoAll(SetArgPointee<0>(value), Return(0)));
-  PrepareControl(false);
+  PrepareControl();
 
   android::CameraMetadata metadata;
   EXPECT_EQ(control_->PopulateTemplateRequest(template_type, &metadata), 0);
@@ -192,11 +224,39 @@
 }
 
 TEST_F(ControlTest, PopulateTemplateOptionlessFail) {
+  use_options_ = false;
   int template_type = 3;
   int err = 10;
   // Should use delegate instead of options if no options.
   EXPECT_CALL(*mock_delegate_, GetValue(_)).WillOnce(Return(err));
-  PrepareControl(false);
+  PrepareControl();
+
+  android::CameraMetadata metadata;
+  EXPECT_EQ(control_->PopulateTemplateRequest(template_type, &metadata), err);
+}
+
+TEST_F(ControlTest, PopulateTemplateUnreportedOptions) {
+  report_options_ = false;
+  int template_type = 3;
+  uint8_t default_value = 123;
+  // Unreported options should behave just like reported ones for templating.
+  EXPECT_CALL(*mock_options_, DefaultValueForTemplate(template_type, _))
+      .WillOnce(DoAll(SetArgPointee<1>(default_value), Return(0)));
+  PrepareControl();
+
+  android::CameraMetadata metadata;
+  EXPECT_EQ(control_->PopulateTemplateRequest(template_type, &metadata), 0);
+  ExpectMetadataEq(metadata, delegate_tag_, default_value);
+}
+
+TEST_F(ControlTest, PopulateTemplateUnreportedOptionsFail) {
+  report_options_ = false;
+  int template_type = 3;
+  int err = 10;
+  // Unreported options should behave just like reported ones for templating.
+  EXPECT_CALL(*mock_options_, DefaultValueForTemplate(template_type, _))
+      .WillOnce(Return(err));
+  PrepareControl();
 
   android::CameraMetadata metadata;
   EXPECT_EQ(control_->PopulateTemplateRequest(template_type, &metadata), err);
@@ -214,10 +274,23 @@
 }
 
 TEST_F(ControlTest, SupportsRequestNoOptions) {
+  use_options_ = false;
   android::CameraMetadata metadata;
   uint8_t test_option = 123;
   ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
-  PrepareControl(false);
+  PrepareControl();
+
+  EXPECT_EQ(control_->SupportsRequestValues(metadata), true);
+}
+
+TEST_F(ControlTest, SupportsRequestUnreportedOptions) {
+  report_options_ = false;
+  android::CameraMetadata metadata;
+  uint8_t test_option = 123;
+  ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
+
+  EXPECT_CALL(*mock_options_, IsSupported(test_option)).WillOnce(Return(true));
+  PrepareControl();
 
   EXPECT_EQ(control_->SupportsRequestValues(metadata), true);
 }
@@ -233,6 +306,19 @@
   EXPECT_EQ(control_->SupportsRequestValues(metadata), false);
 }
 
+TEST_F(ControlTest, SupportsRequestUnreportedOptionsFail) {
+  report_options_ = false;
+  android::CameraMetadata metadata;
+  uint8_t test_option = 123;
+  ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
+
+  // Unreported options should still be checked against.
+  EXPECT_CALL(*mock_options_, IsSupported(test_option)).WillOnce(Return(false));
+  PrepareControl();
+
+  EXPECT_EQ(control_->SupportsRequestValues(metadata), false);
+}
+
 TEST_F(ControlTest, SupportsRequestInvalidNumber) {
   // Start with a request for multiple values.
   android::CameraMetadata metadata;
@@ -243,11 +329,12 @@
 }
 
 TEST_F(ControlTest, SupportsRequestInvalidNumberNoOptions) {
+  use_options_ = false;
   // Start with a request for multiple values.
   android::CameraMetadata metadata;
   std::vector<uint8_t> test_data = {1, 2, 3};
   ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_data), 0);
-  PrepareControl(false);
+  PrepareControl();
   // Not having any explicit options does not exempt a control
   // from requiring the right number of values.
   EXPECT_EQ(control_->SupportsRequestValues(metadata), false);
@@ -277,13 +364,33 @@
 }
 
 TEST_F(ControlTest, SetRequestNoOptions) {
+  use_options_ = false;
   android::CameraMetadata metadata;
   uint8_t test_option = 123;
   ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
 
   // No options, no validation check.
   EXPECT_CALL(*mock_delegate_, SetValue(test_option)).WillOnce(Return(0));
-  PrepareControl(false);
+  PrepareControl();
+
+  // Make the request.
+  ASSERT_EQ(control_->SetRequestValues(metadata), 0);
+}
+
+TEST_F(ControlTest, SetRequestUnreportedOptions) {
+  report_options_ = false;
+  android::CameraMetadata metadata;
+  uint8_t test_option = 123;
+  ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_option), 0);
+
+  // Unreported options still get a validation check.
+  Expectation validation_check =
+      EXPECT_CALL(*mock_options_, IsSupported(test_option))
+          .WillOnce(Return(true));
+  EXPECT_CALL(*mock_delegate_, SetValue(test_option))
+      .After(validation_check)
+      .WillOnce(Return(0));
+  PrepareControl();
 
   // Make the request.
   ASSERT_EQ(control_->SetRequestValues(metadata), 0);
@@ -328,12 +435,13 @@
 }
 
 TEST_F(ControlTest, SetRequestInvalidNumberNoOptions) {
+  use_options_ = false;
   // Start with a request for multiple values.
   android::CameraMetadata metadata;
   std::vector<uint8_t> test_data = {1, 2, 3};
   ASSERT_EQ(UpdateMetadata(&metadata, delegate_tag_, test_data), 0);
 
-  PrepareControl(false);
+  PrepareControl();
   // Not having explicit options does not change that an incorrect
   // number of values is invalid.
   EXPECT_EQ(control_->SetRequestValues(metadata), -EINVAL);
diff --git a/modules/camera/3_4/metadata/default_option_delegate.h b/modules/camera/3_4/metadata/default_option_delegate.h
new file mode 100644
index 0000000..f290318
--- /dev/null
+++ b/modules/camera/3_4/metadata/default_option_delegate.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef V4L2_CAMERA_HAL_METADATA_DEFAULT_OPTION_DELEGATE_H_
+#define V4L2_CAMERA_HAL_METADATA_DEFAULT_OPTION_DELEGATE_H_
+
+#include <errno.h>
+
+#include <map>
+
+#include <hardware/camera3.h>
+
+namespace v4l2_camera_hal {
+
+// A constant that can be used to identify an overall default.
+static constexpr int OTHER_TEMPLATES = CAMERA3_TEMPLATE_COUNT;
+
+// DefaultingOptionDelegate provides an interface to get default options from.
+template <typename T>
+class DefaultOptionDelegate {
+ public:
+  // |defaults| maps template types to default values
+  DefaultOptionDelegate(std::map<int, T> defaults)
+      : defaults_(std::move(defaults)){};
+  virtual ~DefaultOptionDelegate(){};
+
+  // Get a default value for a template type. Returns false if no default
+  // provided.
+  virtual bool DefaultValueForTemplate(int template_type, T* default_value) {
+    if (defaults_.count(template_type) > 0) {
+      // Best option is template-specific.
+      *default_value = defaults_[template_type];
+      return true;
+    } else if (defaults_.count(OTHER_TEMPLATES)) {
+      // Fall back to a general default.
+      *default_value = defaults_[OTHER_TEMPLATES];
+      return true;
+    }
+
+    return false;
+  };
+
+ private:
+  std::map<int, T> defaults_;
+};
+
+}  // namespace v4l2_camera_hal
+
+#endif  // V4L2_CAMERA_HAL_METADATA_DEFAULT_OPTION_DELEGATE_H_
diff --git a/modules/camera/3_4/metadata/default_option_delegate_mock.h b/modules/camera/3_4/metadata/default_option_delegate_mock.h
new file mode 100644
index 0000000..84ec740
--- /dev/null
+++ b/modules/camera/3_4/metadata/default_option_delegate_mock.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Mock for default option delegates.
+
+#ifndef V4L2_CAMERA_HAL_METADATA_DEFAULT_OPTION_DELEGATE_MOCK_H_
+#define V4L2_CAMERA_HAL_METADATA_DEFAULT_OPTION_DELEGATE_MOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "default_option_delegate.h"
+
+namespace v4l2_camera_hal {
+
+template <typename T>
+class DefaultOptionDelegateMock : public DefaultOptionDelegate<T> {
+ public:
+  DefaultOptionDelegateMock() : DefaultOptionDelegate<T>({}){};
+  MOCK_METHOD2_T(DefaultValueForTemplate, bool(int, T*));
+};
+
+}  // namespace v4l2_camera_hal
+
+#endif  // V4L2_CAMERA_HAL_METADATA_DEFAULT_OPTION_DELEGATE_MOCK_H_
diff --git a/modules/camera/3_4/metadata/default_option_delegate_test.cpp b/modules/camera/3_4/metadata/default_option_delegate_test.cpp
new file mode 100644
index 0000000..7b61dd4
--- /dev/null
+++ b/modules/camera/3_4/metadata/default_option_delegate_test.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "default_option_delegate.h"
+
+#include <memory>
+
+#include <gtest/gtest.h>
+#include <hardware/camera3.h>
+
+using testing::Test;
+
+namespace v4l2_camera_hal {
+
+class DefaultOptionDelegateTest : public Test {
+ protected:
+  virtual void SetUp() {
+    dut_.reset(new DefaultOptionDelegate<int>(defaults_));
+  }
+
+  std::unique_ptr<DefaultOptionDelegate<int>> dut_;
+  std::map<int, int> defaults_{{CAMERA3_TEMPLATE_STILL_CAPTURE, 10},
+                               {OTHER_TEMPLATES, 20},
+                               {CAMERA3_TEMPLATE_VIDEO_SNAPSHOT, 30}};
+};
+
+TEST_F(DefaultOptionDelegateTest, SpecificDefault) {
+  int actual = 0;
+  EXPECT_TRUE(
+      dut_->DefaultValueForTemplate(CAMERA3_TEMPLATE_STILL_CAPTURE, &actual));
+  EXPECT_EQ(actual, defaults_[CAMERA3_TEMPLATE_STILL_CAPTURE]);
+}
+
+TEST_F(DefaultOptionDelegateTest, GeneralDefault) {
+  int actual = 0;
+  // No ZSL default; should fall back to the OTHER_TEMPLATES default.
+  EXPECT_TRUE(dut_->DefaultValueForTemplate(CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG,
+                                            &actual));
+  EXPECT_EQ(actual, defaults_[OTHER_TEMPLATES]);
+}
+
+TEST_F(DefaultOptionDelegateTest, NoDefaults) {
+  dut_.reset(new DefaultOptionDelegate<int>({}));
+  int actual = 0;
+  EXPECT_FALSE(dut_->DefaultValueForTemplate(CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG,
+                                             &actual));
+}
+
+}  // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/menu_control_options.h b/modules/camera/3_4/metadata/menu_control_options.h
index 95ed3b6..c972dc6 100644
--- a/modules/camera/3_4/metadata/menu_control_options.h
+++ b/modules/camera/3_4/metadata/menu_control_options.h
@@ -21,6 +21,7 @@
 
 #include "../common.h"
 #include "control_options_interface.h"
+#include "default_option_delegate.h"
 
 namespace v4l2_camera_hal {
 
@@ -29,7 +30,12 @@
 class MenuControlOptions : public ControlOptionsInterface<T> {
  public:
   // |options| must be non-empty.
-  MenuControlOptions(std::vector<T> options) : options_(options) {}
+  MenuControlOptions(std::vector<T> options,
+                     std::shared_ptr<DefaultOptionDelegate<T>> defaults)
+      : options_(options), defaults_(defaults){};
+  MenuControlOptions(std::vector<T> options, std::map<int, T> defaults)
+      : options_(options),
+        defaults_(std::make_shared<DefaultOptionDelegate<T>>(defaults)){};
 
   virtual std::vector<T> MetadataRepresentation() override { return options_; };
   virtual bool IsSupported(const T& option) override {
@@ -38,18 +44,26 @@
   };
   virtual int DefaultValueForTemplate(int template_type,
                                       T* default_value) override {
-    // TODO(b/31017806): More complex logic, depend on template_type.
     // Default to the first option.
     if (options_.empty()) {
       HAL_LOGE("Can't get default value, options are empty.");
       return -ENODEV;
     }
+
+    // Try to get it from the defaults delegate.
+    if (defaults_->DefaultValueForTemplate(template_type, default_value) &&
+        IsSupported(*default_value)) {
+      return 0;
+    }
+
+    // Fall back to the first available.
     *default_value = options_[0];
     return 0;
-  }
+  };
 
  private:
   std::vector<T> options_;
+  std::shared_ptr<DefaultOptionDelegate<T>> defaults_;
 };
 
 }  // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/menu_control_options_test.cpp b/modules/camera/3_4/metadata/menu_control_options_test.cpp
index 24582f6..1a6ce6e 100644
--- a/modules/camera/3_4/metadata/menu_control_options_test.cpp
+++ b/modules/camera/3_4/metadata/menu_control_options_test.cpp
@@ -18,19 +18,29 @@
 
 #include <memory>
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <hardware/camera3.h>
 
+#include "default_option_delegate_mock.h"
+
+using testing::Return;
+using testing::SetArgPointee;
 using testing::Test;
+using testing::_;
 
 namespace v4l2_camera_hal {
 
 class MenuControlOptionsTest : public Test {
  protected:
-  virtual void SetUp() { dut_.reset(new MenuControlOptions<int>(options_)); }
+  virtual void SetUp() {
+    mock_defaults_.reset(new DefaultOptionDelegateMock<int>());
+    dut_.reset(new MenuControlOptions<int>(options_, mock_defaults_));
+  }
 
   std::unique_ptr<MenuControlOptions<int>> dut_;
   const std::vector<int> options_{1, 10, 19, 30};
+  std::shared_ptr<DefaultOptionDelegateMock<int>> mock_defaults_;
 };
 
 TEST_F(MenuControlOptionsTest, MetadataRepresentation) {
@@ -47,19 +57,49 @@
   EXPECT_FALSE(dut_->IsSupported(99));
 }
 
-TEST_F(MenuControlOptionsTest, DefaultValue) {
-  // All default values should be supported.
-  // For some reason, the templates have values in the range [1, COUNT).
-  for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; ++i) {
-    int value = -1;
-    EXPECT_EQ(dut_->DefaultValueForTemplate(i, &value), 0);
-    EXPECT_TRUE(dut_->IsSupported(value));
-  }
+TEST_F(MenuControlOptionsTest, DelegateDefaultValue) {
+  int template_index = 3;
+  int expected = options_[2];
+  ASSERT_TRUE(dut_->IsSupported(expected));
+  EXPECT_CALL(*mock_defaults_, DefaultValueForTemplate(template_index, _))
+      .WillOnce(DoAll(SetArgPointee<1>(expected), Return(true)));
+  int actual = expected - 1;
+  EXPECT_EQ(dut_->DefaultValueForTemplate(template_index, &actual), 0);
+  EXPECT_EQ(actual, expected);
+}
+
+TEST_F(MenuControlOptionsTest, InvalidDelegateDefaultValue) {
+  // -1 is not a supported option.
+  int template_index = 3;
+  int default_val = -1;
+  ASSERT_FALSE(dut_->IsSupported(default_val));
+
+  EXPECT_CALL(*mock_defaults_, DefaultValueForTemplate(template_index, _))
+      .WillOnce(DoAll(SetArgPointee<1>(default_val), Return(true)));
+
+  int actual = default_val;
+  EXPECT_EQ(dut_->DefaultValueForTemplate(template_index, &actual), 0);
+  // Should just give any supported option instead.
+  EXPECT_TRUE(dut_->IsSupported(actual));
+}
+
+TEST_F(MenuControlOptionsTest, NoDelegateDefaultValue) {
+  int template_index = 3;
+  int actual = -1;
+  ASSERT_FALSE(dut_->IsSupported(actual));
+
+  // Have delegate error.
+  EXPECT_CALL(*mock_defaults_, DefaultValueForTemplate(template_index, _))
+      .WillOnce(Return(false));
+
+  // Should still give *some* supported value.
+  EXPECT_EQ(dut_->DefaultValueForTemplate(template_index, &actual), 0);
+  EXPECT_TRUE(dut_->IsSupported(actual));
 }
 
 TEST_F(MenuControlOptionsTest, NoDefaultValue) {
   // Invalid options don't have a valid default.
-  MenuControlOptions<int> bad_options({});
+  MenuControlOptions<int> bad_options({}, mock_defaults_);
   for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; ++i) {
     int value = -1;
     EXPECT_EQ(bad_options.DefaultValueForTemplate(i, &value), -ENODEV);
diff --git a/modules/camera/3_4/metadata/partial_metadata_factory.h b/modules/camera/3_4/metadata/partial_metadata_factory.h
index 13f3d61..6b6dbd8 100644
--- a/modules/camera/3_4/metadata/partial_metadata_factory.h
+++ b/modules/camera/3_4/metadata/partial_metadata_factory.h
@@ -45,26 +45,31 @@
     int32_t delegate_tag, T default_value);
 
 // NoEffectMenuControl: Some menu options, but they have no effect.
-// The default value will be the first element of |options|.
 template <typename T>
 static std::unique_ptr<Control<T>> NoEffectMenuControl(
-    int32_t delegate_tag, int32_t options_tag, const std::vector<T>& options);
+    int32_t delegate_tag,
+    int32_t options_tag,
+    const std::vector<T>& options,
+    std::map<int, T> default_values = {});
 
 // NoEffectSliderControl: A slider of options, but they have no effect.
-// The default value will be |min|.
 template <typename T>
-static std::unique_ptr<Control<T>> NoEffectSliderControl(int32_t delegate_tag,
-                                                         int32_t options_tag,
-                                                         T min,
-                                                         T max);
+static std::unique_ptr<Control<T>> NoEffectSliderControl(
+    int32_t delegate_tag,
+    int32_t options_tag,
+    T min,
+    T max,
+    std::map<int, T> default_values = {});
 
 // NoEffectControl: A control with no effect and only a single allowable
 // value. Chooses an appropriate ControlOptionsInterface depending on type.
 template <typename T>
-static std::unique_ptr<Control<T>> NoEffectControl(ControlType type,
-                                                   int32_t delegate_tag,
-                                                   int32_t options_tag,
-                                                   T value);
+static std::unique_ptr<Control<T>> NoEffectControl(
+    ControlType type,
+    int32_t delegate_tag,
+    int32_t options_tag,
+    T value,
+    std::map<int, T> default_values = {});
 
 // V4L2Control: A control corresponding to a V4L2 control.
 template <typename T>
@@ -74,10 +79,12 @@
     int32_t options_tag,
     std::shared_ptr<V4L2Wrapper> device,
     int control_id,
-    std::shared_ptr<ConverterInterface<T, int32_t>> converter);
+    std::shared_ptr<ConverterInterface<T, int32_t>> converter,
+    std::map<int, T> default_values = {});
 
 // V4L2ControlOrDefault: Like V4L2Control, but if the V4L2Control fails to
-// initialize for some reason, this method will fall back to NoEffectControl.
+// initialize for some reason, this method will fall back to NoEffectControl
+// with an initial value defined by |fallback_default|.
 template <typename T>
 static std::unique_ptr<Control<T>> V4L2ControlOrDefault(
     ControlType type,
@@ -86,7 +93,8 @@
     std::shared_ptr<V4L2Wrapper> device,
     int control_id,
     std::shared_ptr<ConverterInterface<T, int32_t>> converter,
-    const T& default_value);
+    T fallback_default,
+    std::map<int, T> default_values = {});
 
 // -----------------------------------------------------------------------------
 
@@ -114,9 +122,11 @@
 }
 
 template <typename T>
-std::unique_ptr<Control<T>> NoEffectMenuControl(int32_t delegate_tag,
-                                                int32_t options_tag,
-                                                const std::vector<T>& options) {
+std::unique_ptr<Control<T>> NoEffectMenuControl(
+    int32_t delegate_tag,
+    int32_t options_tag,
+    const std::vector<T>& options,
+    std::map<int, T> default_values) {
   HAL_LOG_ENTER();
 
   if (options.empty()) {
@@ -129,35 +139,42 @@
           delegate_tag,
           std::make_unique<NoEffectControlDelegate<T>>(options[0])),
       std::make_unique<TaggedControlOptions<T>>(
-          options_tag, std::make_unique<MenuControlOptions<T>>(options)));
+          options_tag,
+          std::make_unique<MenuControlOptions<T>>(options, default_values)));
 }
 
 template <typename T>
-std::unique_ptr<Control<T>> NoEffectSliderControl(int32_t delegate_tag,
-                                                  int32_t options_tag,
-                                                  T min,
-                                                  T max) {
+std::unique_ptr<Control<T>> NoEffectSliderControl(
+    int32_t delegate_tag,
+    int32_t options_tag,
+    T min,
+    T max,
+    std::map<int, T> default_values) {
   HAL_LOG_ENTER();
 
   return std::make_unique<Control<T>>(
       std::make_unique<TaggedControlDelegate<T>>(
           delegate_tag, std::make_unique<NoEffectControlDelegate<T>>(min)),
       std::make_unique<TaggedControlOptions<T>>(
-          options_tag, std::make_unique<SliderControlOptions<T>>(min, max)));
+          options_tag,
+          std::make_unique<SliderControlOptions<T>>(min, max, default_values)));
 }
 
 template <typename T>
 std::unique_ptr<Control<T>> NoEffectControl(ControlType type,
                                             int32_t delegate_tag,
                                             int32_t options_tag,
-                                            T value) {
+                                            T value,
+                                            std::map<int, T> default_values) {
   HAL_LOG_ENTER();
 
   switch (type) {
     case ControlType::kMenu:
-      return NoEffectMenuControl<T>(delegate_tag, options_tag, {value});
+      return NoEffectMenuControl<T>(
+          delegate_tag, options_tag, {value}, default_values);
     case ControlType::kSlider:
-      return NoEffectSliderControl(delegate_tag, options_tag, value, value);
+      return NoEffectSliderControl(
+          delegate_tag, options_tag, value, value, default_values);
   }
 }
 
@@ -168,7 +185,8 @@
     int32_t options_tag,
     std::shared_ptr<V4L2Wrapper> device,
     int control_id,
-    std::shared_ptr<ConverterInterface<T, int32_t>> converter) {
+    std::shared_ptr<ConverterInterface<T, int32_t>> converter,
+    std::map<int, T> default_values) {
   HAL_LOG_ENTER();
 
   // Query the device.
@@ -230,7 +248,8 @@
         HAL_LOGE("No valid options for control %d.", control_id);
         return nullptr;
       }
-      result_options.reset(new MenuControlOptions<T>(options));
+
+      result_options.reset(new MenuControlOptions<T>(options, default_values));
       // No converter changes necessary.
       break;
     case V4L2_CTRL_TYPE_INTEGER:
@@ -265,8 +284,8 @@
             control_id);
         return nullptr;
       }
-      result_options.reset(
-          new SliderControlOptions<T>(metadata_min, metadata_max));
+      result_options.reset(new SliderControlOptions<T>(
+          metadata_min, metadata_max, default_values));
       break;
     default:
       HAL_LOGE("Control %d (%s) is of unsupported type %d",
@@ -294,13 +313,20 @@
     std::shared_ptr<V4L2Wrapper> device,
     int control_id,
     std::shared_ptr<ConverterInterface<T, int32_t>> converter,
-    const T& default_value) {
+    T fallback_default,
+    std::map<int, T> default_values) {
   HAL_LOG_ENTER();
 
-  std::unique_ptr<Control<T>> result = V4L2Control(
-      type, delegate_tag, options_tag, device, control_id, converter);
+  std::unique_ptr<Control<T>> result = V4L2Control(type,
+                                                   delegate_tag,
+                                                   options_tag,
+                                                   device,
+                                                   control_id,
+                                                   converter,
+                                                   default_values);
   if (!result) {
-    result = NoEffectControl(type, delegate_tag, options_tag, default_value);
+    result = NoEffectControl(
+        type, delegate_tag, options_tag, fallback_default, default_values);
   }
   return result;
 }
diff --git a/modules/camera/3_4/metadata/slider_control_options.h b/modules/camera/3_4/metadata/slider_control_options.h
index 2815dad..88c1651 100644
--- a/modules/camera/3_4/metadata/slider_control_options.h
+++ b/modules/camera/3_4/metadata/slider_control_options.h
@@ -23,6 +23,7 @@
 
 #include "../common.h"
 #include "control_options_interface.h"
+#include "default_option_delegate.h"
 
 namespace v4l2_camera_hal {
 
@@ -31,7 +32,14 @@
 class SliderControlOptions : public ControlOptionsInterface<T> {
  public:
   // |min| must be <= |max|.
-  SliderControlOptions(T min, T max) : min_(min), max_(max) {}
+  SliderControlOptions(const T& min,
+                       const T& max,
+                       std::shared_ptr<DefaultOptionDelegate<T>> defaults)
+      : min_(min), max_(max), defaults_(defaults){};
+  SliderControlOptions(const T& min, const T& max, std::map<int, T> defaults)
+      : min_(min),
+        max_(max),
+        defaults_(std::make_shared<DefaultOptionDelegate<T>>(defaults)){};
 
   virtual std::vector<T> MetadataRepresentation() override {
     return {min_, max_};
@@ -41,19 +49,30 @@
   };
   virtual int DefaultValueForTemplate(int template_type,
                                       T* default_value) override {
-    // TODO(b/31017806): More complex logic, depend on template_type.
     if (min_ > max_) {
       HAL_LOGE("No valid default slider option, min is greater than max.");
       return -ENODEV;
     }
-    // Default to the min value.
+
+    if (defaults_->DefaultValueForTemplate(template_type, default_value)) {
+      // Get as close as we can to the desired value.
+      if (*default_value < min_) {
+        *default_value = min_;
+      } else if (*default_value > max_) {
+        *default_value = max_;
+      }
+      return 0;
+    }
+
+    // No default given, just fall back to the min of the range.
     *default_value = min_;
     return 0;
-  }
+  };
 
  private:
   T min_;
   T max_;
+  std::shared_ptr<DefaultOptionDelegate<T>> defaults_;
 };
 
 }  // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/slider_control_options_test.cpp b/modules/camera/3_4/metadata/slider_control_options_test.cpp
index a241ad6..b7cef5a 100644
--- a/modules/camera/3_4/metadata/slider_control_options_test.cpp
+++ b/modules/camera/3_4/metadata/slider_control_options_test.cpp
@@ -18,20 +18,28 @@
 
 #include <memory>
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <hardware/camera3.h>
 
+#include "default_option_delegate_mock.h"
+
+using testing::Return;
+using testing::SetArgPointee;
 using testing::Test;
+using testing::_;
 
 namespace v4l2_camera_hal {
 
 class SliderControlOptionsTest : public Test {
  protected:
   virtual void SetUp() {
-    dut_.reset(new SliderControlOptions<int>(min_, max_));
+    mock_defaults_.reset(new DefaultOptionDelegateMock<int>());
+    dut_.reset(new SliderControlOptions<int>(min_, max_, mock_defaults_));
   }
 
   std::unique_ptr<SliderControlOptions<int>> dut_;
+  std::shared_ptr<DefaultOptionDelegateMock<int>> mock_defaults_;
   const int min_ = 1;
   const int max_ = 10;
 };
@@ -52,19 +60,66 @@
   EXPECT_FALSE(dut_->IsSupported(max_ + 1));
 }
 
-TEST_F(SliderControlOptionsTest, DefaultValue) {
-  // All default values should be supported.
-  // For some reason, the templates have values in the range [1, COUNT).
-  for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; ++i) {
-    int value = -1;
-    EXPECT_EQ(dut_->DefaultValueForTemplate(i, &value), 0);
-    EXPECT_TRUE(dut_->IsSupported(value));
-  }
+TEST_F(SliderControlOptionsTest, DelegateDefaultValue) {
+  int template_index = 3;
+  int expected = max_ - 1;
+  ASSERT_TRUE(dut_->IsSupported(expected));
+  EXPECT_CALL(*mock_defaults_, DefaultValueForTemplate(template_index, _))
+      .WillOnce(DoAll(SetArgPointee<1>(expected), Return(true)));
+  int actual = expected - 1;
+  EXPECT_EQ(dut_->DefaultValueForTemplate(template_index, &actual), 0);
+  EXPECT_EQ(actual, expected);
+}
+
+TEST_F(SliderControlOptionsTest, LowDelegateDefaultValue) {
+  int template_index = 3;
+  // min - 1 is below the valid range.
+  int default_val = min_ - 1;
+  // Should get bumped up into range.
+  int expected = min_;
+  ASSERT_FALSE(dut_->IsSupported(default_val));
+  ASSERT_TRUE(dut_->IsSupported(expected));
+
+  EXPECT_CALL(*mock_defaults_, DefaultValueForTemplate(template_index, _))
+      .WillOnce(DoAll(SetArgPointee<1>(default_val), Return(true)));
+  int actual = default_val;
+  EXPECT_EQ(dut_->DefaultValueForTemplate(template_index, &actual), 0);
+  EXPECT_EQ(actual, expected);
+}
+
+TEST_F(SliderControlOptionsTest, HighDelegateDefaultValue) {
+  int template_index = 3;
+  // max + 1 is above the valid range.
+  int default_val = max_ + 1;
+  // Should get bumped down into range.
+  int expected = max_;
+  ASSERT_FALSE(dut_->IsSupported(default_val));
+  ASSERT_TRUE(dut_->IsSupported(expected));
+
+  EXPECT_CALL(*mock_defaults_, DefaultValueForTemplate(template_index, _))
+      .WillOnce(DoAll(SetArgPointee<1>(default_val), Return(true)));
+  int actual = default_val;
+  EXPECT_EQ(dut_->DefaultValueForTemplate(template_index, &actual), 0);
+  EXPECT_EQ(actual, expected);
+}
+
+TEST_F(SliderControlOptionsTest, NoDelegateDefaultValue) {
+  int template_index = 3;
+  int actual = min_ - 1;
+  ASSERT_FALSE(dut_->IsSupported(actual));
+
+  // Have delegate error.
+  EXPECT_CALL(*mock_defaults_, DefaultValueForTemplate(template_index, _))
+      .WillOnce(Return(false));
+
+  // Should still give *some* supported value.
+  EXPECT_EQ(dut_->DefaultValueForTemplate(template_index, &actual), 0);
+  EXPECT_TRUE(dut_->IsSupported(actual));
 }
 
 TEST_F(SliderControlOptionsTest, NoDefaultValue) {
   // Invalid options don't have a valid default.
-  SliderControlOptions<int> bad_options(10, 9);  // min > max.
+  SliderControlOptions<int> bad_options(10, 9, mock_defaults_);  // min > max.
   for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; ++i) {
     int value = -1;
     EXPECT_EQ(bad_options.DefaultValueForTemplate(i, &value), -ENODEV);
diff --git a/modules/camera/3_4/metadata/tagged_control_options.h b/modules/camera/3_4/metadata/tagged_control_options.h
index 9204fea..3d900ae 100644
--- a/modules/camera/3_4/metadata/tagged_control_options.h
+++ b/modules/camera/3_4/metadata/tagged_control_options.h
@@ -23,6 +23,13 @@
 
 namespace v4l2_camera_hal {
 
+// A constant tag with a value not used as a real tag
+// (since all real tags are unsigned),  to indicate options
+// that should not be reported.
+// Any class working with TaggedControlOptions should check
+// the tag against this value before using it.
+static int32_t DO_NOT_REPORT_OPTIONS = -1;
+
 // A TaggedControlOptions wraps a ControlOptions and adds a tag.
 template <typename T>
 class TaggedControlOptions : public ControlOptionsInterface<T> {
diff --git a/modules/camera/3_4/v4l2_metadata_factory.cpp b/modules/camera/3_4/v4l2_metadata_factory.cpp
index b9c64be..dc43377 100644
--- a/modules/camera/3_4/v4l2_metadata_factory.cpp
+++ b/modules/camera/3_4/v4l2_metadata_factory.cpp
@@ -58,7 +58,10 @@
       ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
       ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
       {ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST,
-       ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY}));
+       ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY},
+      {{CAMERA3_TEMPLATE_STILL_CAPTURE,
+        ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY},
+       {OTHER_TEMPLATES, ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST}}));
 
   // TODO(b/30510395): subcomponents of 3A.
   // In general, default to ON/AUTO since they imply pretty much nothing,
@@ -76,11 +79,12 @@
       V4L2_CID_AUTO_EXPOSURE_BIAS,
       // No scaling necessary, AE_COMPENSATION_STEP handles this.
       std::make_shared<ScalingConverter<int32_t, int32_t>>(1, 1),
-      0));
+      0,
+      {{OTHER_TEMPLATES, 0}}));
   components.insert(std::unique_ptr<PartialMetadataInterface>(
       new Property<camera_metadata_rational_t>(
           ANDROID_CONTROL_AE_COMPENSATION_STEP, kAeCompensationUnit)));
-  // TODO(b/31021522): Autofocus subcomponent, AFTrigger.
+  // TODO(b/31021522): Autofocus subcomponent.
   components.insert(
       NoEffectMenuControl<uint8_t>(ANDROID_CONTROL_AF_MODE,
                                    ANDROID_CONTROL_AF_AVAILABLE_MODES,
@@ -91,7 +95,23 @@
   // the docs (system/media/camera/docs/docs.html).
   components.insert(FixedState<uint8_t>(ANDROID_CONTROL_AF_STATE,
                                         ANDROID_CONTROL_AF_STATE_INACTIVE));
-  // TODO(b/31022735): AE & AF triggers.
+  // TODO(b/31022735): Correctly implement AE & AF triggers that
+  // actually do something. These no effect triggers are even worse than most
+  // of the useless controls in this class, since technically they should
+  // revert back to IDLE eventually after START/CANCEL, but for now they won't
+  // unless IDLE is requested.
+  components.insert(
+      NoEffectMenuControl<uint8_t>(ANDROID_CONTROL_AF_TRIGGER,
+                                   DO_NOT_REPORT_OPTIONS,
+                                   {ANDROID_CONTROL_AF_TRIGGER_IDLE,
+                                    ANDROID_CONTROL_AF_TRIGGER_START,
+                                    ANDROID_CONTROL_AF_TRIGGER_CANCEL}));
+  components.insert(NoEffectMenuControl<uint8_t>(
+      ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+      DO_NOT_REPORT_OPTIONS,
+      {ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE,
+       ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START,
+       ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL}));
   components.insert(V4L2ControlOrDefault<uint8_t>(
       ControlType::kMenu,
       ANDROID_CONTROL_AE_MODE,
@@ -101,7 +121,9 @@
       std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(new EnumConverter(
           {{V4L2_EXPOSURE_AUTO, ANDROID_CONTROL_AE_MODE_ON},
            {V4L2_EXPOSURE_MANUAL, ANDROID_CONTROL_AE_MODE_OFF}})),
-      ANDROID_CONTROL_AE_MODE_ON));
+      ANDROID_CONTROL_AE_MODE_ON,
+      {{CAMERA3_TEMPLATE_MANUAL, ANDROID_CONTROL_AE_MODE_OFF},
+       {OTHER_TEMPLATES, ANDROID_CONTROL_AE_MODE_ON}}));
   components.insert(V4L2ControlOrDefault<uint8_t>(
       ControlType::kMenu,
       ANDROID_CONTROL_AE_ANTIBANDING_MODE,
@@ -117,7 +139,9 @@
                               ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ},
                              {V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
                               ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO}})),
-      ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO));
+      ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,
+      {{CAMERA3_TEMPLATE_MANUAL, ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF},
+       {OTHER_TEMPLATES, ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO}}));
   std::unique_ptr<PartialMetadataInterface> exposure_time =
       V4L2Control<int64_t>(ControlType::kSlider,
                            ANDROID_SENSOR_EXPOSURE_TIME,
@@ -171,7 +195,9 @@
            {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}}))));
+           {V4L2_WHITE_BALANCE_SHADE, ANDROID_CONTROL_AWB_MODE_SHADE}})),
+      {{CAMERA3_TEMPLATE_MANUAL, ANDROID_CONTROL_AWB_MODE_OFF},
+       {OTHER_TEMPLATES, ANDROID_CONTROL_AWB_MODE_AUTO}}));
   if (awb) {
     components.insert(std::move(awb));
   } else {
@@ -185,7 +211,9 @@
         std::shared_ptr<ConverterInterface<uint8_t, int32_t>>(
             new EnumConverter({{0, ANDROID_CONTROL_AWB_MODE_OFF},
                                {1, ANDROID_CONTROL_AWB_MODE_AUTO}})),
-        ANDROID_CONTROL_AWB_MODE_AUTO));
+        ANDROID_CONTROL_AWB_MODE_AUTO,
+        {{CAMERA3_TEMPLATE_MANUAL, ANDROID_CONTROL_AWB_MODE_OFF},
+         {OTHER_TEMPLATES, ANDROID_CONTROL_AWB_MODE_AUTO}}));
   }
   // TODO(b/31041577): Handle AWB state machine correctly.
   components.insert(FixedState<uint8_t>(ANDROID_CONTROL_AWB_STATE,
@@ -249,19 +277,23 @@
 
   // 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
-  // either way it's fine to list.
-  components.insert(
-      NoEffectMenuControl<uint8_t>(ANDROID_EDGE_MODE,
-                                   ANDROID_EDGE_AVAILABLE_EDGE_MODES,
-                                   {ANDROID_EDGE_MODE_FAST}));
+  // either way it's fine to list. And if FAST is included, HIGH_QUALITY
+  // is supposed to be included as well.
+  components.insert(NoEffectMenuControl<uint8_t>(
+      ANDROID_EDGE_MODE,
+      ANDROID_EDGE_AVAILABLE_EDGE_MODES,
+      {ANDROID_EDGE_MODE_FAST, ANDROID_EDGE_MODE_HIGH_QUALITY},
+      {{CAMERA3_TEMPLATE_STILL_CAPTURE, ANDROID_EDGE_MODE_HIGH_QUALITY},
+       {OTHER_TEMPLATES, ANDROID_EDGE_MODE_FAST}}));
 
   // TODO(b/31023454): subcomponents of flash.
-  // Missing android.flash.mode control, since it uses a different enum.
   components.insert(
       std::unique_ptr<PartialMetadataInterface>(new Property<uint8_t>(
           ANDROID_FLASH_INFO_AVAILABLE, ANDROID_FLASH_INFO_AVAILABLE_FALSE)));
   components.insert(FixedState<uint8_t>(ANDROID_FLASH_STATE,
                                         ANDROID_FLASH_STATE_UNAVAILABLE));
+  components.insert(NoEffectMenuControl<uint8_t>(
+      ANDROID_FLASH_MODE, DO_NOT_REPORT_OPTIONS, {ANDROID_FLASH_MODE_OFF}));
 
   // TODO(30510395): subcomponents of hotpixel.
   // No known V4L2 hot pixel correction. But it might be happening,
@@ -344,16 +376,39 @@
       {ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF}));
   // TODO(b/31017806): This should definitely have a different default depending
   // on template.
-  components.insert(NoEffectOptionlessControl<uint8_t>(
+  components.insert(NoEffectMenuControl<uint8_t>(
       ANDROID_CONTROL_CAPTURE_INTENT,
-      ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE));
+      DO_NOT_REPORT_OPTIONS,
+      {ANDROID_CONTROL_CAPTURE_INTENT_CUSTOM,
+       ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW,
+       ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE,
+       ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD,
+       ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT,
+       ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG,
+       ANDROID_CONTROL_CAPTURE_INTENT_MANUAL},
+      {{CAMERA3_TEMPLATE_PREVIEW, ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW},
+       {CAMERA3_TEMPLATE_STILL_CAPTURE,
+        ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE},
+       {CAMERA3_TEMPLATE_VIDEO_RECORD,
+        ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD},
+       {CAMERA3_TEMPLATE_VIDEO_SNAPSHOT,
+        ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT},
+       {CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG,
+        ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG},
+       {CAMERA3_TEMPLATE_MANUAL, ANDROID_CONTROL_CAPTURE_INTENT_MANUAL},
+       {OTHER_TEMPLATES, ANDROID_CONTROL_CAPTURE_INTENT_CUSTOM}}));
 
   // Unable to control noise reduction in V4L2 devices,
-  // but FAST is allowed to be the same as OFF.
+  // but FAST is allowed to be the same as OFF,
+  // and HIGH_QUALITY can be the same as FAST.
   components.insert(NoEffectMenuControl<uint8_t>(
       ANDROID_NOISE_REDUCTION_MODE,
       ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
-      {ANDROID_NOISE_REDUCTION_MODE_FAST}));
+      {ANDROID_NOISE_REDUCTION_MODE_FAST,
+       ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY},
+      {{CAMERA3_TEMPLATE_STILL_CAPTURE,
+        ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY},
+       {OTHER_TEMPLATES, ANDROID_NOISE_REDUCTION_MODE_FAST}}));
 
   // TODO(30510395): subcomponents of formats/streams.
   // For now, no thumbnails available (only [0,0], the "no thumbnail" size).