Loading services/camera/virtualcamera/VirtualCameraService.cc +132 −26 Original line number Diff line number Diff line Loading @@ -18,18 +18,25 @@ #define LOG_TAG "VirtualCameraService" #include "VirtualCameraService.h" #include <algorithm> #include <cinttypes> #include <cstdint> #include <cstdio> #include <iterator> #include <memory> #include <mutex> #include <optional> #include <regex> #include <variant> #include "VirtualCameraDevice.h" #include "VirtualCameraProvider.h" #include "aidl/android/companion/virtualcamera/Format.h" #include "aidl/android/companion/virtualcamera/LensFacing.h" #include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h" #include "android/binder_auto_utils.h" #include "android/binder_libbinder.h" #include "android/binder_status.h" #include "binder/Status.h" #include "util/Permissions.h" #include "util/Util.h" Loading Loading @@ -57,9 +64,15 @@ constexpr int kVgaHeight = 480; constexpr int kMaxFps = 60; constexpr char kEnableTestCameraCmd[] = "enable_test_camera"; constexpr char kDisableTestCameraCmd[] = "disable_test_camera"; constexpr char kHelp[] = "help"; constexpr char kShellCmdHelp[] = R"( Usage: cmd virtual_camera command [--option=value] Available commands: * enable_test_camera Options: --camera_id=(ID) - override numerical ID for test camera instance --lens_facing=(front|back|external) - specifies lens facing for test camera instance * disable_test_camera )"; constexpr char kCreateVirtualDevicePermission[] = Loading Loading @@ -102,6 +115,66 @@ ndk::ScopedAStatus validateConfiguration( return ndk::ScopedAStatus::ok(); } enum class Command { ENABLE_TEST_CAMERA, DISABLE_TEST_CAMERA, HELP, }; struct CommandWithOptions { Command command; std::map<std::string, std::string> optionToValueMap; }; std::optional<int> parseInt(const std::string& s) { if (!std::all_of(s.begin(), s.end(), [](char c) { return std::isdigit(c); })) { return std::nullopt; } int ret = atoi(s.c_str()); return ret > 0 ? std::optional(ret) : std::nullopt; } std::optional<LensFacing> parseLensFacing(const std::string& s) { static const std::map<std::string, LensFacing> strToLensFacing{ {"front", LensFacing::FRONT}, {"back", LensFacing::BACK}, {"external", LensFacing::EXTERNAL}}; auto it = strToLensFacing.find(s); return it == strToLensFacing.end() ? std::nullopt : std::optional(it->second); } std::variant<CommandWithOptions, std::string> parseCommand( const char** args, const uint32_t numArgs) { static const std::regex optionRegex("^--(\\w+)(?:=(.+))?$"); static const std::map<std::string, Command> strToCommand{ {kHelp, Command::HELP}, {kEnableTestCameraCmd, Command::ENABLE_TEST_CAMERA}, {kDisableTestCameraCmd, Command::DISABLE_TEST_CAMERA}}; if (numArgs < 1) { return CommandWithOptions{.command = Command::HELP}; } // We interpret the first argument as command; auto it = strToCommand.find(args[0]); if (it == strToCommand.end()) { return "Unknown command: " + std::string(args[0]); } CommandWithOptions cmd{.command = it->second}; for (int i = 1; i < numArgs; i++) { std::cmatch cm; if (!std::regex_match(args[i], cm, optionRegex)) { return "Not an option: " + std::string(args[i]); } cmd.optionToValueMap[cm[1]] = cm[2]; } return cmd; }; } // namespace VirtualCameraService::VirtualCameraService( Loading Loading @@ -232,8 +305,7 @@ std::shared_ptr<VirtualCameraDevice> VirtualCameraService::getCamera( return mVirtualCameraProvider->getCamera(it->second); } binder_status_t VirtualCameraService::handleShellCommand(int in, int out, int err, binder_status_t VirtualCameraService::handleShellCommand(int, int out, int err, const char** args, uint32_t numArgs) { if (numArgs <= 0) { Loading @@ -242,36 +314,68 @@ binder_status_t VirtualCameraService::handleShellCommand(int in, int out, return STATUS_OK; } if (args == nullptr || args[0] == nullptr) { auto isNullptr = [](const char* ptr) { return ptr == nullptr; }; if (args == nullptr || std::any_of(args, args + numArgs, isNullptr)) { return STATUS_BAD_VALUE; } const char* const cmd = args[0]; if (strcmp(kEnableTestCameraCmd, cmd) == 0) { int cameraId = 0; if (numArgs > 1 && args[1] != nullptr) { cameraId = atoi(args[1]); } if (cameraId == 0) { cameraId = sNextId++; std::variant<CommandWithOptions, std::string> cmdOrErrorMessage = parseCommand(args, numArgs); if (std::holds_alternative<std::string>(cmdOrErrorMessage)) { dprintf(err, "Error: %s\n", std::get<std::string>(cmdOrErrorMessage).c_str()); return STATUS_BAD_VALUE; } enableTestCameraCmd(in, err, cameraId); } else if (strcmp(kDisableTestCameraCmd, cmd) == 0) { disableTestCameraCmd(in); } else { const CommandWithOptions& cmd = std::get<CommandWithOptions>(cmdOrErrorMessage); binder_status_t status = STATUS_OK; switch (cmd.command) { case Command::HELP: dprintf(out, kShellCmdHelp); break; case Command::ENABLE_TEST_CAMERA: status = enableTestCameraCmd(out, err, cmd.optionToValueMap); break; case Command::DISABLE_TEST_CAMERA: disableTestCameraCmd(out); break; } fsync(err); fsync(out); return STATUS_OK; return status; } void VirtualCameraService::enableTestCameraCmd(const int out, const int err, const int cameraId) { binder_status_t VirtualCameraService::enableTestCameraCmd( const int out, const int err, const std::map<std::string, std::string>& options) { if (mTestCameraToken != nullptr) { dprintf(out, "Test camera is already enabled (%s).", dprintf(out, "Test camera is already enabled (%s).\n", getCamera(mTestCameraToken)->getCameraName().c_str()); return; return STATUS_OK; } std::optional<int> cameraId; auto it = options.find("camera_id"); if (it != options.end()) { cameraId = parseInt(it->second); if (!cameraId.has_value()) { dprintf(err, "Invalid camera_id: %s\n, must be number > 0", it->second.c_str()); return STATUS_BAD_VALUE; } } std::optional<LensFacing> lensFacing; it = options.find("lens_facing"); if (it != options.end()) { lensFacing = parseLensFacing(it->second); if (!lensFacing.has_value()) { dprintf(err, "Invalid lens_facing: %s\n, must be front|back|external", it->second.c_str()); return STATUS_BAD_VALUE; } } sp<BBinder> token = sp<BBinder>::make(); Loading @@ -283,14 +387,16 @@ void VirtualCameraService::enableTestCameraCmd(const int out, const int err, .height = kVgaHeight, Format::YUV_420_888, .maxFps = kMaxFps}); configuration.lensFacing = LensFacing::EXTERNAL; registerCamera(mTestCameraToken, configuration, cameraId, &ret); configuration.lensFacing = lensFacing.value_or(LensFacing::EXTERNAL); registerCamera(mTestCameraToken, configuration, cameraId.value_or(sNextId++), &ret); if (ret) { dprintf(out, "Successfully registered test camera %s", dprintf(out, "Successfully registered test camera %s\n", getCamera(mTestCameraToken)->getCameraName().c_str()); } else { dprintf(err, "Failed to create test camera"); dprintf(err, "Failed to create test camera\n"); } return STATUS_OK; } void VirtualCameraService::disableTestCameraCmd(const int out) { Loading services/camera/virtualcamera/VirtualCameraService.h +2 −1 Original line number Diff line number Diff line Loading @@ -71,7 +71,8 @@ class VirtualCameraService private: // Create and enable test camera instance if there's none. void enableTestCameraCmd(int out, int err, int cameraId); binder_status_t enableTestCameraCmd( int out, int err, const std::map<std::string, std::string>& options); // Disable and destroy test camera instance if there's one. void disableTestCameraCmd(int out); Loading services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc +53 −9 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include "binder/Binder.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "util/MetadataUtil.h" #include "util/Permissions.h" #include "utils/Errors.h" Loading @@ -47,6 +48,7 @@ using ::aidl::android::companion::virtualcamera::SensorOrientation; using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration; using ::aidl::android::hardware::camera::common::CameraDeviceStatus; using ::aidl::android::hardware::camera::common::TorchModeStatus; using ::aidl::android::hardware::camera::device::CameraMetadata; using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback; using ::aidl::android::hardware::graphics::common::PixelFormat; using ::aidl::android::view::Surface; Loading @@ -57,6 +59,7 @@ using ::testing::Ge; using ::testing::IsEmpty; using ::testing::IsNull; using ::testing::Not; using ::testing::Optional; using ::testing::Return; using ::testing::SizeIs; Loading Loading @@ -138,7 +141,7 @@ class VirtualCameraServiceTest : public ::testing::Test { close(mDevNullFd); } void execute_shell_command(const std::string& cmd) { binder_status_t execute_shell_command(const std::string& cmd) { const static std::regex whitespaceRegex("\\s+"); std::vector<std::string> tokens; std::copy_if( Loading @@ -151,10 +154,8 @@ class VirtualCameraServiceTest : public ::testing::Test { std::transform(tokens.begin(), tokens.end(), std::back_inserter(argv), [](const std::string& str) { return str.c_str(); }); ASSERT_THAT( mCameraService->handleShellCommand(mDevNullFd, mDevNullFd, mDevNullFd, argv.data(), argv.size()), Eq(NO_ERROR)); return mCameraService->handleShellCommand( mDevNullFd, mDevNullFd, mDevNullFd, argv.data(), argv.size()); } std::vector<std::string> getCameraIds() { Loading @@ -163,6 +164,17 @@ class VirtualCameraServiceTest : public ::testing::Test { return cameraIds; } std::optional<camera_metadata_enum_android_lens_facing> getCameraLensFacing( const std::string& id) { std::shared_ptr<VirtualCameraDevice> camera = mCameraProvider->getCamera(id); if (camera == nullptr) { return std::nullopt; } CameraMetadata metadata; camera->getCameraCharacteristics(&metadata); return getLensFacing(metadata); } protected: std::shared_ptr<VirtualCameraService> mCameraService; std::shared_ptr<VirtualCameraProvider> mCameraProvider; Loading Loading @@ -374,29 +386,61 @@ TEST_F(VirtualCameraServiceTest, ShellCmdWithNoArgs) { } TEST_F(VirtualCameraServiceTest, TestCameraShellCmd) { execute_shell_command("enable_test_camera"); EXPECT_THAT(execute_shell_command("enable_test_camera"), Eq(NO_ERROR)); std::vector<std::string> cameraIdsAfterEnable = getCameraIds(); EXPECT_THAT(cameraIdsAfterEnable, SizeIs(1)); execute_shell_command("disable_test_camera"); EXPECT_THAT(execute_shell_command("disable_test_camera"), Eq(NO_ERROR)); std::vector<std::string> cameraIdsAfterDisable = getCameraIds(); EXPECT_THAT(cameraIdsAfterDisable, IsEmpty()); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithId) { execute_shell_command("enable_test_camera 12345"); EXPECT_THAT(execute_shell_command("enable_test_camera --camera_id=12345"), Eq(NO_ERROR)); std::vector<std::string> cameraIdsAfterEnable = getCameraIds(); EXPECT_THAT(cameraIdsAfterEnable, ElementsAre("device@1.1/virtual/12345")); execute_shell_command("disable_test_camera"); EXPECT_THAT(execute_shell_command("disable_test_camera"), Eq(NO_ERROR)); std::vector<std::string> cameraIdsAfterDisable = getCameraIds(); EXPECT_THAT(cameraIdsAfterDisable, IsEmpty()); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithInvalidId) { EXPECT_THAT( execute_shell_command("enable_test_camera --camera_id=NotNumericalId"), Eq(STATUS_BAD_VALUE)); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithUnknownCommand) { EXPECT_THAT(execute_shell_command("brew_coffee --flavor=vanilla"), Eq(STATUS_BAD_VALUE)); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithMalformedOption) { EXPECT_THAT(execute_shell_command("enable_test_camera **camera_id=12345"), Eq(STATUS_BAD_VALUE)); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithLensFacing) { EXPECT_THAT(execute_shell_command("enable_test_camera --lens_facing=front"), Eq(NO_ERROR)); std::vector<std::string> cameraIds = getCameraIds(); ASSERT_THAT(cameraIds, SizeIs(1)); EXPECT_THAT(getCameraLensFacing(cameraIds[0]), Optional(Eq(ANDROID_LENS_FACING_FRONT))); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithInvalidLensFacing) { EXPECT_THAT(execute_shell_command("enable_test_camera --lens_facing=west"), Eq(STATUS_BAD_VALUE)); } } // namespace } // namespace virtualcamera } // namespace companion Loading services/camera/virtualcamera/util/MetadataUtil.cc +14 −0 Original line number Diff line number Diff line Loading @@ -903,6 +903,20 @@ std::optional<GpsCoordinates> getGpsCoordinates( return coordinates; } std::optional<camera_metadata_enum_android_lens_facing> getLensFacing( const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) { auto metadata = reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data()); camera_metadata_ro_entry_t entry; if (find_camera_metadata_ro_entry(metadata, ANDROID_LENS_FACING, &entry) != OK) { return std::nullopt; } return static_cast<camera_metadata_enum_android_lens_facing>(entry.data.u8[0]); } } // namespace virtualcamera } // namespace companion } // namespace android services/camera/virtualcamera/util/MetadataUtil.h +3 −0 Original line number Diff line number Diff line Loading @@ -469,6 +469,9 @@ std::optional<camera_metadata_enum_android_control_capture_intent> getCaptureInt std::optional<GpsCoordinates> getGpsCoordinates( const aidl::android::hardware::camera::device::CameraMetadata& metadata); std::optional<camera_metadata_enum_android_lens_facing> getLensFacing( const aidl::android::hardware::camera::device::CameraMetadata& metadata); } // namespace virtualcamera } // namespace companion } // namespace android Loading Loading
services/camera/virtualcamera/VirtualCameraService.cc +132 −26 Original line number Diff line number Diff line Loading @@ -18,18 +18,25 @@ #define LOG_TAG "VirtualCameraService" #include "VirtualCameraService.h" #include <algorithm> #include <cinttypes> #include <cstdint> #include <cstdio> #include <iterator> #include <memory> #include <mutex> #include <optional> #include <regex> #include <variant> #include "VirtualCameraDevice.h" #include "VirtualCameraProvider.h" #include "aidl/android/companion/virtualcamera/Format.h" #include "aidl/android/companion/virtualcamera/LensFacing.h" #include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h" #include "android/binder_auto_utils.h" #include "android/binder_libbinder.h" #include "android/binder_status.h" #include "binder/Status.h" #include "util/Permissions.h" #include "util/Util.h" Loading Loading @@ -57,9 +64,15 @@ constexpr int kVgaHeight = 480; constexpr int kMaxFps = 60; constexpr char kEnableTestCameraCmd[] = "enable_test_camera"; constexpr char kDisableTestCameraCmd[] = "disable_test_camera"; constexpr char kHelp[] = "help"; constexpr char kShellCmdHelp[] = R"( Usage: cmd virtual_camera command [--option=value] Available commands: * enable_test_camera Options: --camera_id=(ID) - override numerical ID for test camera instance --lens_facing=(front|back|external) - specifies lens facing for test camera instance * disable_test_camera )"; constexpr char kCreateVirtualDevicePermission[] = Loading Loading @@ -102,6 +115,66 @@ ndk::ScopedAStatus validateConfiguration( return ndk::ScopedAStatus::ok(); } enum class Command { ENABLE_TEST_CAMERA, DISABLE_TEST_CAMERA, HELP, }; struct CommandWithOptions { Command command; std::map<std::string, std::string> optionToValueMap; }; std::optional<int> parseInt(const std::string& s) { if (!std::all_of(s.begin(), s.end(), [](char c) { return std::isdigit(c); })) { return std::nullopt; } int ret = atoi(s.c_str()); return ret > 0 ? std::optional(ret) : std::nullopt; } std::optional<LensFacing> parseLensFacing(const std::string& s) { static const std::map<std::string, LensFacing> strToLensFacing{ {"front", LensFacing::FRONT}, {"back", LensFacing::BACK}, {"external", LensFacing::EXTERNAL}}; auto it = strToLensFacing.find(s); return it == strToLensFacing.end() ? std::nullopt : std::optional(it->second); } std::variant<CommandWithOptions, std::string> parseCommand( const char** args, const uint32_t numArgs) { static const std::regex optionRegex("^--(\\w+)(?:=(.+))?$"); static const std::map<std::string, Command> strToCommand{ {kHelp, Command::HELP}, {kEnableTestCameraCmd, Command::ENABLE_TEST_CAMERA}, {kDisableTestCameraCmd, Command::DISABLE_TEST_CAMERA}}; if (numArgs < 1) { return CommandWithOptions{.command = Command::HELP}; } // We interpret the first argument as command; auto it = strToCommand.find(args[0]); if (it == strToCommand.end()) { return "Unknown command: " + std::string(args[0]); } CommandWithOptions cmd{.command = it->second}; for (int i = 1; i < numArgs; i++) { std::cmatch cm; if (!std::regex_match(args[i], cm, optionRegex)) { return "Not an option: " + std::string(args[i]); } cmd.optionToValueMap[cm[1]] = cm[2]; } return cmd; }; } // namespace VirtualCameraService::VirtualCameraService( Loading Loading @@ -232,8 +305,7 @@ std::shared_ptr<VirtualCameraDevice> VirtualCameraService::getCamera( return mVirtualCameraProvider->getCamera(it->second); } binder_status_t VirtualCameraService::handleShellCommand(int in, int out, int err, binder_status_t VirtualCameraService::handleShellCommand(int, int out, int err, const char** args, uint32_t numArgs) { if (numArgs <= 0) { Loading @@ -242,36 +314,68 @@ binder_status_t VirtualCameraService::handleShellCommand(int in, int out, return STATUS_OK; } if (args == nullptr || args[0] == nullptr) { auto isNullptr = [](const char* ptr) { return ptr == nullptr; }; if (args == nullptr || std::any_of(args, args + numArgs, isNullptr)) { return STATUS_BAD_VALUE; } const char* const cmd = args[0]; if (strcmp(kEnableTestCameraCmd, cmd) == 0) { int cameraId = 0; if (numArgs > 1 && args[1] != nullptr) { cameraId = atoi(args[1]); } if (cameraId == 0) { cameraId = sNextId++; std::variant<CommandWithOptions, std::string> cmdOrErrorMessage = parseCommand(args, numArgs); if (std::holds_alternative<std::string>(cmdOrErrorMessage)) { dprintf(err, "Error: %s\n", std::get<std::string>(cmdOrErrorMessage).c_str()); return STATUS_BAD_VALUE; } enableTestCameraCmd(in, err, cameraId); } else if (strcmp(kDisableTestCameraCmd, cmd) == 0) { disableTestCameraCmd(in); } else { const CommandWithOptions& cmd = std::get<CommandWithOptions>(cmdOrErrorMessage); binder_status_t status = STATUS_OK; switch (cmd.command) { case Command::HELP: dprintf(out, kShellCmdHelp); break; case Command::ENABLE_TEST_CAMERA: status = enableTestCameraCmd(out, err, cmd.optionToValueMap); break; case Command::DISABLE_TEST_CAMERA: disableTestCameraCmd(out); break; } fsync(err); fsync(out); return STATUS_OK; return status; } void VirtualCameraService::enableTestCameraCmd(const int out, const int err, const int cameraId) { binder_status_t VirtualCameraService::enableTestCameraCmd( const int out, const int err, const std::map<std::string, std::string>& options) { if (mTestCameraToken != nullptr) { dprintf(out, "Test camera is already enabled (%s).", dprintf(out, "Test camera is already enabled (%s).\n", getCamera(mTestCameraToken)->getCameraName().c_str()); return; return STATUS_OK; } std::optional<int> cameraId; auto it = options.find("camera_id"); if (it != options.end()) { cameraId = parseInt(it->second); if (!cameraId.has_value()) { dprintf(err, "Invalid camera_id: %s\n, must be number > 0", it->second.c_str()); return STATUS_BAD_VALUE; } } std::optional<LensFacing> lensFacing; it = options.find("lens_facing"); if (it != options.end()) { lensFacing = parseLensFacing(it->second); if (!lensFacing.has_value()) { dprintf(err, "Invalid lens_facing: %s\n, must be front|back|external", it->second.c_str()); return STATUS_BAD_VALUE; } } sp<BBinder> token = sp<BBinder>::make(); Loading @@ -283,14 +387,16 @@ void VirtualCameraService::enableTestCameraCmd(const int out, const int err, .height = kVgaHeight, Format::YUV_420_888, .maxFps = kMaxFps}); configuration.lensFacing = LensFacing::EXTERNAL; registerCamera(mTestCameraToken, configuration, cameraId, &ret); configuration.lensFacing = lensFacing.value_or(LensFacing::EXTERNAL); registerCamera(mTestCameraToken, configuration, cameraId.value_or(sNextId++), &ret); if (ret) { dprintf(out, "Successfully registered test camera %s", dprintf(out, "Successfully registered test camera %s\n", getCamera(mTestCameraToken)->getCameraName().c_str()); } else { dprintf(err, "Failed to create test camera"); dprintf(err, "Failed to create test camera\n"); } return STATUS_OK; } void VirtualCameraService::disableTestCameraCmd(const int out) { Loading
services/camera/virtualcamera/VirtualCameraService.h +2 −1 Original line number Diff line number Diff line Loading @@ -71,7 +71,8 @@ class VirtualCameraService private: // Create and enable test camera instance if there's none. void enableTestCameraCmd(int out, int err, int cameraId); binder_status_t enableTestCameraCmd( int out, int err, const std::map<std::string, std::string>& options); // Disable and destroy test camera instance if there's one. void disableTestCameraCmd(int out); Loading
services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc +53 −9 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include "binder/Binder.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "util/MetadataUtil.h" #include "util/Permissions.h" #include "utils/Errors.h" Loading @@ -47,6 +48,7 @@ using ::aidl::android::companion::virtualcamera::SensorOrientation; using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration; using ::aidl::android::hardware::camera::common::CameraDeviceStatus; using ::aidl::android::hardware::camera::common::TorchModeStatus; using ::aidl::android::hardware::camera::device::CameraMetadata; using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback; using ::aidl::android::hardware::graphics::common::PixelFormat; using ::aidl::android::view::Surface; Loading @@ -57,6 +59,7 @@ using ::testing::Ge; using ::testing::IsEmpty; using ::testing::IsNull; using ::testing::Not; using ::testing::Optional; using ::testing::Return; using ::testing::SizeIs; Loading Loading @@ -138,7 +141,7 @@ class VirtualCameraServiceTest : public ::testing::Test { close(mDevNullFd); } void execute_shell_command(const std::string& cmd) { binder_status_t execute_shell_command(const std::string& cmd) { const static std::regex whitespaceRegex("\\s+"); std::vector<std::string> tokens; std::copy_if( Loading @@ -151,10 +154,8 @@ class VirtualCameraServiceTest : public ::testing::Test { std::transform(tokens.begin(), tokens.end(), std::back_inserter(argv), [](const std::string& str) { return str.c_str(); }); ASSERT_THAT( mCameraService->handleShellCommand(mDevNullFd, mDevNullFd, mDevNullFd, argv.data(), argv.size()), Eq(NO_ERROR)); return mCameraService->handleShellCommand( mDevNullFd, mDevNullFd, mDevNullFd, argv.data(), argv.size()); } std::vector<std::string> getCameraIds() { Loading @@ -163,6 +164,17 @@ class VirtualCameraServiceTest : public ::testing::Test { return cameraIds; } std::optional<camera_metadata_enum_android_lens_facing> getCameraLensFacing( const std::string& id) { std::shared_ptr<VirtualCameraDevice> camera = mCameraProvider->getCamera(id); if (camera == nullptr) { return std::nullopt; } CameraMetadata metadata; camera->getCameraCharacteristics(&metadata); return getLensFacing(metadata); } protected: std::shared_ptr<VirtualCameraService> mCameraService; std::shared_ptr<VirtualCameraProvider> mCameraProvider; Loading Loading @@ -374,29 +386,61 @@ TEST_F(VirtualCameraServiceTest, ShellCmdWithNoArgs) { } TEST_F(VirtualCameraServiceTest, TestCameraShellCmd) { execute_shell_command("enable_test_camera"); EXPECT_THAT(execute_shell_command("enable_test_camera"), Eq(NO_ERROR)); std::vector<std::string> cameraIdsAfterEnable = getCameraIds(); EXPECT_THAT(cameraIdsAfterEnable, SizeIs(1)); execute_shell_command("disable_test_camera"); EXPECT_THAT(execute_shell_command("disable_test_camera"), Eq(NO_ERROR)); std::vector<std::string> cameraIdsAfterDisable = getCameraIds(); EXPECT_THAT(cameraIdsAfterDisable, IsEmpty()); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithId) { execute_shell_command("enable_test_camera 12345"); EXPECT_THAT(execute_shell_command("enable_test_camera --camera_id=12345"), Eq(NO_ERROR)); std::vector<std::string> cameraIdsAfterEnable = getCameraIds(); EXPECT_THAT(cameraIdsAfterEnable, ElementsAre("device@1.1/virtual/12345")); execute_shell_command("disable_test_camera"); EXPECT_THAT(execute_shell_command("disable_test_camera"), Eq(NO_ERROR)); std::vector<std::string> cameraIdsAfterDisable = getCameraIds(); EXPECT_THAT(cameraIdsAfterDisable, IsEmpty()); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithInvalidId) { EXPECT_THAT( execute_shell_command("enable_test_camera --camera_id=NotNumericalId"), Eq(STATUS_BAD_VALUE)); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithUnknownCommand) { EXPECT_THAT(execute_shell_command("brew_coffee --flavor=vanilla"), Eq(STATUS_BAD_VALUE)); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithMalformedOption) { EXPECT_THAT(execute_shell_command("enable_test_camera **camera_id=12345"), Eq(STATUS_BAD_VALUE)); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithLensFacing) { EXPECT_THAT(execute_shell_command("enable_test_camera --lens_facing=front"), Eq(NO_ERROR)); std::vector<std::string> cameraIds = getCameraIds(); ASSERT_THAT(cameraIds, SizeIs(1)); EXPECT_THAT(getCameraLensFacing(cameraIds[0]), Optional(Eq(ANDROID_LENS_FACING_FRONT))); } TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithInvalidLensFacing) { EXPECT_THAT(execute_shell_command("enable_test_camera --lens_facing=west"), Eq(STATUS_BAD_VALUE)); } } // namespace } // namespace virtualcamera } // namespace companion Loading
services/camera/virtualcamera/util/MetadataUtil.cc +14 −0 Original line number Diff line number Diff line Loading @@ -903,6 +903,20 @@ std::optional<GpsCoordinates> getGpsCoordinates( return coordinates; } std::optional<camera_metadata_enum_android_lens_facing> getLensFacing( const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) { auto metadata = reinterpret_cast<const camera_metadata_t*>(cameraMetadata.metadata.data()); camera_metadata_ro_entry_t entry; if (find_camera_metadata_ro_entry(metadata, ANDROID_LENS_FACING, &entry) != OK) { return std::nullopt; } return static_cast<camera_metadata_enum_android_lens_facing>(entry.data.u8[0]); } } // namespace virtualcamera } // namespace companion } // namespace android
services/camera/virtualcamera/util/MetadataUtil.h +3 −0 Original line number Diff line number Diff line Loading @@ -469,6 +469,9 @@ std::optional<camera_metadata_enum_android_control_capture_intent> getCaptureInt std::optional<GpsCoordinates> getGpsCoordinates( const aidl::android::hardware::camera::device::CameraMetadata& metadata); std::optional<camera_metadata_enum_android_lens_facing> getLensFacing( const aidl::android::hardware::camera::device::CameraMetadata& metadata); } // namespace virtualcamera } // namespace companion } // namespace android Loading