| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/capture/video/chromeos/camera_3a_controller.h" |
| |
| #include <functional> |
| |
| #include "base/bind.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "base/threading/thread.h" |
| #include "media/capture/video/chromeos/camera_metadata_utils.h" |
| #include "media/capture/video/chromeos/request_builder.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::_; |
| |
| namespace media { |
| |
| namespace { |
| |
| class MockCaptureMetadataDispatcher : public CaptureMetadataDispatcher { |
| public: |
| MockCaptureMetadataDispatcher() {} |
| ~MockCaptureMetadataDispatcher() override {} |
| MOCK_METHOD1( |
| AddResultMetadataObserver, |
| void(CaptureMetadataDispatcher::ResultMetadataObserver* observer)); |
| MOCK_METHOD1( |
| RemoveResultMetadataObserver, |
| void(CaptureMetadataDispatcher::ResultMetadataObserver* observer)); |
| MOCK_METHOD4(SetCaptureMetadata, |
| void(cros::mojom::CameraMetadataTag tag, |
| cros::mojom::EntryType type, |
| size_t count, |
| std::vector<uint8_t> value)); |
| MOCK_METHOD4(SetRepeatingCaptureMetadata, |
| void(cros::mojom::CameraMetadataTag tag, |
| cros::mojom::EntryType type, |
| size_t count, |
| std::vector<uint8_t> value)); |
| MOCK_METHOD1(UnsetRepeatingCaptureMetadata, |
| void(cros::mojom::CameraMetadataTag tag)); |
| }; |
| |
| } // namespace |
| |
| class Camera3AControllerTest : public ::testing::Test { |
| public: |
| Camera3AControllerTest() : thread_("Camera3AControllerThread") {} |
| |
| void SetUp() override { |
| thread_.Start(); |
| mock_capture_metadata_dispatcher_ = |
| std::make_unique<MockCaptureMetadataDispatcher>(); |
| } |
| |
| void TearDown() override { |
| thread_.task_runner()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&Camera3AControllerTest::Clear3AControllerOnThread, |
| base::Unretained(this))); |
| thread_.Stop(); |
| mock_capture_metadata_dispatcher_.reset(); |
| } |
| |
| void RunOnThreadSync(const base::Location& location, |
| base::OnceClosure closure) { |
| base::WaitableEvent done(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| thread_.task_runner()->PostTask( |
| location, |
| base::BindOnce(&Camera3AControllerTest::RunOnThread, |
| base::Unretained(this), std::cref(location), |
| base::Passed(&closure), base::Unretained(&done))); |
| done.Wait(); |
| } |
| |
| void Reset3AController( |
| const cros::mojom::CameraMetadataPtr& static_metadata) { |
| RunOnThreadSync( |
| FROM_HERE, |
| base::BindOnce(&Camera3AControllerTest::Reset3AControllerOnThread, |
| base::Unretained(this), std::cref(static_metadata))); |
| } |
| |
| template <typename Value> |
| void Set3AMode(cros::mojom::CameraMetadataPtr* metadata, |
| cros::mojom::CameraMetadataTag control, |
| Value value, |
| bool append = false) { |
| auto* e = GetMetadataEntry(*metadata, control); |
| if (e) { |
| if (append) { |
| (*e)->count++; |
| (*e)->data.push_back(base::checked_cast<uint8_t>(value)); |
| } else { |
| (*e)->count = 1; |
| (*e)->data = {base::checked_cast<uint8_t>(value)}; |
| } |
| } else { |
| cros::mojom::CameraMetadataEntryPtr entry = |
| cros::mojom::CameraMetadataEntry::New(); |
| entry->index = (*metadata)->entries.value().size(); |
| entry->tag = control; |
| entry->type = cros::mojom::EntryType::TYPE_BYTE; |
| entry->count = 1; |
| entry->data = {base::checked_cast<uint8_t>(value)}; |
| |
| (*metadata)->entries.value().push_back(std::move(entry)); |
| (*metadata)->entry_count++; |
| (*metadata)->entry_capacity++; |
| } |
| SortCameraMetadata(metadata); |
| } |
| |
| cros::mojom::CameraMetadataPtr CreateDefaultFakeStaticMetadata() { |
| auto metadata = cros::mojom::CameraMetadata::New(); |
| metadata->entries = std::vector<cros::mojom::CameraMetadataEntryPtr>(); |
| metadata->entry_count = 0; |
| metadata->entry_capacity = 0; |
| |
| // Set the available AF modes. |
| Set3AMode( |
| &metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF); |
| Set3AMode( |
| &metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO, |
| /* append */ true); |
| Set3AMode( |
| &metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAfMode:: |
| ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE, |
| /* append */ true); |
| Set3AMode( |
| &metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAfMode:: |
| ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO, |
| /* append */ true); |
| |
| // Set the available AE modes. |
| Set3AMode( |
| &metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAeMode::ANDROID_CONTROL_AE_MODE_OFF); |
| Set3AMode( |
| &metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAeMode::ANDROID_CONTROL_AE_MODE_ON, |
| /* append */ true); |
| |
| // Set the available AWB modes. |
| Set3AMode( |
| &metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAwbMode::ANDROID_CONTROL_AWB_MODE_OFF); |
| Set3AMode( |
| &metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAwbMode::ANDROID_CONTROL_AWB_MODE_AUTO, |
| /* append */ true); |
| |
| return metadata; |
| } |
| |
| void On3AStabilizedCallback(base::WaitableEvent* done) { done->Signal(); } |
| |
| protected: |
| base::Thread thread_; |
| std::unique_ptr<MockCaptureMetadataDispatcher> |
| mock_capture_metadata_dispatcher_; |
| std::unique_ptr<Camera3AController> camera_3a_controller_; |
| |
| private: |
| void RunOnThread(const base::Location& location, |
| base::OnceClosure closure, |
| base::WaitableEvent* done) { |
| DCHECK(thread_.task_runner()->BelongsToCurrentThread()); |
| |
| std::move(closure).Run(); |
| done->Signal(); |
| } |
| |
| void Clear3AControllerOnThread() { |
| DCHECK(thread_.task_runner()->BelongsToCurrentThread()); |
| |
| if (camera_3a_controller_) { |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| RemoveResultMetadataObserver(camera_3a_controller_.get())) |
| .Times(1); |
| } |
| camera_3a_controller_.reset(); |
| } |
| |
| void Reset3AControllerOnThread( |
| const cros::mojom::CameraMetadataPtr& static_metadata) { |
| DCHECK(thread_.task_runner()->BelongsToCurrentThread()); |
| |
| Clear3AControllerOnThread(); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| AddResultMetadataObserver(_)) |
| .Times(1); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, |
| cros::mojom::EntryType::TYPE_BYTE, 1, _)) |
| .Times(1); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_MODE, |
| cros::mojom::EntryType::TYPE_BYTE, 1, _)) |
| .Times(1); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE, |
| cros::mojom::EntryType::TYPE_BYTE, 1, _)) |
| .Times(1); |
| camera_3a_controller_ = std::make_unique<Camera3AController>( |
| static_metadata, mock_capture_metadata_dispatcher_.get(), |
| thread_.task_runner()); |
| } |
| }; |
| |
| TEST_F(Camera3AControllerTest, Stabilize3AForStillCaptureTest) { |
| Reset3AController(CreateDefaultFakeStaticMetadata()); |
| |
| // Set AF mode. |
| std::vector<uint8_t> af_trigger_start, af_trigger_cancel, af_mode, ae_trigger; |
| af_trigger_start = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAfTrigger::ANDROID_CONTROL_AF_TRIGGER_START)}; |
| af_trigger_cancel = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAfTrigger::ANDROID_CONTROL_AF_TRIGGER_CANCEL)}; |
| af_mode = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAfMode:: |
| ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE)}; |
| ae_trigger = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAePrecaptureTrigger:: |
| ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START)}; |
| |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger_cancel)) |
| .Times(1); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) |
| .Times(1); |
| RunOnThreadSync( |
| FROM_HERE, |
| base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture, |
| base::Unretained(camera_3a_controller_.get()))); |
| |
| // |camera_3a_controller_| should wait until the AF mode is set |
| // before setting the AF and AE precapture triggers. |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger_start)) |
| .Times(0); |
| EXPECT_CALL( |
| *mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, |
| cros::mojom::EntryType::TYPE_BYTE, 1, ae_trigger)) |
| .Times(0); |
| base::WaitableEvent done(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| RunOnThreadSync( |
| FROM_HERE, |
| base::BindOnce( |
| &Camera3AController::Stabilize3AForStillCapture, |
| base::Unretained(camera_3a_controller_.get()), |
| base::BindOnce(&Camera3AControllerTest::On3AStabilizedCallback, |
| base::Unretained(this), &done))); |
| testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); |
| |
| // |camera_3a_controller_| should set the AF and AE precapture triggers once |
| // the 3A modes are set. |
| auto result_metadata = CreateDefaultFakeStaticMetadata(); |
| Set3AMode(&result_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, |
| cros::mojom::AndroidControlAfMode:: |
| ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE); |
| Set3AMode( |
| &result_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_STATE, |
| cros::mojom::AndroidControlAfState::ANDROID_CONTROL_AF_STATE_INACTIVE); |
| Set3AMode(&result_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_MODE, |
| cros::mojom::AndroidControlAeMode::ANDROID_CONTROL_AE_MODE_ON); |
| Set3AMode( |
| &result_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_STATE, |
| cros::mojom::AndroidControlAeState::ANDROID_CONTROL_AE_STATE_INACTIVE); |
| Set3AMode(&result_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_MODE, |
| cros::mojom::AndroidControlAwbMode::ANDROID_CONTROL_AWB_MODE_AUTO); |
| Set3AMode( |
| &result_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_STATE, |
| cros::mojom::AndroidControlAwbState::ANDROID_CONTROL_AWB_STATE_INACTIVE); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger_start)) |
| .Times(1); |
| EXPECT_CALL( |
| *mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, |
| cros::mojom::EntryType::TYPE_BYTE, 1, ae_trigger)) |
| .Times(1); |
| RunOnThreadSync(FROM_HERE, |
| base::BindOnce(&Camera3AController::OnResultMetadataAvailable, |
| base::Unretained(camera_3a_controller_.get()), |
| std::cref(result_metadata))); |
| |
| // |camera_3a_controller_| should call the registered callback once 3A are |
| // stabilized. |
| Set3AMode(&result_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_STATE, |
| cros::mojom::AndroidControlAfState:: |
| ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED); |
| Set3AMode( |
| &result_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AE_STATE, |
| cros::mojom::AndroidControlAeState::ANDROID_CONTROL_AE_STATE_CONVERGED); |
| Set3AMode( |
| &result_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AWB_STATE, |
| cros::mojom::AndroidControlAwbState::ANDROID_CONTROL_AWB_STATE_CONVERGED); |
| RunOnThreadSync(FROM_HERE, |
| base::BindOnce(&Camera3AController::OnResultMetadataAvailable, |
| base::Unretained(camera_3a_controller_.get()), |
| std::cref(result_metadata))); |
| done.Wait(); |
| } |
| |
| // Test that SetAutoFocusModeForStillCapture sets the right auto-focus mode on |
| // cameras with different capabilities. |
| TEST_F(Camera3AControllerTest, SetAutoFocusModeForStillCaptureTest) { |
| auto static_metadata = CreateDefaultFakeStaticMetadata(); |
| std::vector<uint8_t> af_mode; |
| std::vector<uint8_t> af_trigger = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAfTrigger::ANDROID_CONTROL_AF_TRIGGER_CANCEL)}; |
| |
| // For camera that supports continuous auto-focus for picture mode. |
| Reset3AController(static_metadata); |
| af_mode = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAfMode:: |
| ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE)}; |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) |
| .Times(1); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) |
| .Times(1); |
| RunOnThreadSync( |
| FROM_HERE, |
| base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture, |
| base::Unretained(camera_3a_controller_.get()))); |
| testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); |
| |
| // For camera that only supports basic auto focus. |
| Set3AMode(&static_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF); |
| Set3AMode(&static_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO, |
| /* append */ true); |
| Reset3AController(static_metadata); |
| af_mode.clear(); |
| af_mode = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO)}; |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) |
| .Times(1); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) |
| .Times(1); |
| RunOnThreadSync( |
| FROM_HERE, |
| base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture, |
| base::Unretained(camera_3a_controller_.get()))); |
| testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); |
| |
| // For camera that is fixed-focus. |
| Set3AMode(&static_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF); |
| Reset3AController(static_metadata); |
| af_mode.clear(); |
| af_mode = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF)}; |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) |
| .Times(1); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) |
| .Times(1); |
| RunOnThreadSync( |
| FROM_HERE, |
| base::BindOnce(&Camera3AController::SetAutoFocusModeForStillCapture, |
| base::Unretained(camera_3a_controller_.get()))); |
| testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); |
| } |
| |
| // Test that SetAutoFocusModeForVideoRecording sets the right auto-focus mode on |
| // cameras with different capabilities. |
| TEST_F(Camera3AControllerTest, SetAutoFocusModeForVideoRecordingTest) { |
| auto static_metadata = CreateDefaultFakeStaticMetadata(); |
| std::vector<uint8_t> af_mode; |
| std::vector<uint8_t> af_trigger = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAfTrigger::ANDROID_CONTROL_AF_TRIGGER_CANCEL)}; |
| |
| // For camera that supports continuous auto-focus for picture mode. |
| Reset3AController(static_metadata); |
| af_mode = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAfMode:: |
| ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO)}; |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) |
| .Times(1); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) |
| .Times(1); |
| RunOnThreadSync( |
| FROM_HERE, |
| base::BindOnce(&Camera3AController::SetAutoFocusModeForVideoRecording, |
| base::Unretained(camera_3a_controller_.get()))); |
| testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); |
| |
| // For camera that only supports basic auto focus. |
| Set3AMode(&static_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF); |
| Set3AMode(&static_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO, |
| /* append */ true); |
| Reset3AController(static_metadata); |
| af_mode.clear(); |
| af_mode = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_AUTO)}; |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) |
| .Times(1); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) |
| .Times(1); |
| RunOnThreadSync( |
| FROM_HERE, |
| base::BindOnce(&Camera3AController::SetAutoFocusModeForVideoRecording, |
| base::Unretained(camera_3a_controller_.get()))); |
| testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); |
| |
| // For camera that is fixed-focus. |
| Set3AMode(&static_metadata, |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_AVAILABLE_MODES, |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF); |
| Reset3AController(static_metadata); |
| af_mode.clear(); |
| af_mode = {base::checked_cast<uint8_t>( |
| cros::mojom::AndroidControlAfMode::ANDROID_CONTROL_AF_MODE_OFF)}; |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_TRIGGER, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_trigger)) |
| .Times(1); |
| EXPECT_CALL(*mock_capture_metadata_dispatcher_, |
| SetCaptureMetadata( |
| cros::mojom::CameraMetadataTag::ANDROID_CONTROL_AF_MODE, |
| cros::mojom::EntryType::TYPE_BYTE, 1, af_mode)) |
| .Times(1); |
| RunOnThreadSync( |
| FROM_HERE, |
| base::BindOnce(&Camera3AController::SetAutoFocusModeForVideoRecording, |
| base::Unretained(camera_3a_controller_.get()))); |
| testing::Mock::VerifyAndClearExpectations(camera_3a_controller_.get()); |
| } |
| |
| // TODO(shik): Add tests for SetPointOfInterest(). |
| // TODO(shik): Add fake timestamps for result metadata. |
| |
| } // namespace media |