blob: 615a77c5d58d2d2282ca0b7778900a884c09832d [file] [log] [blame]
/*
* Copyright (C) 2023 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 <memory>
#include "VirtualCameraProvider.h"
#include "aidl/android/hardware/camera/common/CameraDeviceStatus.h"
#include "aidl/android/hardware/camera/common/Status.h"
#include "aidl/android/hardware/camera/common/TorchModeStatus.h"
#include "aidl/android/hardware/camera/provider/BnCameraProviderCallback.h"
#include "android/binder_auto_utils.h"
#include "android/binder_interface_utils.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "util/Util.h"
namespace android {
namespace companion {
namespace virtualcamera {
namespace {
using ::aidl::android::companion::virtualcamera::Format;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::common::TorchModeStatus;
using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
using ::testing::_;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::IsEmpty;
using ::testing::IsNull;
using ::testing::MatchesRegex;
using ::testing::Not;
using ::testing::Return;
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
constexpr char kVirtualCameraNameRegex[] =
"device@[0-9]+\\.[0-9]+/virtual/[0-9]+";
class MockCameraProviderCallback : public BnCameraProviderCallback {
public:
MOCK_METHOD(ndk::ScopedAStatus, cameraDeviceStatusChange,
(const std::string&, CameraDeviceStatus), (override));
MOCK_METHOD(ndk::ScopedAStatus, torchModeStatusChange,
(const std::string&, TorchModeStatus), (override));
MOCK_METHOD(ndk::ScopedAStatus, physicalCameraDeviceStatusChange,
(const std::string&, const std::string&, CameraDeviceStatus),
(override));
};
class VirtualCameraProviderTest : public ::testing::Test {
public:
void SetUp() override {
mCameraProvider = ndk::SharedRefBase::make<VirtualCameraProvider>();
mMockCameraProviderCallback =
ndk::SharedRefBase::make<MockCameraProviderCallback>();
ON_CALL(*mMockCameraProviderCallback, cameraDeviceStatusChange)
.WillByDefault([](const std::string&, CameraDeviceStatus) {
return ndk::ScopedAStatus::ok();
});
}
protected:
std::shared_ptr<VirtualCameraProvider> mCameraProvider;
std::shared_ptr<MockCameraProviderCallback> mMockCameraProviderCallback =
ndk::SharedRefBase::make<MockCameraProviderCallback>();
std::vector<SupportedStreamConfiguration> mInputConfigs = {
SupportedStreamConfiguration{.width = kVgaWidth,
.height = kVgaHeight,
.pixelFormat = Format::YUV_420_888}};
};
TEST_F(VirtualCameraProviderTest, SetNullCameraCallbackFails) {
// Attempting to set callback to nullptr should fail.
EXPECT_FALSE(mCameraProvider->setCallback(nullptr).isOk());
}
TEST_F(VirtualCameraProviderTest, NoCamerasInitially) {
std::vector<std::string> cameras;
// Initially, the camera provider should return empty list
// of cameras.
ASSERT_TRUE(mCameraProvider->getCameraIdList(&cameras).isOk());
EXPECT_THAT(cameras, IsEmpty());
}
TEST_F(VirtualCameraProviderTest, CreateCamera) {
// When new camera is created, we expect
// cameraDeviceStatusChange to be called exactly once with
// PRESENT status.
EXPECT_CALL(*mMockCameraProviderCallback,
cameraDeviceStatusChange(_, CameraDeviceStatus::PRESENT))
.WillOnce(Return(ndk::ScopedAStatus::ok()));
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
mCameraProvider->createCamera(mInputConfigs);
EXPECT_THAT(camera, Not(IsNull()));
EXPECT_THAT(camera->getCameraName(), MatchesRegex(kVirtualCameraNameRegex));
// Created camera should be in the list of cameras.
std::vector<std::string> cameraIds;
ASSERT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
EXPECT_THAT(cameraIds, ElementsAre(camera->getCameraName()));
}
TEST_F(VirtualCameraProviderTest, CreateCameraBeforeCallbackIsSet) {
// We expect cameraDeviceStatusChange to be invoked even when the
// setCallback configures the callback after camera is already created.
EXPECT_CALL(*mMockCameraProviderCallback,
cameraDeviceStatusChange(_, CameraDeviceStatus::PRESENT))
.WillOnce(Return(ndk::ScopedAStatus::ok()));
std::shared_ptr<VirtualCameraDevice> camera =
mCameraProvider->createCamera(mInputConfigs);
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
// Created camera should be in the list of cameras.
std::vector<std::string> cameraIds;
EXPECT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
EXPECT_THAT(cameraIds, ElementsAre(camera->getCameraName()));
}
TEST_F(VirtualCameraProviderTest, RemoveCamera) {
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
mCameraProvider->createCamera(mInputConfigs);
EXPECT_CALL(*mMockCameraProviderCallback,
cameraDeviceStatusChange(Eq(camera->getCameraName()),
CameraDeviceStatus::NOT_PRESENT))
.WillOnce(Return(ndk::ScopedAStatus::ok()));
EXPECT_TRUE(mCameraProvider->removeCamera(camera->getCameraName()));
// There are no cameras present after only camera is removed.
std::vector<std::string> cameraIds;
ASSERT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
EXPECT_THAT(cameraIds, IsEmpty());
}
TEST_F(VirtualCameraProviderTest, RemoveNonExistingCamera) {
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
mCameraProvider->createCamera(mInputConfigs);
// Removing non-existing camera should fail.
const std::string cameraName = "DefinitelyNoTCamera";
EXPECT_FALSE(mCameraProvider->removeCamera(cameraName));
// Camera should be still present in the camera list.
std::vector<std::string> cameraIds;
ASSERT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
EXPECT_THAT(cameraIds, ElementsAre(camera->getCameraName()));
}
} // namespace
} // namespace virtualcamera
} // namespace companion
} // namespace android