Add abstract control class.

Partial implementation of tagged_partial_metadata. A control
is a value that can be changed.
Implements supported/get/set of parent class, abstracting
into simpler supported/get/set methods for children to implement.

BUG: 30140438
Change-Id: Iaba6fc2f54f6a8786c5ca379972ee1da9604c7a3
TEST: unit tests pass
diff --git a/modules/camera/3_4/Android.mk b/modules/camera/3_4/Android.mk
index 2f343ac..63e7c1a 100644
--- a/modules/camera/3_4/Android.mk
+++ b/modules/camera/3_4/Android.mk
@@ -49,6 +49,7 @@
   v4l2_wrapper.cpp \
 
 v4l2_test_files := \
+  metadata/control_test.cpp \
   metadata/fixed_property_test.cpp \
   metadata/metadata_test.cpp \
 
diff --git a/modules/camera/3_4/metadata/control.h b/modules/camera/3_4/metadata/control.h
new file mode 100644
index 0000000..db19b1d
--- /dev/null
+++ b/modules/camera/3_4/metadata/control.h
@@ -0,0 +1,127 @@
+/*
+ * 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_CONTROL_H_
+#define V4L2_CAMERA_HAL_METADATA_CONTROL_H_
+
+#include <vector>
+
+#include <system/camera_metadata.h>
+
+#include "../common.h"
+#include "tagged_partial_metadata.h"
+
+namespace v4l2_camera_hal {
+
+// A Control is a PartialMetadata with values that can be gotten/set.
+template <typename T>
+class Control : public TaggedPartialMetadata {
+ public:
+  Control(int32_t control_tag, std::vector<int32_t> static_tags = {});
+
+  // Child classes still need to implement PopulateStaticFields.
+  virtual int PopulateDynamicFields(
+      android::CameraMetadata* metadata) const override;
+  virtual bool SupportsRequestValues(
+      const android::CameraMetadata& metadata) const override;
+  virtual int SetRequestValues(
+      const android::CameraMetadata& metadata) override;
+
+ protected:
+  // Simpler access to tag.
+  inline int32_t ControlTag() const { return ControlTags()[0]; }
+
+  // Get/Set the control value. Return non-0 on failure.
+  virtual int GetValue(T* value) const = 0;
+  virtual int SetValue(const T& value) = 0;
+  // Helper to check if val is supported by this control.
+  virtual bool IsSupported(const T& val) const = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(Control);
+};
+
+// -----------------------------------------------------------------------------
+
+template <typename T>
+Control<T>::Control(int32_t control_tag, std::vector<int32_t> static_tags)
+    // Controls use the same tag for setting the control
+    // and getting the dynamic value.
+    : TaggedPartialMetadata(static_tags, {control_tag}, {control_tag}) {
+  HAL_LOG_ENTER();
+}
+
+template <typename T>
+int Control<T>::PopulateDynamicFields(android::CameraMetadata* metadata) const {
+  HAL_LOG_ENTER();
+
+  // Populate the current setting.
+  T value;
+  int res = GetValue(&value);
+  if (res) {
+    return res;
+  }
+  return UpdateMetadata(metadata, ControlTag(), value);
+}
+
+template <typename T>
+bool Control<T>::SupportsRequestValues(
+    const android::CameraMetadata& metadata) const {
+  HAL_LOG_ENTER();
+  if (metadata.isEmpty()) {
+    // Implicitly supported.
+    return true;
+  }
+
+  // Check that the requested setting is in the supported options.
+  T requested;
+  int res = SingleTagValue(metadata, ControlTag(), &requested);
+  if (res == -ENOENT) {
+    // Nothing requested of this control, that's fine.
+    return true;
+  } else if (res) {
+    HAL_LOGE("Failure while searching for request value for tag %d",
+             ControlTag());
+    return false;
+  }
+  return IsSupported(requested);
+}
+
+template <typename T>
+int Control<T>::SetRequestValues(const android::CameraMetadata& metadata) {
+  HAL_LOG_ENTER();
+  if (metadata.isEmpty()) {
+    // No changes necessary.
+    return 0;
+  }
+
+  // Get the requested value.
+  T requested;
+  int res = SingleTagValue(metadata, ControlTag(), &requested);
+  if (res == -ENOENT) {
+    // Nothing requested of this control, nothing to do.
+    return 0;
+  } else if (res) {
+    HAL_LOGE("Failure while searching for request value for tag %d",
+             ControlTag());
+    return res;
+  }
+
+  return SetValue(requested);
+}
+
+}  // namespace v4l2_camera_hal
+
+#endif  // V4L2_CAMERA_HAL_METADATA_CONTROL_H_
diff --git a/modules/camera/3_4/metadata/control_test.cpp b/modules/camera/3_4/metadata/control_test.cpp
new file mode 100644
index 0000000..6e45d02
--- /dev/null
+++ b/modules/camera/3_4/metadata/control_test.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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 "control.h"
+
+#include <array>
+
+#include <camera/CameraMetadata.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::AtMost;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace v4l2_camera_hal {
+
+class ControlTest : public Test {
+ protected:
+  // A subclass of Control with the pure virtual methods mocked out.
+  template <typename T>
+  class MockControl : public Control<T> {
+   public:
+    MockControl(int32_t control_tag) : Control<T>(control_tag){};
+    MOCK_CONST_METHOD1_T(PopulateStaticFields,
+                         int(android::CameraMetadata* metadata));
+    MOCK_CONST_METHOD1_T(GetValue, int(T* value));
+    MOCK_METHOD1_T(SetValue, int(const T& value));
+    MOCK_CONST_METHOD1_T(IsSupported, bool(const T& value));
+  };
+
+  virtual void SetUp() {
+    control_.reset(new MockControl<uint8_t>(control_tag_));
+  }
+  // Check that metadata of a given tag matches expectations.
+  virtual void ExpectMetadataEq(const android::CameraMetadata& metadata,
+                                int32_t tag, const uint8_t* expected,
+                                size_t size) {
+    camera_metadata_ro_entry_t entry = metadata.find(tag);
+    ASSERT_EQ(entry.count, size);
+    for (size_t i = 0; i < size; ++i) {
+      EXPECT_EQ(entry.data.u8[i], expected[i]);
+    }
+  }
+  virtual void ExpectMetadataEq(const android::CameraMetadata& metadata,
+                                int32_t tag, const int32_t* expected,
+                                size_t size) {
+    camera_metadata_ro_entry_t entry = metadata.find(tag);
+    ASSERT_EQ(entry.count, size);
+    for (size_t i = 0; i < size; ++i) {
+      EXPECT_EQ(entry.data.i32[i], expected[i]);
+    }
+  }
+  // Single item.
+  template <typename T>
+  void ExpectMetadataEq(const android::CameraMetadata& metadata, int32_t tag,
+                        T expected) {
+    ExpectMetadataEq(metadata, tag, &expected, 1);
+  }
+  // Vector of items.
+  template <typename T>
+  void ExpectMetadataEq(const android::CameraMetadata& metadata, int32_t tag,
+                        const std::vector<T>& expected) {
+    ExpectMetadataEq(metadata, tag, expected.data(), expected.size());
+  }
+
+  std::unique_ptr<MockControl<uint8_t>> control_;
+
+  // Need tags that match the data type (uint8_t) being passed.
+  static constexpr int32_t control_tag_ =
+      ANDROID_COLOR_CORRECTION_ABERRATION_MODE;
+};
+
+TEST_F(ControlTest, Tags) {
+  // Should have no static tags by default.
+  EXPECT_EQ(control_->StaticTags().size(), 0);
+  // Controls use the same tag for getting and setting.
+  // The macro doesn't like the static variables
+  // being passed directly to assertions.
+  int32_t expected_tag = control_tag_;
+  ASSERT_EQ(control_->ControlTags().size(), 1);
+  EXPECT_EQ(control_->ControlTags()[0], expected_tag);
+  ASSERT_EQ(control_->DynamicTags().size(), 1);
+  EXPECT_EQ(control_->DynamicTags()[0], expected_tag);
+}
+
+TEST_F(ControlTest, PopulateDynamic) {
+  uint8_t test_option = 99;
+  EXPECT_CALL(*control_, GetValue(_))
+      .WillOnce(DoAll(SetArgPointee<0>(test_option), Return(0)));
+
+  android::CameraMetadata metadata;
+  EXPECT_EQ(control_->PopulateDynamicFields(&metadata), 0);
+
+  // Should only have added 1 entry.
+  EXPECT_EQ(metadata.entryCount(), 1);
+  // Should have added the right entry.
+  ExpectMetadataEq(metadata, control_tag_, test_option);
+}
+
+TEST_F(ControlTest, PopulateDynamicFail) {
+  int err = -99;
+  EXPECT_CALL(*control_, GetValue(_)).WillOnce(Return(err));
+
+  android::CameraMetadata metadata;
+  EXPECT_EQ(control_->PopulateDynamicFields(&metadata), err);
+
+  // Should not have added an entry.
+  EXPECT_TRUE(metadata.isEmpty());
+}
+
+TEST_F(ControlTest, SupportsRequest) {
+  android::CameraMetadata metadata;
+  uint8_t test_option = 123;
+  ASSERT_EQ(metadata.update(control_tag_, &test_option, 1), android::OK);
+
+  EXPECT_CALL(*control_, IsSupported(test_option)).WillOnce(Return(true));
+  EXPECT_EQ(control_->SupportsRequestValues(metadata), true);
+}
+
+TEST_F(ControlTest, ArraySupportsRequest) {
+  android::CameraMetadata metadata;
+  std::array<uint8_t, 2> test_option = {{12, 34}};
+  ASSERT_EQ(
+      metadata.update(control_tag_, test_option.data(), test_option.size()),
+      android::OK);
+
+  MockControl<std::array<uint8_t, 2>> test_control(control_tag_);
+  EXPECT_CALL(test_control, IsSupported(test_option)).WillOnce(Return(true));
+  EXPECT_EQ(test_control.SupportsRequestValues(metadata), true);
+}
+
+TEST_F(ControlTest, SupportsRequestFail) {
+  android::CameraMetadata metadata;
+  uint8_t test_option = 123;
+  ASSERT_EQ(metadata.update(control_tag_, &test_option, 1), android::OK);
+
+  EXPECT_CALL(*control_, IsSupported(test_option)).WillOnce(Return(false));
+  EXPECT_EQ(control_->SupportsRequestValues(metadata), false);
+}
+
+TEST_F(ControlTest, SupportsRequestInvalidNumber) {
+  // Start with a request for multiple values.
+  android::CameraMetadata metadata;
+  std::vector<uint8_t> test_data = {1, 2, 3};
+  ASSERT_EQ(metadata.update(control_tag_, test_data.data(), test_data.size()),
+            android::OK);
+  EXPECT_EQ(control_->SupportsRequestValues(metadata), false);
+}
+
+TEST_F(ControlTest, ArraySupportsRequestInvalidNumber) {
+  // Start with a request for a single (non-array) value.
+  android::CameraMetadata metadata;
+  uint8_t test_data = 1;
+  ASSERT_EQ(metadata.update(control_tag_, &test_data, 1), android::OK);
+
+  MockControl<std::array<uint8_t, 2>> test_control(control_tag_);
+  EXPECT_EQ(test_control.SupportsRequestValues(metadata), false);
+}
+
+TEST_F(ControlTest, SupportsRequestEmpty) {
+  android::CameraMetadata metadata;
+  EXPECT_EQ(control_->SupportsRequestValues(metadata), true);
+}
+
+TEST_F(ControlTest, SetRequest) {
+  android::CameraMetadata metadata(1);
+  uint8_t test_option = 123;
+  ASSERT_EQ(metadata.update(control_tag_, &test_option, 1), android::OK);
+
+  EXPECT_CALL(*control_, SetValue(test_option)).WillOnce(Return(0));
+  // Make the request.
+  ASSERT_EQ(control_->SetRequestValues(metadata), 0);
+}
+
+TEST_F(ControlTest, ArraySetRequest) {
+  android::CameraMetadata metadata;
+  std::array<uint8_t, 2> test_option = {{12, 34}};
+  ASSERT_EQ(
+      metadata.update(control_tag_, test_option.data(), test_option.size()),
+      android::OK);
+
+  MockControl<std::array<uint8_t, 2>> test_control(control_tag_);
+  EXPECT_CALL(test_control, SetValue(test_option)).WillOnce(Return(0));
+  EXPECT_EQ(test_control.SetRequestValues(metadata), 0);
+}
+
+TEST_F(ControlTest, SetRequestFail) {
+  android::CameraMetadata metadata(1);
+  uint8_t test_option = 123;
+  ASSERT_EQ(metadata.update(control_tag_, &test_option, 1), android::OK);
+
+  int err = -99;
+  EXPECT_CALL(*control_, SetValue(test_option)).WillOnce(Return(err));
+  EXPECT_EQ(control_->SetRequestValues(metadata), err);
+}
+
+TEST_F(ControlTest, SetRequestInvalidNumber) {
+  // Start with a request for multiple values.
+  android::CameraMetadata metadata;
+  std::vector<uint8_t> test_data = {1, 2, 3};
+  ASSERT_EQ(metadata.update(control_tag_, test_data.data(), test_data.size()),
+            android::OK);
+  EXPECT_EQ(control_->SetRequestValues(metadata), -EINVAL);
+}
+
+TEST_F(ControlTest, ArraySetRequestInvalidNumber) {
+  // Start with a request for a single (non-array) value.
+  android::CameraMetadata metadata;
+  uint8_t test_data = 1;
+  ASSERT_EQ(metadata.update(control_tag_, &test_data, 1), android::OK);
+
+  MockControl<std::array<uint8_t, 2>> test_control(control_tag_);
+  EXPECT_EQ(test_control.SetRequestValues(metadata), -EINVAL);
+}
+
+TEST_F(ControlTest, SetRequestEmpty) {
+  // Should do nothing.
+  android::CameraMetadata metadata;
+  EXPECT_EQ(control_->SetRequestValues(metadata), 0);
+}
+
+}  // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/metadata/partial_metadata_interface.h b/modules/camera/3_4/metadata/partial_metadata_interface.h
index 21d198d..09bfebc 100644
--- a/modules/camera/3_4/metadata/partial_metadata_interface.h
+++ b/modules/camera/3_4/metadata/partial_metadata_interface.h
@@ -104,6 +104,111 @@
                             const ArrayVector<T, N>& val) {
     return UpdateMetadata(metadata, tag, val.data(), val.total_num_elements());
   }
+
+  // Specialization for vectors of arrays.
+  template <typename T, size_t N>
+  static int UpdateMetadata(android::CameraMetadata* metadata, int32_t tag,
+                            const std::vector<std::array<T, N>>& val) {
+    // Convert to array vector so we know all the elements are contiguous.
+    ArrayVector<T, N> array_vector;
+    for (const auto& array : val) {
+      array_vector.push_back(array);
+    }
+    return UpdateMetadata(metadata, tag, array_vector);
+  }
+
+  // Get the data pointer of a given metadata entry. Enforces that |val| must
+  // be a type supported by camera_metadata.
+
+  static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+                             const uint8_t** val) {
+    *val = entry.data.u8;
+  }
+
+  static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+                             const int32_t** val) {
+    *val = entry.data.i32;
+  }
+
+  static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+                             const float** val) {
+    *val = entry.data.f;
+  }
+
+  static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+                             const int64_t** val) {
+    *val = entry.data.i64;
+  }
+
+  static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+                             const double** val) {
+    *val = entry.data.d;
+  }
+
+  static void GetDataPointer(camera_metadata_ro_entry_t& entry,
+                             const camera_metadata_rational_t** val) {
+    *val = entry.data.r;
+  }
+
+  // Get a tag value that is expected to be a single item.
+  // Returns:
+  //   -ENOENT: The tag couldn't be found or was empty.
+  //   -EINVAL: The tag contained more than one item.
+  //   -ENODEV: The tag claims to be non-empty, but the data pointer is null.
+  //   0: Success. |*val| will contain the value for |tag|.
+
+  // Generic (one of the types supported by TagValue above).
+  template <typename T>
+  static int SingleTagValue(const android::CameraMetadata& metadata,
+                            int32_t tag, T* val) {
+    camera_metadata_ro_entry_t entry = metadata.find(tag);
+    if (entry.count == 0) {
+      HAL_LOGE("Metadata tag %d is empty.", tag);
+      return -ENOENT;
+    } else if (entry.count != 1) {
+      HAL_LOGE(
+          "Error: expected metadata tag %d to contain exactly 1 value "
+          "(had %d).",
+          tag, entry.count);
+      return -EINVAL;
+    }
+    const T* data = nullptr;
+    GetDataPointer(entry, &data);
+    if (data == nullptr) {
+      HAL_LOGE("Metadata tag %d is empty.", tag);
+      return -ENODEV;
+    }
+    *val = *data;
+    return 0;
+  }
+
+  // Specialization for std::array (of the types supported by TagValue above).
+  template <typename T, size_t N>
+  static int SingleTagValue(const android::CameraMetadata& metadata,
+                            int32_t tag, std::array<T, N>* val) {
+    camera_metadata_ro_entry_t entry = metadata.find(tag);
+    if (entry.count == 0) {
+      HAL_LOGE("Metadata tag %d is empty.", tag);
+      return -ENOENT;
+    } else if (entry.count != N) {
+      HAL_LOGE(
+          "Error: expected metadata tag %d to contain a single array of "
+          "exactly %d values (had %d).",
+          tag, N, entry.count);
+      return -EINVAL;
+    }
+    const T* data = nullptr;
+    GetDataPointer(entry, &data);
+    if (data == nullptr) {
+      HAL_LOGE("Metadata tag %d is empty.", tag);
+      return -ENODEV;
+    }
+    // Fill in the array.
+    for (size_t i = 0; i < N; ++i) {
+      (*val)[i] = data[i];
+    }
+    return 0;
+  }
 };
 
 }  // namespace v4l2_camera_hal