Add StaticProperties and MetadataReader

MetadataReader provides a clean wrapper around getting
and translating certain metadata values in a nice form.

StaticProperties will be used by Camera as the source of
truth for metadata properties, extracted directly from a reader,
rather than calling down into the device again.

BUG: 31044638
TEST: unit tests pass
Change-Id: I712a80f87e629a7288c678637de0eae0225acf96
diff --git a/modules/camera/3_4/Android.mk b/modules/camera/3_4/Android.mk
index bf888be..12e8436 100644
--- a/modules/camera/3_4/Android.mk
+++ b/modules/camera/3_4/Android.mk
@@ -42,6 +42,8 @@
   format_metadata_factory.cpp \
   metadata/enum_converter.cpp \
   metadata/metadata.cpp \
+  metadata/metadata_reader.cpp \
+  static_properties.cpp \
   stream.cpp \
   stream_format.cpp \
   v4l2_camera.cpp \
@@ -57,6 +59,7 @@
   metadata/ignored_control_delegate_test.cpp \
   metadata/map_converter_test.cpp \
   metadata/menu_control_options_test.cpp \
+  metadata/metadata_reader_test.cpp \
   metadata/metadata_test.cpp \
   metadata/no_effect_control_delegate_test.cpp \
   metadata/partial_metadata_factory_test.cpp \
@@ -67,6 +70,7 @@
   metadata/tagged_control_delegate_test.cpp \
   metadata/tagged_control_options_test.cpp \
   metadata/v4l2_control_delegate_test.cpp \
+  static_properties_test.cpp \
 
 # V4L2 Camera HAL.
 # ==============================================================================
diff --git a/modules/camera/3_4/metadata/metadata_reader.cpp b/modules/camera/3_4/metadata/metadata_reader.cpp
new file mode 100644
index 0000000..c570048
--- /dev/null
+++ b/modules/camera/3_4/metadata/metadata_reader.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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 "metadata_reader.h"
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "MetadataReader"
+#include <cutils/log.h>
+#include <system/camera.h>
+
+#include "metadata_common.h"
+
+namespace default_camera_hal {
+
+MetadataReader::MetadataReader(
+    std::unique_ptr<const android::CameraMetadata> metadata)
+    : metadata_(std::move(metadata)) {}
+
+MetadataReader::~MetadataReader() {}
+
+int MetadataReader::Facing(int* facing) const {
+  uint8_t metadata_facing = 0;
+  int res = v4l2_camera_hal::SingleTagValue(
+      *metadata_, ANDROID_LENS_FACING, &metadata_facing);
+  if (res) {
+    ALOGE("%s: Failed to get facing from static metadata.", __func__);
+    return res;
+  }
+
+  switch (metadata_facing) {
+    case (ANDROID_LENS_FACING_FRONT):
+      *facing = CAMERA_FACING_FRONT;
+      break;
+    case (ANDROID_LENS_FACING_BACK):
+      *facing = CAMERA_FACING_BACK;
+      break;
+    case (ANDROID_LENS_FACING_EXTERNAL):
+      *facing = CAMERA_FACING_EXTERNAL;
+      break;
+    default:
+      ALOGE("%s: Invalid facing from static metadata: %d.",
+            __func__,
+            metadata_facing);
+      return -EINVAL;
+  }
+  return 0;
+}
+
+int MetadataReader::Orientation(int* orientation) const {
+  int32_t metadata_orientation = 0;
+  int res = v4l2_camera_hal::SingleTagValue(
+      *metadata_, ANDROID_SENSOR_ORIENTATION, &metadata_orientation);
+  if (res) {
+    ALOGE("%s: Failed to get orientation from static metadata.", __func__);
+    return res;
+  }
+
+  // Orientation must be 0, 90, 180, or 270.
+  if (metadata_orientation < 0 || metadata_orientation > 270 ||
+      metadata_orientation % 90 != 0) {
+    ALOGE(
+        "%s: Invalid orientation %d "
+        "(must be a 90-degree increment in [0, 360)).",
+        __func__,
+        metadata_orientation);
+    return -EINVAL;
+  }
+
+  *orientation = static_cast<int>(metadata_orientation);
+  return 0;
+}
+
+}  // namespace default_camera_hal
diff --git a/modules/camera/3_4/metadata/metadata_reader.h b/modules/camera/3_4/metadata/metadata_reader.h
new file mode 100644
index 0000000..64bedd6
--- /dev/null
+++ b/modules/camera/3_4/metadata/metadata_reader.h
@@ -0,0 +1,63 @@
+/*
+ * 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 DEFAULT_CAMERA_HAL_METADATA_METADATA_READER_H_
+#define DEFAULT_CAMERA_HAL_METADATA_METADATA_READER_H_
+
+#include <memory>
+
+#include <camera/CameraMetadata.h>
+
+#include "../common.h"
+
+namespace default_camera_hal {
+
+// A MetadataReader reads and converts/validates various metadata entries.
+class MetadataReader {
+ public:
+  MetadataReader(std::unique_ptr<const android::CameraMetadata> metadata);
+  virtual ~MetadataReader();
+
+  // Get a pointer to the underlying metadata being read.
+  // The pointer is valid only as long as this object is alive.
+  // The "locking" here only causes non-const methods to fail,
+  // which is not a problem since the CameraMetadata being locked
+  // is already const. This could be a problem if the metadata was
+  // shared more widely, but |metadata_| is a unique_ptr,
+  // guaranteeing the safety of this. Destructing automatically "unlocks".
+  virtual const camera_metadata_t* raw_metadata() const {
+    return metadata_->getAndLock();
+  }
+
+  // All accessor methods must be given a valid pointer. They will return:
+  // 0: Success.
+  // -ENOENT: The necessary entry is missing.
+  // -EINVAL: The entry value is invalid.
+  // -ENODEV: Some other error occured.
+
+  // The |facing| returned will be one of the enum values from system/camera.h.
+  virtual int Facing(int* facing) const;
+  virtual int Orientation(int* orientation) const;
+
+ private:
+  std::unique_ptr<const android::CameraMetadata> metadata_;
+
+  DISALLOW_COPY_AND_ASSIGN(MetadataReader);
+};
+
+}  // namespace default_camera_hal
+
+#endif  // DEFAULT_CAMERA_HAL_METADATA_METADATA_READER_H_
diff --git a/modules/camera/3_4/metadata/metadata_reader_mock.h b/modules/camera/3_4/metadata/metadata_reader_mock.h
new file mode 100644
index 0000000..096cefe
--- /dev/null
+++ b/modules/camera/3_4/metadata/metadata_reader_mock.h
@@ -0,0 +1,38 @@
+/*
+ * 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 metadata readers.
+
+#ifndef DEFAULT_CAMERA_HAL_METADATA_METADATA_READER_MOCK_H_
+#define DEFAULT_CAMERA_HAL_METADATA_METADATA_READER_MOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "metadata_reader.h"
+
+namespace default_camera_hal {
+
+class MetadataReaderMock : public MetadataReader {
+ public:
+  MetadataReaderMock() : MetadataReader(nullptr){};
+  MOCK_CONST_METHOD0(raw_metadata, const camera_metadata_t*());
+  MOCK_CONST_METHOD1(Facing, int(int*));
+  MOCK_CONST_METHOD1(Orientation, int(int*));
+};
+
+}  // namespace default_camera_hal
+
+#endif  // DEFAULT_CAMERA_HAL_METADATA_METADATA_READER_MOCK_H_
diff --git a/modules/camera/3_4/metadata/metadata_reader_test.cpp b/modules/camera/3_4/metadata/metadata_reader_test.cpp
new file mode 100644
index 0000000..cdbb3f9
--- /dev/null
+++ b/modules/camera/3_4/metadata/metadata_reader_test.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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 "metadata_reader.h"
+
+#include <camera/CameraMetadata.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <system/camera.h>
+
+#include "metadata_common.h"
+
+using testing::AtMost;
+using testing::Expectation;
+using testing::Return;
+using testing::Test;
+
+namespace default_camera_hal {
+
+class MetadataReaderTest : public Test {
+ protected:
+  void SetUp() {
+    ResetMetadata();
+    // FillDUT should be called before using the device under test.
+    dut_.reset();
+  }
+
+  void ResetMetadata() {
+    metadata_ = std::make_unique<android::CameraMetadata>();
+  }
+
+  void FillDUT() {
+    dut_ = std::make_unique<MetadataReader>(std::move(metadata_));
+    ResetMetadata();
+  }
+
+  std::unique_ptr<MetadataReader> dut_;
+  std::unique_ptr<android::CameraMetadata> metadata_;
+
+  const int32_t facing_tag_ = ANDROID_LENS_FACING;
+  const int32_t orientation_tag_ = ANDROID_SENSOR_ORIENTATION;
+  const std::vector<int32_t> valid_orientations_ = {0, 90, 180, 270};
+};
+
+TEST_F(MetadataReaderTest, FacingTranslations) {
+  // Check that the enums are converting properly.
+  std::map<uint8_t, int> translations{
+      {ANDROID_LENS_FACING_FRONT, CAMERA_FACING_FRONT},
+      {ANDROID_LENS_FACING_BACK, CAMERA_FACING_BACK},
+      {ANDROID_LENS_FACING_EXTERNAL, CAMERA_FACING_EXTERNAL}};
+  for (const auto& translation : translations) {
+    ASSERT_EQ(v4l2_camera_hal::UpdateMetadata(
+                  metadata_.get(), facing_tag_, translation.first),
+              0);
+    FillDUT();
+
+    int expected = translation.second;
+    int actual = expected + 1;
+    EXPECT_EQ(dut_->Facing(&actual), 0);
+    EXPECT_EQ(actual, expected);
+  }
+}
+
+TEST_F(MetadataReaderTest, InvalidFacing) {
+  uint8_t invalid = 99;
+  ASSERT_EQ(
+      v4l2_camera_hal::UpdateMetadata(metadata_.get(), facing_tag_, invalid),
+      0);
+  FillDUT();
+  int actual = 0;
+  EXPECT_EQ(dut_->Facing(&actual), -EINVAL);
+}
+
+TEST_F(MetadataReaderTest, EmptyFacing) {
+  FillDUT();
+  int actual = 0;
+  EXPECT_EQ(dut_->Facing(&actual), -ENOENT);
+}
+
+TEST_F(MetadataReaderTest, ValidOrientations) {
+  for (int32_t orientation : valid_orientations_) {
+    ASSERT_EQ(v4l2_camera_hal::UpdateMetadata(
+                  metadata_.get(), orientation_tag_, orientation),
+              0);
+    FillDUT();
+
+    int actual = orientation + 1;
+    EXPECT_EQ(dut_->Orientation(&actual), 0);
+    EXPECT_EQ(actual, orientation);
+  }
+}
+
+TEST_F(MetadataReaderTest, InvalidOrientations) {
+  // High.
+  for (int32_t orientation : valid_orientations_) {
+    ASSERT_EQ(v4l2_camera_hal::UpdateMetadata(
+                  metadata_.get(), orientation_tag_, orientation + 1),
+              0);
+    FillDUT();
+    int actual = 0;
+    EXPECT_EQ(dut_->Orientation(&actual), -EINVAL);
+  }
+  // Low.
+  for (int32_t orientation : valid_orientations_) {
+    ASSERT_EQ(v4l2_camera_hal::UpdateMetadata(
+                  metadata_.get(), orientation_tag_, orientation - 1),
+              0);
+    FillDUT();
+    int actual = 0;
+    EXPECT_EQ(dut_->Orientation(&actual), -EINVAL);
+  }
+}
+
+TEST_F(MetadataReaderTest, EmptyOrientation) {
+  FillDUT();
+  int actual = 0;
+  EXPECT_EQ(dut_->Orientation(&actual), -ENOENT);
+}
+
+}  // namespace default_camera_hal
diff --git a/modules/camera/3_4/metadata/partial_metadata_factory.h b/modules/camera/3_4/metadata/partial_metadata_factory.h
index 27ea6e8..13f3d61 100644
--- a/modules/camera/3_4/metadata/partial_metadata_factory.h
+++ b/modules/camera/3_4/metadata/partial_metadata_factory.h
@@ -223,9 +223,6 @@
           HAL_LOGE("Error converting value %d for control %d.", i, control_id);
           return nullptr;
         }
-        if (control_id == V4L2_CID_COLORFX) {
-          HAL_LOGE("Adding color effect %d (%d)", i, metadata_val);
-        }
         options.push_back(metadata_val);
       }
       // Check to make sure there's at least one option.
diff --git a/modules/camera/3_4/static_properties.cpp b/modules/camera/3_4/static_properties.cpp
new file mode 100644
index 0000000..a55e9e0
--- /dev/null
+++ b/modules/camera/3_4/static_properties.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 "static_properties.h"
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "StaticProperties"
+#include <cutils/log.h>
+#include <system/camera.h>
+
+#include "metadata/metadata_reader.h"
+
+namespace default_camera_hal {
+
+StaticProperties* StaticProperties::NewStaticProperties(
+    std::unique_ptr<const MetadataReader> metadata_reader) {
+  int facing = 0;
+  int orientation = 0;
+  // If reading any data returns an error, something is wrong.
+  if (metadata_reader->Facing(&facing) ||
+      metadata_reader->Orientation(&orientation)) {
+    return nullptr;
+  }
+
+  return new StaticProperties(std::move(metadata_reader), facing, orientation);
+}
+
+StaticProperties::StaticProperties(
+    std::unique_ptr<const MetadataReader> metadata_reader,
+    int facing,
+    int orientation)
+    : metadata_reader_(std::move(metadata_reader)),
+      facing_(facing),
+      orientation_(orientation) {}
+
+}  // namespace default_camera_hal
diff --git a/modules/camera/3_4/static_properties.h b/modules/camera/3_4/static_properties.h
new file mode 100644
index 0000000..77d5c92
--- /dev/null
+++ b/modules/camera/3_4/static_properties.h
@@ -0,0 +1,61 @@
+/*
+ * 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 DEFAULT_CAMERA_HAL_STATIC_PROPERTIES_H_
+#define DEFAULT_CAMERA_HAL_STATIC_PROPERTIES_H_
+
+#include <memory>
+
+#include "common.h"
+#include "metadata/metadata_reader.h"
+
+namespace default_camera_hal {
+
+// StaticProperties provides a wrapper around useful static metadata entries.
+class StaticProperties {
+ public:
+  // Use this method to create StaticProperties objects.
+  // Functionally equivalent to "new StaticProperties",
+  // except that it may return nullptr in case of failure (missing entries).
+  static StaticProperties* NewStaticProperties(
+      std::unique_ptr<const MetadataReader> metadata_reader);
+  virtual ~StaticProperties(){};
+
+  int facing() const { return facing_; };
+  int orientation() const { return orientation_; };
+  // Carrying on the promise of the underlying reader,
+  // the returned pointer is valid only as long as this object is alive.
+  const camera_metadata_t* raw_metadata() const {
+    return metadata_reader_->raw_metadata();
+  };
+
+ private:
+  // Constructor private to allow failing on bad input.
+  // Use NewStaticProperties instead.
+  StaticProperties(std::unique_ptr<const MetadataReader> metadata_reader,
+                   int facing,
+                   int orientation);
+
+  const std::unique_ptr<const MetadataReader> metadata_reader_;
+  const int facing_;
+  const int orientation_;
+
+  DISALLOW_COPY_AND_ASSIGN(StaticProperties);
+};
+
+}  // namespace default_camera_hal
+
+#endif  // DEFAULT_CAMERA_HAL_STATIC_PROPERTIES_H_
diff --git a/modules/camera/3_4/static_properties_test.cpp b/modules/camera/3_4/static_properties_test.cpp
new file mode 100644
index 0000000..7c05ad3
--- /dev/null
+++ b/modules/camera/3_4/static_properties_test.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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 "static_properties.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <system/camera.h>
+
+#include "metadata/metadata_reader_mock.h"
+
+using testing::AtMost;
+using testing::Expectation;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Test;
+using testing::_;
+
+namespace default_camera_hal {
+
+class StaticPropertiesTest : public Test {
+ protected:
+  void SetUp() {
+    // Ensure tests will probably fail if PrepareDUT isn't called.
+    dut_.reset();
+    mock_reader_ = std::make_unique<MetadataReaderMock>();
+  }
+
+  void PrepareDUT() {
+    dut_.reset(StaticProperties::NewStaticProperties(std::move(mock_reader_)));
+  }
+
+  void SetDefaultExpectations() {
+    EXPECT_CALL(*mock_reader_, Facing(_))
+        .Times(AtMost(1))
+        .WillOnce(DoAll(SetArgPointee<0>(test_facing_), Return(0)));
+    EXPECT_CALL(*mock_reader_, Orientation(_))
+        .Times(AtMost(1))
+        .WillOnce(DoAll(SetArgPointee<0>(test_orientation_), Return(0)));
+  }
+
+  std::unique_ptr<StaticProperties> dut_;
+  std::unique_ptr<MetadataReaderMock> mock_reader_;
+
+  const int test_facing_ = CAMERA_FACING_FRONT;
+  const int test_orientation_ = 90;
+};
+
+TEST_F(StaticPropertiesTest, FactorySuccess) {
+  SetDefaultExpectations();
+  PrepareDUT();
+  ASSERT_NE(dut_, nullptr);
+  EXPECT_EQ(dut_->facing(), test_facing_);
+  EXPECT_EQ(dut_->orientation(), test_orientation_);
+}
+
+TEST_F(StaticPropertiesTest, FactoryFailedFacing) {
+  SetDefaultExpectations();
+  // Override with a failure expectation.
+  EXPECT_CALL(*mock_reader_, Facing(_)).WillOnce(Return(99));
+  PrepareDUT();
+  EXPECT_EQ(dut_, nullptr);
+}
+
+TEST_F(StaticPropertiesTest, FactoryFailedOrientation) {
+  SetDefaultExpectations();
+  // Override with a failure expectation.
+  EXPECT_CALL(*mock_reader_, Orientation(_)).WillOnce(Return(99));
+  PrepareDUT();
+  EXPECT_EQ(dut_, nullptr);
+}
+
+}  // namespace default_camera_hal