Files
hardware_interfaces/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
Emilian Peev 8bdbf00a34 Camera: Remove binderized todo comment
The camera test cases already already run in binderized mode
for any devices that have this mode enabled.
Additionally remove the missing camera device todo as well.
This should be handled by the VTS infrastructure.
Camera provider service constant updated as well.

Bug: 38137798
Test: VtsHalCameraProviderV2_4TargetTest
Change-Id: I45ddf224dd4dac3ddfbbd751fa297e4631283537
2017-05-19 11:42:08 +01:00

3263 lines
134 KiB
C++

/*
* 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.
*/
#define LOG_TAG "camera_hidl_hal_test"
#include <VtsHalHidlTargetTestBase.h>
#include <android/hardware/camera/device/1.0/ICameraDevice.h>
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
#include <android/log.h>
#include <binder/MemoryHeapBase.h>
#include <grallocusage/GrallocUsageConversion.h>
#include <gui/BufferItemConsumer.h>
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
#include <hardware/gralloc.h>
#include <hardware/gralloc1.h>
#include <inttypes.h>
#include <system/camera.h>
#include <ui/GraphicBuffer.h>
#include <utils/Errors.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <regex>
#include <unordered_map>
#include "CameraParameters.h"
#include "system/camera_metadata.h"
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::sp;
using ::android::wp;
using ::android::GraphicBuffer;
using ::android::IGraphicBufferProducer;
using ::android::IGraphicBufferConsumer;
using ::android::BufferQueue;
using ::android::BufferItemConsumer;
using ::android::Surface;
using ::android::CameraParameters;
using ::android::hardware::graphics::common::V1_0::BufferUsage;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
using ::android::hardware::camera::common::V1_0::Status;
using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
using ::android::hardware::camera::common::V1_0::TorchMode;
using ::android::hardware::camera::common::V1_0::TorchModeStatus;
using ::android::hardware::camera::provider::V2_4::ICameraProvider;
using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
using ::android::hardware::camera::device::V3_2::ICameraDevice;
using ::android::hardware::camera::device::V3_2::BufferCache;
using ::android::hardware::camera::device::V3_2::CaptureRequest;
using ::android::hardware::camera::device::V3_2::CaptureResult;
using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
using ::android::hardware::camera::device::V3_2::NotifyMsg;
using ::android::hardware::camera::device::V3_2::RequestTemplate;
using ::android::hardware::camera::device::V3_2::Stream;
using ::android::hardware::camera::device::V3_2::StreamType;
using ::android::hardware::camera::device::V3_2::StreamRotation;
using ::android::hardware::camera::device::V3_2::StreamConfiguration;
using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
using ::android::hardware::camera::device::V3_2::CameraMetadata;
using ::android::hardware::camera::device::V3_2::HalStreamConfiguration;
using ::android::hardware::camera::device::V3_2::BufferStatus;
using ::android::hardware::camera::device::V3_2::StreamBuffer;
using ::android::hardware::camera::device::V3_2::MsgType;
using ::android::hardware::camera::device::V3_2::ErrorMsg;
using ::android::hardware::camera::device::V3_2::ErrorCode;
using ::android::hardware::camera::device::V1_0::CameraFacing;
using ::android::hardware::camera::device::V1_0::NotifyCallbackMsg;
using ::android::hardware::camera::device::V1_0::CommandType;
using ::android::hardware::camera::device::V1_0::DataCallbackMsg;
using ::android::hardware::camera::device::V1_0::CameraFrameMetadata;
using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback;
using ::android::hardware::camera::device::V1_0::FrameCallbackFlag;
using ::android::hardware::camera::device::V1_0::HandleTimestampMessage;
const char kCameraLegacyServiceName[] = "legacy/0";
const uint32_t kMaxPreviewWidth = 1920;
const uint32_t kMaxPreviewHeight = 1080;
const uint32_t kMaxVideoWidth = 4096;
const uint32_t kMaxVideoHeight = 2160;
const int64_t kStreamBufferTimeoutSec = 3;
const int64_t kAutoFocusTimeoutSec = 5;
const int64_t kTorchTimeoutSec = 1;
const int64_t kEmptyFlushTimeoutMSec = 200;
const char kDumpOutput[] = "/dev/null";
struct AvailableStream {
int32_t width;
int32_t height;
int32_t format;
};
struct AvailableZSLInputOutput {
int32_t inputFormat;
int32_t outputFormat;
};
namespace {
// "device@<version>/legacy/<id>"
const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/legacy/(.+)";
const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
const char *kHAL3_2 = "3.2";
const char *kHAL1_0 = "1.0";
bool matchDeviceName(const hidl_string& deviceName, std::smatch& sm) {
std::regex e(kDeviceNameRE);
std::string deviceNameStd(deviceName.c_str());
return std::regex_match(deviceNameStd, sm, e);
}
int getCameraDeviceVersion(const hidl_string& deviceName) {
std::smatch sm;
bool match = matchDeviceName(deviceName, sm);
if (!match) {
return -1;
}
std::string version = sm[1].str();
if (version.compare(kHAL3_2) == 0) {
// maybe switched to 3.4 or define the hidl version enumlater
return CAMERA_DEVICE_API_VERSION_3_2;
} else if (version.compare(kHAL1_0) == 0) {
return CAMERA_DEVICE_API_VERSION_1_0;
}
return 0;
}
Status mapToStatus(::android::status_t s) {
switch(s) {
case ::android::OK:
return Status::OK ;
case ::android::BAD_VALUE:
return Status::ILLEGAL_ARGUMENT ;
case -EBUSY:
return Status::CAMERA_IN_USE;
case -EUSERS:
return Status::MAX_CAMERAS_IN_USE;
case ::android::UNKNOWN_TRANSACTION:
return Status::METHOD_NOT_SUPPORTED;
case ::android::INVALID_OPERATION:
return Status::OPERATION_NOT_SUPPORTED;
case ::android::DEAD_OBJECT:
return Status::CAMERA_DISCONNECTED;
}
ALOGW("Unexpected HAL status code %d", s);
return Status::OPERATION_NOT_SUPPORTED;
}
}
// Test environment for camera
class CameraHidlEnvironment : public ::testing::Environment {
public:
// get the test environment singleton
static CameraHidlEnvironment* Instance() {
static CameraHidlEnvironment* instance = new CameraHidlEnvironment;
return instance;
}
virtual void SetUp() override;
virtual void TearDown() override;
sp<ICameraProvider> mProvider;
private:
CameraHidlEnvironment() {}
GTEST_DISALLOW_COPY_AND_ASSIGN_(CameraHidlEnvironment);
};
void CameraHidlEnvironment::SetUp() {
mProvider = ::testing::VtsHalHidlTargetTestBase::getService<ICameraProvider>(kCameraLegacyServiceName);
ALOGI_IF(mProvider, "provider is not nullptr, %p", mProvider.get());
ASSERT_NE(mProvider, nullptr);
}
void CameraHidlEnvironment::TearDown() {
ALOGI("TearDown CameraHidlEnvironment");
}
struct BufferItemHander: public BufferItemConsumer::FrameAvailableListener {
BufferItemHander(wp<BufferItemConsumer> consumer) : mConsumer(consumer) {}
void onFrameAvailable(const android::BufferItem&) override {
sp<BufferItemConsumer> consumer = mConsumer.promote();
ASSERT_NE(nullptr, consumer.get());
android::BufferItem buffer;
ASSERT_EQ(android::OK, consumer->acquireBuffer(&buffer, 0));
ASSERT_EQ(android::OK, consumer->releaseBuffer(buffer));
}
private:
wp<BufferItemConsumer> mConsumer;
};
struct PreviewWindowCb : public ICameraDevicePreviewCallback {
PreviewWindowCb(sp<ANativeWindow> anw) : mPreviewWidth(0),
mPreviewHeight(0), mFormat(0), mPreviewUsage(0),
mPreviewSwapInterval(-1), mCrop{-1, -1, -1, -1}, mAnw(anw) {}
using dequeueBuffer_cb =
std::function<void(Status status, uint64_t bufferId,
const hidl_handle& buffer, uint32_t stride)>;
Return<void> dequeueBuffer(dequeueBuffer_cb _hidl_cb) override;
Return<Status> enqueueBuffer(uint64_t bufferId) override;
Return<Status> cancelBuffer(uint64_t bufferId) override;
Return<Status> setBufferCount(uint32_t count) override;
Return<Status> setBuffersGeometry(uint32_t w,
uint32_t h, PixelFormat format) override;
Return<Status> setCrop(int32_t left, int32_t top,
int32_t right, int32_t bottom) override;
Return<Status> setUsage(BufferUsage usage) override;
Return<Status> setSwapInterval(int32_t interval) override;
using getMinUndequeuedBufferCount_cb =
std::function<void(Status status, uint32_t count)>;
Return<void> getMinUndequeuedBufferCount(
getMinUndequeuedBufferCount_cb _hidl_cb) override;
Return<Status> setTimestamp(int64_t timestamp) override;
private:
struct BufferHasher {
size_t operator()(const buffer_handle_t& buf) const {
if (buf == nullptr)
return 0;
size_t result = 1;
result = 31 * result + buf->numFds;
result = 31 * result + buf->numInts;
int length = buf->numFds + buf->numInts;
for (int i = 0; i < length; i++) {
result = 31 * result + buf->data[i];
}
return result;
}
};
struct BufferComparator {
bool operator()(const buffer_handle_t& buf1,
const buffer_handle_t& buf2) const {
if ((buf1->numFds == buf2->numFds) &&
(buf1->numInts == buf2->numInts)) {
int length = buf1->numFds + buf1->numInts;
for (int i = 0; i < length; i++) {
if (buf1->data[i] != buf2->data[i]) {
return false;
}
}
return true;
}
return false;
}
};
std::pair<bool, uint64_t> getBufferId(ANativeWindowBuffer* anb);
void cleanupCirculatingBuffers();
std::mutex mBufferIdMapLock; // protecting mBufferIdMap and mNextBufferId
typedef std::unordered_map<const buffer_handle_t, uint64_t,
BufferHasher, BufferComparator> BufferIdMap;
BufferIdMap mBufferIdMap; // stream ID -> per stream buffer ID map
std::unordered_map<uint64_t, ANativeWindowBuffer*> mReversedBufMap;
uint64_t mNextBufferId = 1;
uint32_t mPreviewWidth, mPreviewHeight;
int mFormat, mPreviewUsage;
int32_t mPreviewSwapInterval;
android_native_rect_t mCrop;
sp<ANativeWindow> mAnw; //Native window reference
};
std::pair<bool, uint64_t> PreviewWindowCb::getBufferId(
ANativeWindowBuffer* anb) {
std::lock_guard<std::mutex> lock(mBufferIdMapLock);
buffer_handle_t& buf = anb->handle;
auto it = mBufferIdMap.find(buf);
if (it == mBufferIdMap.end()) {
uint64_t bufId = mNextBufferId++;
mBufferIdMap[buf] = bufId;
mReversedBufMap[bufId] = anb;
return std::make_pair(true, bufId);
} else {
return std::make_pair(false, it->second);
}
}
void PreviewWindowCb::cleanupCirculatingBuffers() {
std::lock_guard<std::mutex> lock(mBufferIdMapLock);
mBufferIdMap.clear();
mReversedBufMap.clear();
}
Return<void> PreviewWindowCb::dequeueBuffer(dequeueBuffer_cb _hidl_cb) {
ANativeWindowBuffer* anb;
auto rc = native_window_dequeue_buffer_and_wait(mAnw.get(), &anb);
uint64_t bufferId = 0;
uint32_t stride = 0;
hidl_handle buf = nullptr;
if (rc == ::android::OK) {
auto pair = getBufferId(anb);
buf = (pair.first) ? anb->handle : nullptr;
bufferId = pair.second;
stride = anb->stride;
}
_hidl_cb(mapToStatus(rc), bufferId, buf, stride);
return Void();
}
Return<Status> PreviewWindowCb::enqueueBuffer(uint64_t bufferId) {
if (mReversedBufMap.count(bufferId) == 0) {
ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId);
return Status::ILLEGAL_ARGUMENT;
}
return mapToStatus(mAnw->queueBuffer(mAnw.get(),
mReversedBufMap.at(bufferId), -1));
}
Return<Status> PreviewWindowCb::cancelBuffer(uint64_t bufferId) {
if (mReversedBufMap.count(bufferId) == 0) {
ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId);
return Status::ILLEGAL_ARGUMENT;
}
return mapToStatus(mAnw->cancelBuffer(mAnw.get(),
mReversedBufMap.at(bufferId), -1));
}
Return<Status> PreviewWindowCb::setBufferCount(uint32_t count) {
if (mAnw.get() != nullptr) {
// WAR for b/27039775
native_window_api_disconnect(mAnw.get(), NATIVE_WINDOW_API_CAMERA);
native_window_api_connect(mAnw.get(), NATIVE_WINDOW_API_CAMERA);
if (mPreviewWidth != 0) {
native_window_set_buffers_dimensions(mAnw.get(),
mPreviewWidth, mPreviewHeight);
native_window_set_buffers_format(mAnw.get(), mFormat);
}
if (mPreviewUsage != 0) {
native_window_set_usage(mAnw.get(), mPreviewUsage);
}
if (mPreviewSwapInterval >= 0) {
mAnw->setSwapInterval(mAnw.get(), mPreviewSwapInterval);
}
if (mCrop.left >= 0) {
native_window_set_crop(mAnw.get(), &(mCrop));
}
}
auto rc = native_window_set_buffer_count(mAnw.get(), count);
if (rc == ::android::OK) {
cleanupCirculatingBuffers();
}
return mapToStatus(rc);
}
Return<Status> PreviewWindowCb::setBuffersGeometry(uint32_t w, uint32_t h,
PixelFormat format) {
auto rc = native_window_set_buffers_dimensions(mAnw.get(), w, h);
if (rc == ::android::OK) {
mPreviewWidth = w;
mPreviewHeight = h;
rc = native_window_set_buffers_format(mAnw.get(),
static_cast<int>(format));
if (rc == ::android::OK) {
mFormat = static_cast<int>(format);
}
}
return mapToStatus(rc);
}
Return<Status> PreviewWindowCb::setCrop(int32_t left, int32_t top,
int32_t right, int32_t bottom) {
android_native_rect_t crop = { left, top, right, bottom };
auto rc = native_window_set_crop(mAnw.get(), &crop);
if (rc == ::android::OK) {
mCrop = crop;
}
return mapToStatus(rc);
}
Return<Status> PreviewWindowCb::setUsage(BufferUsage usage) {
auto rc = native_window_set_usage(mAnw.get(), static_cast<int>(usage));
if (rc == ::android::OK) {
mPreviewUsage = static_cast<int>(usage);
}
return mapToStatus(rc);
}
Return<Status> PreviewWindowCb::setSwapInterval(int32_t interval) {
auto rc = mAnw->setSwapInterval(mAnw.get(), interval);
if (rc == ::android::OK) {
mPreviewSwapInterval = interval;
}
return mapToStatus(rc);
}
Return<void> PreviewWindowCb::getMinUndequeuedBufferCount(
getMinUndequeuedBufferCount_cb _hidl_cb) {
int count = 0;
auto rc = mAnw->query(mAnw.get(),
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &count);
_hidl_cb(mapToStatus(rc), count);
return Void();
}
Return<Status> PreviewWindowCb::setTimestamp(int64_t timestamp) {
return mapToStatus(native_window_set_buffers_timestamp(mAnw.get(),
timestamp));
}
// The main test class for camera HIDL HAL.
class CameraHidlTest : public ::testing::VtsHalHidlTargetTestBase {
public:
virtual void SetUp() override {}
virtual void TearDown() override {}
hidl_vec<hidl_string> getCameraDeviceNames();
struct EmptyDeviceCb : public ICameraDeviceCallback {
virtual Return<void> processCaptureResult(const hidl_vec<CaptureResult>& /*results*/) override {
ALOGI("processCaptureResult callback");
ADD_FAILURE(); // Empty callback should not reach here
return Void();
}
virtual Return<void> notify(const hidl_vec<NotifyMsg>& /*msgs*/) override {
ALOGI("notify callback");
ADD_FAILURE(); // Empty callback should not reach here
return Void();
}
};
struct DeviceCb : public ICameraDeviceCallback {
DeviceCb(CameraHidlTest *parent) : mParent(parent) {}
Return<void> processCaptureResult(const hidl_vec<CaptureResult>& results) override;
Return<void> notify(const hidl_vec<NotifyMsg>& msgs) override;
private:
CameraHidlTest *mParent; // Parent object
};
struct TorchProviderCb : public ICameraProviderCallback {
TorchProviderCb(CameraHidlTest *parent) : mParent(parent) {}
virtual Return<void> cameraDeviceStatusChange(
const hidl_string&, CameraDeviceStatus) override {
return Void();
}
virtual Return<void> torchModeStatusChange(
const hidl_string&, TorchModeStatus newStatus) override {
std::lock_guard<std::mutex> l(mParent->mTorchLock);
mParent->mTorchStatus = newStatus;
mParent->mTorchCond.notify_one();
return Void();
}
private:
CameraHidlTest *mParent; // Parent object
};
struct Camera1DeviceCb :
public ::android::hardware::camera::device::V1_0::ICameraDeviceCallback {
Camera1DeviceCb(CameraHidlTest *parent) : mParent(parent) {}
Return<void> notifyCallback(NotifyCallbackMsg msgType,
int32_t ext1, int32_t ext2) override;
Return<uint32_t> registerMemory(const hidl_handle& descriptor,
uint32_t bufferSize, uint32_t bufferCount) override;
Return<void> unregisterMemory(uint32_t memId) override;
Return<void> dataCallback(DataCallbackMsg msgType,
uint32_t data, uint32_t bufferIndex,
const CameraFrameMetadata& metadata) override;
Return<void> dataCallbackTimestamp(DataCallbackMsg msgType,
uint32_t data, uint32_t bufferIndex,
int64_t timestamp) override;
Return<void> handleCallbackTimestamp(DataCallbackMsg msgType,
const hidl_handle& frameData,uint32_t data,
uint32_t bufferIndex, int64_t timestamp) override;
Return<void> handleCallbackTimestampBatch(DataCallbackMsg msgType,
const ::android::hardware::hidl_vec<HandleTimestampMessage>& batch) override;
private:
CameraHidlTest *mParent; // Parent object
};
void openCameraDevice(const std::string &name,const CameraHidlEnvironment* env,
sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device /*out*/);
void setupPreviewWindow(
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
sp<BufferItemConsumer> *bufferItemConsumer /*out*/,
sp<BufferItemHander> *bufferHandler /*out*/);
void stopPreviewAndClose(
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
void startPreview(
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
void enableMsgType(unsigned int msgType,
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
void disableMsgType(unsigned int msgType,
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device);
void getParameters(
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
CameraParameters *cameraParams /*out*/);
void setParameters(
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
const CameraParameters &cameraParams);
void waitForFrameLocked(DataCallbackMsg msgFrame,
std::unique_lock<std::mutex> &l);
void openEmptyDeviceSession(const std::string &name,
const CameraHidlEnvironment* env,
sp<ICameraDeviceSession> *session /*out*/,
camera_metadata_t **staticMeta /*out*/);
void configurePreviewStream(const std::string &name,
const CameraHidlEnvironment* env,
const AvailableStream *previewThreshold,
sp<ICameraDeviceSession> *session /*out*/,
Stream *previewStream /*out*/,
HalStreamConfiguration *halStreamConfig /*out*/);
static Status getAvailableOutputStreams(camera_metadata_t *staticMeta,
std::vector<AvailableStream> &outputStreams,
const AvailableStream *threshold = nullptr);
static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
AvailableStream &hfrStream);
static Status isZSLModeAvailable(camera_metadata_t *staticMeta);
static Status getZSLInputOutputMap(camera_metadata_t *staticMeta,
std::vector<AvailableZSLInputOutput> &inputOutputMap);
static Status findLargestSize(
const std::vector<AvailableStream> &streamSizes,
int32_t format, AvailableStream &result);
static Status isAutoFocusModeAvailable(
::android::CameraParameters &cameraParams, const char *mode) ;
protected:
std::mutex mLock; // Synchronize access to member variables
std::condition_variable mResultCondition; // Condition variable for incoming results
uint32_t mResultFrameNumber; // Expected result frame number
std::vector<StreamBuffer> mResultBuffers; // Holds stream buffers from capture result
std::vector<ErrorMsg> mErrors; // Holds incoming error notifications
DataCallbackMsg mDataMessageTypeReceived; // Most recent message type received through data callbacks
uint32_t mVideoBufferIndex; // Buffer index of the most recent video buffer
uint32_t mVideoData; // Buffer data of the most recent video buffer
hidl_handle mVideoNativeHandle; // Most recent video buffer native handle
NotifyCallbackMsg mNotifyMessage; // Current notification message
std::mutex mTorchLock; // Synchronize access to torch status
std::condition_variable mTorchCond; // Condition variable for torch status
TorchModeStatus mTorchStatus; // Current torch status
// Holds camera registered buffers
std::unordered_map<uint32_t, sp<::android::MemoryHeapBase> > mMemoryPool;
};
Return<void> CameraHidlTest::Camera1DeviceCb::notifyCallback(
NotifyCallbackMsg msgType, int32_t ext1 __unused,
int32_t ext2 __unused) {
std::unique_lock<std::mutex> l(mParent->mLock);
mParent->mNotifyMessage = msgType;
mParent->mResultCondition.notify_one();
return Void();
}
Return<uint32_t> CameraHidlTest::Camera1DeviceCb::registerMemory(
const hidl_handle& descriptor, uint32_t bufferSize,
uint32_t bufferCount) {
if (descriptor->numFds != 1) {
ADD_FAILURE() << "camera memory descriptor has"
" numFds " << descriptor->numFds << " (expect 1)" ;
return 0;
}
if (descriptor->data[0] < 0) {
ADD_FAILURE() << "camera memory descriptor has"
" FD " << descriptor->data[0] << " (expect >= 0)";
return 0;
}
sp<::android::MemoryHeapBase> pool = new ::android::MemoryHeapBase(
descriptor->data[0], bufferSize*bufferCount, 0, 0);
mParent->mMemoryPool.emplace(pool->getHeapID(), pool);
return pool->getHeapID();
}
Return<void> CameraHidlTest::Camera1DeviceCb::unregisterMemory(uint32_t memId) {
if (mParent->mMemoryPool.count(memId) == 0) {
ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId);
ADD_FAILURE();
return Void();
}
mParent->mMemoryPool.erase(memId);
return Void();
}
Return<void> CameraHidlTest::Camera1DeviceCb::dataCallback(
DataCallbackMsg msgType __unused, uint32_t data __unused,
uint32_t bufferIndex __unused,
const CameraFrameMetadata& metadata __unused) {
std::unique_lock<std::mutex> l(mParent->mLock);
mParent->mDataMessageTypeReceived = msgType;
mParent->mResultCondition.notify_one();
return Void();
}
Return<void> CameraHidlTest::Camera1DeviceCb::dataCallbackTimestamp(
DataCallbackMsg msgType, uint32_t data,
uint32_t bufferIndex, int64_t timestamp __unused) {
std::unique_lock<std::mutex> l(mParent->mLock);
mParent->mDataMessageTypeReceived = msgType;
mParent->mVideoBufferIndex = bufferIndex;
if (mParent->mMemoryPool.count(data) == 0) {
ADD_FAILURE() << "memory pool ID " << data << "not found";
}
mParent->mVideoData = data;
mParent->mResultCondition.notify_one();
return Void();
}
Return<void> CameraHidlTest::Camera1DeviceCb::handleCallbackTimestamp(
DataCallbackMsg msgType, const hidl_handle& frameData,
uint32_t data __unused, uint32_t bufferIndex,
int64_t timestamp __unused) {
std::unique_lock<std::mutex> l(mParent->mLock);
mParent->mDataMessageTypeReceived = msgType;
mParent->mVideoBufferIndex = bufferIndex;
if (mParent->mMemoryPool.count(data) == 0) {
ADD_FAILURE() << "memory pool ID " << data << " not found";
}
mParent->mVideoData = data;
mParent->mVideoNativeHandle = frameData;
mParent->mResultCondition.notify_one();
return Void();
}
Return<void> CameraHidlTest::Camera1DeviceCb::handleCallbackTimestampBatch(
DataCallbackMsg msgType,
const hidl_vec<HandleTimestampMessage>& batch) {
std::unique_lock<std::mutex> l(mParent->mLock);
for (auto& msg : batch) {
mParent->mDataMessageTypeReceived = msgType;
mParent->mVideoBufferIndex = msg.bufferIndex;
if (mParent->mMemoryPool.count(msg.data) == 0) {
ADD_FAILURE() << "memory pool ID " << msg.data << " not found";
}
mParent->mVideoData = msg.data;
mParent->mVideoNativeHandle = msg.frameData;
mParent->mResultCondition.notify_one();
}
return Void();
}
Return<void> CameraHidlTest::DeviceCb::processCaptureResult(
const hidl_vec<CaptureResult>& results) {
if (nullptr == mParent) {
return Void();
}
std::unique_lock<std::mutex> l(mParent->mLock);
const CaptureResult& result = results[0];
if(mParent->mResultFrameNumber != result.frameNumber) {
ALOGE("%s: Unexpected frame number! Expected: %u received: %u",
__func__, mParent->mResultFrameNumber, result.frameNumber);
ADD_FAILURE();
}
size_t resultLength = result.outputBuffers.size();
for (size_t i = 0; i < resultLength; i++) {
mParent->mResultBuffers.push_back(result.outputBuffers[i]);
}
// TODO(epeev): Handle partial results in case client supports them and
// verify the result against request settings.
l.unlock();
mParent->mResultCondition.notify_one();
return Void();
}
Return<void> CameraHidlTest::DeviceCb::notify(
const hidl_vec<NotifyMsg>& messages) {
const NotifyMsg& message = messages[0];
if (MsgType::ERROR == message.type) {
{
std::lock_guard<std::mutex> l(mParent->mLock);
mParent->mErrors.push_back(message.msg.error);
}
if ((ErrorCode::ERROR_REQUEST == message.msg.error.errorCode)
|| (ErrorCode::ERROR_BUFFER == message.msg.error.errorCode)) {
mParent->mResultCondition.notify_one();
}
}
return Void();
}
hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames() {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames;
Return<void> ret;
ret = env->mProvider->getCameraIdList(
[&](auto status, const auto& idList) {
ALOGI("getCameraIdList returns status:%d", (int)status);
for (size_t i = 0; i < idList.size(); i++) {
ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str());
}
ASSERT_EQ(Status::OK, status);
cameraDeviceNames = idList;
});
if (!ret.isOk()) {
ADD_FAILURE();
}
return cameraDeviceNames;
}
// Test if ICameraProvider::isTorchModeSupported returns Status::OK
TEST_F(CameraHidlTest, isTorchModeSupported) {
Return<void> ret;
ret = CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
[&](auto status, bool support) {
ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
(int)status, support);
ASSERT_EQ(Status::OK, status);
});
ASSERT_TRUE(ret.isOk());
}
// TODO: consider removing this test if getCameraDeviceNames() has the same coverage
TEST_F(CameraHidlTest, getCameraIdList) {
Return<void> ret;
ret = CameraHidlEnvironment::Instance()->mProvider->getCameraIdList(
[&](auto status, const auto& idList) {
ALOGI("getCameraIdList returns status:%d", (int)status);
for (size_t i = 0; i < idList.size(); i++) {
ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str());
}
ASSERT_EQ(Status::OK, status);
// This is true for internal camera provider.
// Not necessary hold for external cameras providers
ASSERT_GT(idList.size(), 0u);
});
ASSERT_TRUE(ret.isOk());
}
// Test if ICameraProvider::getVendorTags returns Status::OK
TEST_F(CameraHidlTest, getVendorTags) {
Return<void> ret;
ret = CameraHidlEnvironment::Instance()->mProvider->getVendorTags(
[&](auto status, const auto& vendorTagSecs) {
ALOGI("getVendorTags returns status:%d numSections %zu",
(int)status, vendorTagSecs.size());
for (size_t i = 0; i < vendorTagSecs.size(); i++) {
ALOGI("Vendor tag section %zu name %s",
i, vendorTagSecs[i].sectionName.c_str());
for (size_t j = 0; j < vendorTagSecs[i].tags.size(); j++) {
const auto& tag = vendorTagSecs[i].tags[j];
ALOGI("Vendor tag id %u name %s type %d",
tag.tagId,
tag.tagName.c_str(),
(int) tag.tagType);
}
}
ASSERT_EQ(Status::OK, status);
});
ASSERT_TRUE(ret.isOk());
}
// Test if ICameraProvider::setCallback returns Status::OK
TEST_F(CameraHidlTest, setCallback) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
struct ProviderCb : public ICameraProviderCallback {
virtual Return<void> cameraDeviceStatusChange(
const hidl_string& cameraDeviceName,
CameraDeviceStatus newStatus) override {
ALOGI("camera device status callback name %s, status %d",
cameraDeviceName.c_str(), (int) newStatus);
return Void();
}
virtual Return<void> torchModeStatusChange(
const hidl_string& cameraDeviceName,
TorchModeStatus newStatus) override {
ALOGI("Torch mode status callback name %s, status %d",
cameraDeviceName.c_str(), (int) newStatus);
return Void();
}
};
sp<ProviderCb> cb = new ProviderCb;
auto status = env->mProvider->setCallback(cb);
ASSERT_TRUE(status.isOk());
ASSERT_EQ(Status::OK, status);
}
// Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
TEST_F(CameraHidlTest, getCameraDeviceInterface) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
Return<void> ret;
ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device3_2) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device3_2, nullptr);
});
ASSERT_TRUE(ret.isOk());
} else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
Return<void> ret;
ret = env->mProvider->getCameraDeviceInterface_V1_x(
name,
[&](auto status, const auto& device1) {
ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device1, nullptr);
});
ASSERT_TRUE(ret.isOk());
}
}
}
// Verify that the device resource cost can be retrieved and the values are
// sane.
TEST_F(CameraHidlTest, getResourceCost) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
ALOGI("getResourceCost: Testing camera device %s", name.c_str());
Return<void> ret;
ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device3_2 = device;
});
ASSERT_TRUE(ret.isOk());
ret = device3_2->getResourceCost(
[&](auto status, const auto& resourceCost) {
ALOGI("getResourceCost returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ALOGI(" Resource cost is %d", resourceCost.resourceCost);
ASSERT_LE(resourceCost.resourceCost, 100u);
for (const auto& name : resourceCost.conflictingDevices) {
ALOGI(" Conflicting device: %s", name.c_str());
}
});
ASSERT_TRUE(ret.isOk());
} else {
::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
ALOGI("getResourceCost: Testing camera device %s", name.c_str());
Return<void> ret;
ret = env->mProvider->getCameraDeviceInterface_V1_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device1 = device;
});
ASSERT_TRUE(ret.isOk());
ret = device1->getResourceCost(
[&](auto status, const auto& resourceCost) {
ALOGI("getResourceCost returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ALOGI(" Resource cost is %d", resourceCost.resourceCost);
ASSERT_LE(resourceCost.resourceCost, 100u);
for (const auto& name : resourceCost.conflictingDevices) {
ALOGI(" Conflicting device: %s", name.c_str());
}
});
ASSERT_TRUE(ret.isOk());
}
}
}
// Verify that the static camera info can be retrieved
// successfully.
TEST_F(CameraHidlTest, getCameraInfo) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
Return<void> ret;
ret = env->mProvider->getCameraDeviceInterface_V1_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device1 = device;
});
ASSERT_TRUE(ret.isOk());
ret = device1->getCameraInfo(
[&](auto status, const auto& info) {
ALOGI("getCameraInfo returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
switch(info.orientation) {
case 0:
case 90:
case 180:
case 270:
//Expected cases
ALOGI("camera orientation: %d", info.orientation);
break;
default:
FAIL() << "Unexpected camera orientation:" << info.orientation;
}
switch(info.facing) {
case CameraFacing::BACK:
case CameraFacing::FRONT:
case CameraFacing::EXTERNAL:
//Expected cases
ALOGI("camera facing: %d", info.facing);
break;
default:
FAIL() << "Unexpected camera facing:" << static_cast<uint32_t> (info.facing);
}
});
ASSERT_TRUE(ret.isOk());
}
}
}
// Check whether preview window can be configured
TEST_F(CameraHidlTest, setPreviewWindow) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
sp<BufferItemConsumer> bufferItemConsumer;
sp<BufferItemHander> bufferHandler;
setupPreviewWindow(device1,
&bufferItemConsumer /*out*/, &bufferHandler /*out*/);
Return<void> ret;
ret = device1->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Verify that setting preview window fails in case device is not open
TEST_F(CameraHidlTest, setPreviewWindowInvalid) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
Return<void> ret;
ret = env->mProvider->getCameraDeviceInterface_V1_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device1 = device;
});
ASSERT_TRUE(ret.isOk());
Return<Status> returnStatus = device1->setPreviewWindow(nullptr);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OPERATION_NOT_SUPPORTED, returnStatus);
}
}
}
// Start and stop preview checking whether it gets enabled in between.
TEST_F(CameraHidlTest, startStopPreview) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
sp<BufferItemConsumer> bufferItemConsumer;
sp<BufferItemHander> bufferHandler;
setupPreviewWindow(device1,
&bufferItemConsumer /*out*/, &bufferHandler /*out*/);
startPreview(device1);
Return<bool> returnBoolStatus = device1->previewEnabled();
ASSERT_TRUE(returnBoolStatus.isOk());
ASSERT_TRUE(returnBoolStatus);
stopPreviewAndClose(device1);
}
}
}
// Start preview without active preview window. Preview should start as soon
// as a valid active window gets configured.
TEST_F(CameraHidlTest, startStopPreviewDelayed) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
Return<Status> returnStatus = device1->setPreviewWindow(nullptr);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
startPreview(device1);
sp<BufferItemConsumer> bufferItemConsumer;
sp<BufferItemHander> bufferHandler;
setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
&bufferHandler /*out*/);
//Preview should get enabled now
Return<bool> returnBoolStatus = device1->previewEnabled();
ASSERT_TRUE(returnBoolStatus.isOk());
ASSERT_TRUE(returnBoolStatus);
stopPreviewAndClose(device1);
}
}
}
// Verify that image capture behaves as expected along with preview callbacks.
TEST_F(CameraHidlTest, takePicture) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
sp<BufferItemConsumer> bufferItemConsumer;
sp<BufferItemHander> bufferHandler;
setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
&bufferHandler /*out*/);
{
std::unique_lock<std::mutex> l(mLock);
mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
}
enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
startPreview(device1);
{
std::unique_lock<std::mutex> l(mLock);
waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l);
}
disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME,
device1);
enableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE,
device1);
{
std::unique_lock<std::mutex> l(mLock);
mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
}
Return<Status> returnStatus = device1->takePicture();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
{
std::unique_lock<std::mutex> l(mLock);
waitForFrameLocked(DataCallbackMsg::COMPRESSED_IMAGE, l);
}
disableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE,
device1);
stopPreviewAndClose(device1);
}
}
}
// Image capture should fail in case preview didn't get enabled first.
TEST_F(CameraHidlTest, takePictureFail) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
Return<Status> returnStatus = device1->takePicture();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_NE(Status::OK, returnStatus);
Return<void> ret = device1->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Verify that image capture can be cancelled.
TEST_F(CameraHidlTest, cancelPicture) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
sp<BufferItemConsumer> bufferItemConsumer;
sp<BufferItemHander> bufferHandler;
setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
&bufferHandler /*out*/);
startPreview(device1);
Return<Status> returnStatus = device1->takePicture();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
returnStatus = device1->cancelPicture();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
stopPreviewAndClose(device1);
}
}
}
// Image capture cancel should fail when image capture is not running.
TEST_F(CameraHidlTest, cancelPictureFail) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
sp<BufferItemConsumer> bufferItemConsumer;
sp<BufferItemHander> bufferHandler;
setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
&bufferHandler /*out*/);
startPreview(device1);
Return<Status> returnStatus = device1->cancelPicture();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_NE(Status::OK, returnStatus);
stopPreviewAndClose(device1);
}
}
}
// Test basic video recording.
TEST_F(CameraHidlTest, startStopRecording) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
sp<BufferItemConsumer> bufferItemConsumer;
sp<BufferItemHander> bufferHandler;
setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
&bufferHandler /*out*/);
{
std::unique_lock<std::mutex> l(mLock);
mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
}
enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
startPreview(device1);
{
std::unique_lock<std::mutex> l(mLock);
waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l);
mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
mVideoBufferIndex = UINT32_MAX;
}
disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
bool videoMetaEnabled = false;
Return<Status> returnStatus = device1->storeMetaDataInBuffers(true);
ASSERT_TRUE(returnStatus.isOk());
// It is allowed for devices to not support this feature
ASSERT_TRUE((Status::OK == returnStatus) ||
(Status::OPERATION_NOT_SUPPORTED == returnStatus));
if (Status::OK == returnStatus) {
videoMetaEnabled = true;
}
enableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, device1);
Return<bool> returnBoolStatus = device1->recordingEnabled();
ASSERT_TRUE(returnBoolStatus.isOk());
ASSERT_FALSE(returnBoolStatus);
returnStatus = device1->startRecording();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
{
std::unique_lock<std::mutex> l(mLock);
waitForFrameLocked(DataCallbackMsg::VIDEO_FRAME, l);
ASSERT_NE(UINT32_MAX, mVideoBufferIndex);
disableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME,
device1);
}
returnBoolStatus = device1->recordingEnabled();
ASSERT_TRUE(returnBoolStatus.isOk());
ASSERT_TRUE(returnBoolStatus);
Return<void> ret;
if (videoMetaEnabled) {
ret = device1->releaseRecordingFrameHandle(mVideoData,
mVideoBufferIndex, mVideoNativeHandle);
ASSERT_TRUE(ret.isOk());
} else {
ret = device1->releaseRecordingFrame(mVideoData, mVideoBufferIndex);
ASSERT_TRUE(ret.isOk());
}
ret = device1->stopRecording();
ASSERT_TRUE(ret.isOk());
stopPreviewAndClose(device1);
}
}
}
// It shouldn't be possible to start recording without enabling preview first.
TEST_F(CameraHidlTest, startRecordingFail) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
Return<bool> returnBoolStatus = device1->recordingEnabled();
ASSERT_TRUE(returnBoolStatus.isOk());
ASSERT_FALSE(returnBoolStatus);
Return<Status> returnStatus = device1->startRecording();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_NE(Status::OK, returnStatus);
Return<void> ret = device1->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Check autofocus support if available.
TEST_F(CameraHidlTest, autoFocus) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<const char *> focusModes = {CameraParameters::FOCUS_MODE_AUTO,
CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE,
CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO};
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
::android::CameraParameters cameraParams;
getParameters(device1, &cameraParams /*out*/);
if (Status::OK != isAutoFocusModeAvailable(cameraParams,
CameraParameters::FOCUS_MODE_AUTO)) {
Return<void> ret = device1->close();
ASSERT_TRUE(ret.isOk());
continue;
}
sp<BufferItemConsumer> bufferItemConsumer;
sp<BufferItemHander> bufferHandler;
setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
&bufferHandler /*out*/);
startPreview(device1);
enableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1);
for (auto &iter : focusModes) {
if (Status::OK != isAutoFocusModeAvailable(cameraParams,
iter)) {
continue;
}
cameraParams.set(CameraParameters::KEY_FOCUS_MODE, iter);
setParameters(device1, cameraParams);
{
std::unique_lock<std::mutex> l(mLock);
mNotifyMessage = NotifyCallbackMsg::ERROR;
}
Return<Status> returnStatus = device1->autoFocus();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
{
std::unique_lock<std::mutex> l(mLock);
while (NotifyCallbackMsg::FOCUS != mNotifyMessage) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(kAutoFocusTimeoutSec);
ASSERT_NE(std::cv_status::timeout,
mResultCondition.wait_until(l, timeout));
}
}
}
disableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1);
stopPreviewAndClose(device1);
}
}
}
// In case autofocus is supported verify that it can be cancelled.
TEST_F(CameraHidlTest, cancelAutoFocus) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
::android::CameraParameters cameraParams;
getParameters(device1, &cameraParams /*out*/);
if (Status::OK != isAutoFocusModeAvailable(cameraParams,
CameraParameters::FOCUS_MODE_AUTO)) {
Return<void> ret = device1->close();
ASSERT_TRUE(ret.isOk());
continue;
}
// It should be fine to call before preview starts.
ASSERT_EQ(Status::OK, device1->cancelAutoFocus());
sp<BufferItemConsumer> bufferItemConsumer;
sp<BufferItemHander> bufferHandler;
setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
&bufferHandler /*out*/);
startPreview(device1);
// It should be fine to call after preview starts too.
Return<Status> returnStatus = device1->cancelAutoFocus();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
returnStatus = device1->autoFocus();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
returnStatus = device1->cancelAutoFocus();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
stopPreviewAndClose(device1);
}
}
}
// Check whether face detection is available and try to enable&disable.
TEST_F(CameraHidlTest, sendCommandFaceDetection) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
::android::CameraParameters cameraParams;
getParameters(device1, &cameraParams /*out*/);
int32_t hwFaces = cameraParams.getInt(
CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW);
int32_t swFaces = cameraParams.getInt(
CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW);
if ((0 >= hwFaces) && (0 >= swFaces)) {
Return<void> ret = device1->close();
ASSERT_TRUE(ret.isOk());
continue;
}
sp<BufferItemConsumer> bufferItemConsumer;
sp<BufferItemHander> bufferHandler;
setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
&bufferHandler /*out*/);
startPreview(device1);
if (0 < hwFaces) {
Return<Status> returnStatus = device1->sendCommand(
CommandType::START_FACE_DETECTION,
CAMERA_FACE_DETECTION_HW, 0);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
// TODO(epeev) : Enable and check for face notifications
returnStatus = device1->sendCommand(
CommandType::STOP_FACE_DETECTION,
CAMERA_FACE_DETECTION_HW, 0);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
}
if (0 < swFaces) {
Return<Status> returnStatus = device1->sendCommand(
CommandType::START_FACE_DETECTION,
CAMERA_FACE_DETECTION_SW, 0);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
// TODO(epeev) : Enable and check for face notifications
returnStatus = device1->sendCommand(
CommandType::STOP_FACE_DETECTION,
CAMERA_FACE_DETECTION_SW, 0);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
}
stopPreviewAndClose(device1);
}
}
}
// Check whether smooth zoom is available and try to enable&disable.
TEST_F(CameraHidlTest, sendCommandSmoothZoom) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
::android::CameraParameters cameraParams;
getParameters(device1, &cameraParams /*out*/);
const char *smoothZoomStr = cameraParams.get(
CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED);
bool smoothZoomSupported = ((nullptr != smoothZoomStr) &&
(strcmp(smoothZoomStr, CameraParameters::TRUE) == 0)) ?
true : false;
if (!smoothZoomSupported) {
Return<void> ret = device1->close();
ASSERT_TRUE(ret.isOk());
continue;
}
int32_t maxZoom = cameraParams.getInt(
CameraParameters::KEY_MAX_ZOOM);
ASSERT_TRUE(0 < maxZoom);
sp<BufferItemConsumer> bufferItemConsumer;
sp<BufferItemHander> bufferHandler;
setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
&bufferHandler /*out*/);
startPreview(device1);
setParameters(device1, cameraParams);
Return<Status> returnStatus = device1->sendCommand(
CommandType::START_SMOOTH_ZOOM, maxZoom, 0);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
// TODO(epeev) : Enable and check for face notifications
returnStatus = device1->sendCommand(CommandType::STOP_SMOOTH_ZOOM,
0, 0);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
stopPreviewAndClose(device1);
}
}
}
// Basic sanity tests related to camera parameters.
TEST_F(CameraHidlTest, getSetParameters) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
::android::CameraParameters cameraParams;
getParameters(device1, &cameraParams /*out*/);
int32_t width, height;
cameraParams.getPictureSize(&width, &height);
ASSERT_TRUE((0 < width) && (0 < height));
cameraParams.getPreviewSize(&width, &height);
ASSERT_TRUE((0 < width) && (0 < height));
int32_t minFps, maxFps;
cameraParams.getPreviewFpsRange(&minFps, &maxFps);
ASSERT_TRUE((0 < minFps) && (0 < maxFps));
ASSERT_NE(nullptr, cameraParams.getPreviewFormat());
ASSERT_NE(nullptr, cameraParams.getPictureFormat());
ASSERT_TRUE(strcmp(CameraParameters::PIXEL_FORMAT_JPEG,
cameraParams.getPictureFormat()) == 0);
const char *flashMode = cameraParams.get(
CameraParameters::KEY_FLASH_MODE);
ASSERT_TRUE((nullptr == flashMode) || (strcmp(
CameraParameters::FLASH_MODE_OFF, flashMode) == 0));
const char *wbMode = cameraParams.get(
CameraParameters::KEY_WHITE_BALANCE);
ASSERT_TRUE((nullptr == wbMode) || (strcmp(
CameraParameters::WHITE_BALANCE_AUTO, wbMode) == 0));
const char *effect = cameraParams.get(CameraParameters::KEY_EFFECT);
ASSERT_TRUE((nullptr == effect) || (strcmp(
CameraParameters::EFFECT_NONE, effect) == 0));
::android::Vector<::android::Size> previewSizes;
cameraParams.getSupportedPreviewSizes(previewSizes);
ASSERT_FALSE(previewSizes.empty());
::android::Vector<::android::Size> pictureSizes;
cameraParams.getSupportedPictureSizes(pictureSizes);
ASSERT_FALSE(pictureSizes.empty());
const char *previewFormats = cameraParams.get(
CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
ASSERT_NE(nullptr, previewFormats);
::android::String8 previewFormatsString(previewFormats);
ASSERT_TRUE(previewFormatsString.contains(
CameraParameters::PIXEL_FORMAT_YUV420SP));
ASSERT_NE(nullptr, cameraParams.get(
CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS));
ASSERT_NE(nullptr, cameraParams.get(
CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES));
const char *focusModes = cameraParams.get(
CameraParameters::KEY_SUPPORTED_FOCUS_MODES);
ASSERT_NE(nullptr, focusModes);
::android::String8 focusModesString(focusModes);
const char *focusMode = cameraParams.get(
CameraParameters::KEY_FOCUS_MODE);
ASSERT_NE(nullptr, focusMode);
// Auto focus mode should be default
if (focusModesString.contains(CameraParameters::FOCUS_MODE_AUTO)) {
ASSERT_TRUE(strcmp(
CameraParameters::FOCUS_MODE_AUTO, focusMode) == 0);
}
ASSERT_TRUE(0 < cameraParams.getInt(
CameraParameters::KEY_FOCAL_LENGTH));
int32_t horizontalViewAngle = cameraParams.getInt(
CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE);
ASSERT_TRUE((0 < horizontalViewAngle) && (360 >= horizontalViewAngle));
int32_t verticalViewAngle = cameraParams.getInt(
CameraParameters::KEY_VERTICAL_VIEW_ANGLE);
ASSERT_TRUE((0 < verticalViewAngle) && (360 >= verticalViewAngle));
int32_t jpegQuality = cameraParams.getInt(
CameraParameters::KEY_JPEG_QUALITY);
ASSERT_TRUE((1 <= jpegQuality) && (100 >= jpegQuality));
int32_t jpegThumbQuality = cameraParams.getInt(
CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY);
ASSERT_TRUE((1 <= jpegThumbQuality) && (100 >= jpegThumbQuality));
cameraParams.setPictureSize(pictureSizes[0].width,
pictureSizes[0].height);
cameraParams.setPreviewSize(previewSizes[0].width,
previewSizes[0].height);
setParameters(device1, cameraParams);
getParameters(device1, &cameraParams /*out*/);
cameraParams.getPictureSize(&width, &height);
ASSERT_TRUE((pictureSizes[0].width == width) &&
(pictureSizes[0].height == height));
cameraParams.getPreviewSize(&width, &height);
ASSERT_TRUE((previewSizes[0].width == width) &&
(previewSizes[0].height == height));
Return<void> ret = device1->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Verify that the static camera characteristics can be retrieved
// successfully.
TEST_F(CameraHidlTest, getCameraCharacteristics) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
Return<void> ret;
ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device3_2 = device;
});
ASSERT_TRUE(ret.isOk());
ret = device3_2->getCameraCharacteristics(
[&](auto status, const auto& chars) {
ALOGI("getCameraCharacteristics returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
const camera_metadata_t* metadata = (camera_metadata_t*) chars.data();
size_t expectedSize = chars.size();
ASSERT_EQ(0, validate_camera_metadata_structure(metadata, &expectedSize));
size_t entryCount = get_camera_metadata_entry_count(metadata);
// TODO: we can do better than 0 here. Need to check how many required
// characteristics keys we've defined.
ASSERT_GT(entryCount, 0u);
ALOGI("getCameraCharacteristics metadata entry count is %zu", entryCount);
});
ASSERT_TRUE(ret.isOk());
}
}
}
//In case it is supported verify that torch can be enabled.
//Check for corresponding toch callbacks as well.
TEST_F(CameraHidlTest, setTorchMode) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
bool torchControlSupported = false;
Return<void> ret;
ret = CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
[&](auto status, bool support) {
ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
(int)status, support);
ASSERT_EQ(Status::OK, status);
torchControlSupported = support;
});
sp<TorchProviderCb> cb = new TorchProviderCb(this);
Return<Status> returnStatus = env->mProvider->setCallback(cb);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
ALOGI("setTorchMode: Testing camera device %s", name.c_str());
ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device3_2 = device;
});
ASSERT_TRUE(ret.isOk());
mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
returnStatus = device3_2->setTorchMode(TorchMode::ON);
ASSERT_TRUE(returnStatus.isOk());
if (!torchControlSupported) {
ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
} else {
ASSERT_TRUE(returnStatus == Status::OK ||
returnStatus == Status::OPERATION_NOT_SUPPORTED);
if (returnStatus == Status::OK) {
{
std::unique_lock<std::mutex> l(mTorchLock);
while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(kTorchTimeoutSec);
ASSERT_NE(std::cv_status::timeout,
mTorchCond.wait_until(l, timeout));
}
ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
}
returnStatus = device3_2->setTorchMode(TorchMode::OFF);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
{
std::unique_lock<std::mutex> l(mTorchLock);
while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(kTorchTimeoutSec);
ASSERT_NE(std::cv_status::timeout,
mTorchCond.wait_until(l, timeout));
}
ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
}
}
}
} else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
ALOGI("dumpState: Testing camera device %s", name.c_str());
ret = env->mProvider->getCameraDeviceInterface_V1_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device1 = device;
});
ASSERT_TRUE(ret.isOk());
mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
returnStatus = device1->setTorchMode(TorchMode::ON);
ASSERT_TRUE(returnStatus.isOk());
if (!torchControlSupported) {
ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
} else {
ASSERT_TRUE(returnStatus == Status::OK ||
returnStatus == Status::OPERATION_NOT_SUPPORTED);
if (returnStatus == Status::OK) {
{
std::unique_lock<std::mutex> l(mTorchLock);
while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(kTorchTimeoutSec);
ASSERT_NE(std::cv_status::timeout,
mTorchCond.wait_until(l, timeout));
}
ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
}
returnStatus = device1->setTorchMode(TorchMode::OFF);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
{
std::unique_lock<std::mutex> l(mTorchLock);
while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(kTorchTimeoutSec);
ASSERT_NE(std::cv_status::timeout,
mTorchCond.wait_until(l, timeout));
}
ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
}
}
}
ret = device1->close();
ASSERT_TRUE(ret.isOk());
}
}
returnStatus = env->mProvider->setCallback(nullptr);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
}
// Check dump functionality.
TEST_F(CameraHidlTest, dumpState) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
Return<void> ret;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
ALOGI("dumpState: Testing camera device %s", name.c_str());
ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device3_2 = device;
});
ASSERT_TRUE(ret.isOk());
native_handle_t* raw_handle = native_handle_create(1, 0);
raw_handle->data[0] = open(kDumpOutput, O_RDWR);
ASSERT_GE(raw_handle->data[0], 0);
hidl_handle handle = raw_handle;
ret= device3_2->dumpState(handle);
ASSERT_TRUE(ret.isOk());
close(raw_handle->data[0]);
native_handle_delete(raw_handle);
} else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
ALOGI("dumpState: Testing camera device %s", name.c_str());
ret = env->mProvider->getCameraDeviceInterface_V1_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device1 = device;
});
ASSERT_TRUE(ret.isOk());
native_handle_t* raw_handle = native_handle_create(1, 0);
raw_handle->data[0] = open(kDumpOutput, O_RDWR);
ASSERT_GE(raw_handle->data[0], 0);
hidl_handle handle = raw_handle;
Return<Status> returnStatus = device1->dumpState(handle);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
close(raw_handle->data[0]);
native_handle_delete(raw_handle);
}
}
}
// Open, dumpStates, then close
TEST_F(CameraHidlTest, openClose) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
Return<void> ret;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
ALOGI("openClose: Testing camera device %s", name.c_str());
ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device3_2 = device;
});
ASSERT_TRUE(ret.isOk());
sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
sp<ICameraDeviceSession> session;
ret = device3_2->open(
cb,
[&](auto status, const auto& newSession) {
ALOGI("device::open returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(newSession, nullptr);
session = newSession;
});
ASSERT_TRUE(ret.isOk());
native_handle_t* raw_handle = native_handle_create(1, 0);
raw_handle->data[0] = open(kDumpOutput, O_RDWR);
ASSERT_GE(raw_handle->data[0], 0);
hidl_handle handle = raw_handle;
ret = device3_2->dumpState(handle);
ASSERT_TRUE(ret.isOk());
close(raw_handle->data[0]);
native_handle_delete(raw_handle);
ret = session->close();
ASSERT_TRUE(ret.isOk());
// TODO: test all session API calls return INTERNAL_ERROR after close
// TODO: keep a wp copy here and verify session cannot be promoted out of this scope
} else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
openCameraDevice(name, env, &device1 /*out*/);
ASSERT_NE(nullptr, device1.get());
native_handle_t* raw_handle = native_handle_create(1, 0);
raw_handle->data[0] = open(kDumpOutput, O_RDWR);
ASSERT_GE(raw_handle->data[0], 0);
hidl_handle handle = raw_handle;
Return<Status> returnStatus = device1->dumpState(handle);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
close(raw_handle->data[0]);
native_handle_delete(raw_handle);
ret = device1->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Check whether all common default request settings can be sucessfully
// constructed.
TEST_F(CameraHidlTest, constructDefaultRequestSettings) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
Return<void> ret;
ALOGI("constructDefaultRequestSettings: Testing camera device %s", name.c_str());
ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device3_2 = device;
});
ASSERT_TRUE(ret.isOk());
sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
sp<ICameraDeviceSession> session;
ret = device3_2->open(
cb,
[&](auto status, const auto& newSession) {
ALOGI("device::open returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(newSession, nullptr);
session = newSession;
});
ASSERT_TRUE(ret.isOk());
for (uint32_t t = (uint32_t) RequestTemplate::PREVIEW;
t <= (uint32_t) RequestTemplate::MANUAL; t++) {
RequestTemplate reqTemplate = (RequestTemplate) t;
ret = session->constructDefaultRequestSettings(
reqTemplate,
[&](auto status, const auto& req) {
ALOGI("constructDefaultRequestSettings returns status:%d", (int)status);
if (reqTemplate == RequestTemplate::ZERO_SHUTTER_LAG ||
reqTemplate == RequestTemplate::MANUAL) {
// optional templates
ASSERT_TRUE(status == Status::OK || status == Status::ILLEGAL_ARGUMENT);
} else {
ASSERT_EQ(Status::OK, status);
}
if (status == Status::OK) {
const camera_metadata_t* metadata =
(camera_metadata_t*) req.data();
size_t expectedSize = req.size();
ASSERT_EQ(0, validate_camera_metadata_structure(
metadata, &expectedSize));
size_t entryCount = get_camera_metadata_entry_count(metadata);
// TODO: we can do better than 0 here. Need to check how many required
// request keys we've defined for each template
ASSERT_GT(entryCount, 0u);
ALOGI("template %u metadata entry count is %zu", t, entryCount);
} else {
ASSERT_EQ(0u, req.size());
}
});
ASSERT_TRUE(ret.isOk());
}
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Verify that all supported stream formats and sizes can be configured
// successfully.
TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputStreams;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
camera_metadata_t *staticMeta;
Return<void> ret;
sp<ICameraDeviceSession> session;
openEmptyDeviceSession(name, env, &session /*out*/,
&staticMeta /*out*/);
outputStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
outputStreams));
ASSERT_NE(0u, outputStreams.size());
int32_t streamId = 0;
for (auto &it : outputStreams) {
Stream stream = {streamId, StreamType::OUTPUT,
static_cast<uint32_t> (it.width),
static_cast<uint32_t> (it.height),
static_cast<PixelFormat> (it.format), 0, 0,
StreamRotation::ROTATION_0};
::android::hardware::hidl_vec<Stream> streams = {stream};
StreamConfiguration config = {streams,
StreamConfigurationMode::NORMAL_MODE};
ret = session->configureStreams(config, [streamId] (Status s,
HalStreamConfiguration halConfig) {
ASSERT_EQ(Status::OK, s);
ASSERT_EQ(1u, halConfig.streams.size());
ASSERT_EQ(halConfig.streams[0].id, streamId);
});
ASSERT_TRUE(ret.isOk());
streamId++;
}
free_camera_metadata(staticMeta);
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Check for correct handling of invalid/incorrect configuration parameters.
TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputStreams;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
camera_metadata_t *staticMeta;
Return<void> ret;
sp<ICameraDeviceSession> session;
openEmptyDeviceSession(name, env, &session /*out*/,
&staticMeta /*out*/);
outputStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
outputStreams));
ASSERT_NE(0u, outputStreams.size());
int32_t streamId = 0;
Stream stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (0),
static_cast<uint32_t> (0),
static_cast<PixelFormat> (outputStreams[0].format),
0, 0, StreamRotation::ROTATION_0};
::android::hardware::hidl_vec<Stream> streams = {stream};
StreamConfiguration config = {streams,
StreamConfigurationMode::NORMAL_MODE};
ret = session->configureStreams(config, [] (Status s,
HalStreamConfiguration) {
ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
(Status::INTERNAL_ERROR == s));
});
ASSERT_TRUE(ret.isOk());
stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (UINT32_MAX),
static_cast<uint32_t> (UINT32_MAX),
static_cast<PixelFormat> (outputStreams[0].format),
0, 0, StreamRotation::ROTATION_0};
streams[0] = stream;
config = {streams,
StreamConfigurationMode::NORMAL_MODE};
ret = session->configureStreams(config, [] (Status s,
HalStreamConfiguration) {
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
});
ASSERT_TRUE(ret.isOk());
for (auto &it : outputStreams) {
stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (it.width),
static_cast<uint32_t> (it.height),
static_cast<PixelFormat> (UINT32_MAX),
0, 0, StreamRotation::ROTATION_0};
streams[0] = stream;
config = {streams,
StreamConfigurationMode::NORMAL_MODE};
ret = session->configureStreams(config, [] (Status s,
HalStreamConfiguration) {
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
});
ASSERT_TRUE(ret.isOk());
stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (it.width),
static_cast<uint32_t> (it.height),
static_cast<PixelFormat> (it.format),
0, 0, static_cast<StreamRotation> (UINT32_MAX)};
streams[0] = stream;
config = {streams,
StreamConfigurationMode::NORMAL_MODE};
ret = session->configureStreams(config, [] (Status s,
HalStreamConfiguration) {
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
});
ASSERT_TRUE(ret.isOk());
}
free_camera_metadata(staticMeta);
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Check whether all supported ZSL output stream combinations can be
// configured successfully.
TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> inputStreams;
std::vector<AvailableZSLInputOutput> inputOutputMap;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
camera_metadata_t *staticMeta;
Return<void> ret;
sp<ICameraDeviceSession> session;
openEmptyDeviceSession(name, env, &session /*out*/,
&staticMeta /*out*/);
Status rc = isZSLModeAvailable(staticMeta);
if (Status::METHOD_NOT_SUPPORTED == rc) {
ret = session->close();
ASSERT_TRUE(ret.isOk());
continue;
}
ASSERT_EQ(Status::OK, rc);
inputStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
inputStreams));
ASSERT_NE(0u, inputStreams.size());
inputOutputMap.clear();
ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta,
inputOutputMap));
ASSERT_NE(0u, inputOutputMap.size());
int32_t streamId = 0;
for (auto &inputIter : inputOutputMap) {
AvailableStream input;
ASSERT_EQ(Status::OK,
findLargestSize(inputStreams, inputIter.inputFormat, input));
ASSERT_NE(0u, inputStreams.size());
AvailableStream outputThreshold = {INT32_MAX, INT32_MAX,
inputIter.outputFormat};
std::vector<AvailableStream> outputStreams;
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
outputStreams, &outputThreshold));
for (auto &outputIter : outputStreams) {
Stream zslStream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (input.width),
static_cast<uint32_t> (input.height),
static_cast<PixelFormat> (input.format),
GRALLOC_USAGE_HW_CAMERA_ZSL, 0,
StreamRotation::ROTATION_0};
Stream inputStream = {streamId++, StreamType::INPUT,
static_cast<uint32_t> (input.width),
static_cast<uint32_t> (input.height),
static_cast<PixelFormat> (input.format), 0, 0,
StreamRotation::ROTATION_0};
Stream outputStream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (outputIter.width),
static_cast<uint32_t> (outputIter.height),
static_cast<PixelFormat> (outputIter.format), 0, 0,
StreamRotation::ROTATION_0};
::android::hardware::hidl_vec<Stream> streams = {
inputStream, zslStream, outputStream};
StreamConfiguration config = {streams,
StreamConfigurationMode::NORMAL_MODE};
ret = session->configureStreams(config,
[](Status s, HalStreamConfiguration halConfig) {
ASSERT_EQ(Status::OK, s);
ASSERT_EQ(3u, halConfig.streams.size());
});
ASSERT_TRUE(ret.isOk());
}
}
free_camera_metadata(staticMeta);
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Verify that all supported preview + still capture stream combinations
// can be configured successfully.
TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputBlobStreams;
std::vector<AvailableStream> outputPreviewStreams;
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
AvailableStream blobThreshold = {INT32_MAX, INT32_MAX,
static_cast<int32_t>(PixelFormat::BLOB)};
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
camera_metadata_t *staticMeta;
Return<void> ret;
sp<ICameraDeviceSession> session;
openEmptyDeviceSession(name, env, &session /*out*/,
&staticMeta /*out*/);
outputBlobStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
outputBlobStreams, &blobThreshold));
ASSERT_NE(0u, outputBlobStreams.size());
outputPreviewStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
outputPreviewStreams, &previewThreshold));
ASSERT_NE(0u, outputPreviewStreams.size());
int32_t streamId = 0;
for (auto &blobIter : outputBlobStreams) {
for (auto &previewIter : outputPreviewStreams) {
Stream previewStream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (previewIter.width),
static_cast<uint32_t> (previewIter.height),
static_cast<PixelFormat> (previewIter.format), 0, 0,
StreamRotation::ROTATION_0};
Stream blobStream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (blobIter.width),
static_cast<uint32_t> (blobIter.height),
static_cast<PixelFormat> (blobIter.format), 0, 0,
StreamRotation::ROTATION_0};
::android::hardware::hidl_vec<Stream> streams = {
previewStream, blobStream};
StreamConfiguration config = {streams,
StreamConfigurationMode::NORMAL_MODE};
ret = session->configureStreams(config,
[](Status s, HalStreamConfiguration halConfig) {
ASSERT_EQ(Status::OK, s);
ASSERT_EQ(2u, halConfig.streams.size());
});
ASSERT_TRUE(ret.isOk());
}
}
free_camera_metadata(staticMeta);
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// In case constrained mode is supported, test whether it can be
// configured. Additionally check for common invalid inputs when
// using this mode.
TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
camera_metadata_t *staticMeta;
Return<void> ret;
sp<ICameraDeviceSession> session;
openEmptyDeviceSession(name, env, &session /*out*/,
&staticMeta /*out*/);
Status rc = isConstrainedModeAvailable(staticMeta);
if (Status::METHOD_NOT_SUPPORTED == rc) {
ret = session->close();
ASSERT_TRUE(ret.isOk());
continue;
}
ASSERT_EQ(Status::OK, rc);
AvailableStream hfrStream;
rc = pickConstrainedModeSize(staticMeta, hfrStream);
ASSERT_EQ(Status::OK, rc);
int32_t streamId = 0;
Stream stream = {streamId, StreamType::OUTPUT,
static_cast<uint32_t> (hfrStream.width),
static_cast<uint32_t> (hfrStream.height),
static_cast<PixelFormat> (hfrStream.format), 0, 0,
StreamRotation::ROTATION_0};
::android::hardware::hidl_vec<Stream> streams = {stream};
StreamConfiguration config = {streams,
StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
ret = session->configureStreams(config, [streamId] (Status s,
HalStreamConfiguration halConfig) {
ASSERT_EQ(Status::OK, s);
ASSERT_EQ(1u, halConfig.streams.size());
ASSERT_EQ(halConfig.streams[0].id, streamId);
});
ASSERT_TRUE(ret.isOk());
stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (0),
static_cast<uint32_t> (0),
static_cast<PixelFormat> (hfrStream.format), 0, 0,
StreamRotation::ROTATION_0};
streams[0] = stream;
config = {streams,
StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
ret = session->configureStreams(config, [](Status s, HalStreamConfiguration) {
ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
(Status::INTERNAL_ERROR == s));
});
ASSERT_TRUE(ret.isOk());
stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (UINT32_MAX),
static_cast<uint32_t> (UINT32_MAX),
static_cast<PixelFormat> (hfrStream.format), 0, 0,
StreamRotation::ROTATION_0};
streams[0] = stream;
config = {streams,
StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
ret = session->configureStreams(config, [](Status s, HalStreamConfiguration) {
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
});
ASSERT_TRUE(ret.isOk());
stream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (hfrStream.width),
static_cast<uint32_t> (hfrStream.height),
static_cast<PixelFormat> (UINT32_MAX), 0, 0,
StreamRotation::ROTATION_0};
streams[0] = stream;
config = {streams,
StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
ret = session->configureStreams(config, [](Status s, HalStreamConfiguration) {
ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
});
ASSERT_TRUE(ret.isOk());
free_camera_metadata(staticMeta);
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Verify that all supported video + snapshot stream combinations can
// be configured successfully.
TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputBlobStreams;
std::vector<AvailableStream> outputVideoStreams;
AvailableStream videoThreshold = {kMaxVideoWidth, kMaxVideoHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
AvailableStream blobThreshold = {kMaxVideoWidth, kMaxVideoHeight,
static_cast<int32_t>(PixelFormat::BLOB)};
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
camera_metadata_t *staticMeta;
Return<void> ret;
sp<ICameraDeviceSession> session;
openEmptyDeviceSession(name, env, &session /*out*/,
&staticMeta /*out*/);
outputBlobStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
outputBlobStreams, &blobThreshold));
ASSERT_NE(0u, outputBlobStreams.size());
outputVideoStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
outputVideoStreams, &videoThreshold));
ASSERT_NE(0u, outputVideoStreams.size());
int32_t streamId = 0;
for (auto &blobIter : outputBlobStreams) {
for (auto &videoIter : outputVideoStreams) {
Stream videoStream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (videoIter.width),
static_cast<uint32_t> (videoIter.height),
static_cast<PixelFormat> (videoIter.format), 0, 0,
StreamRotation::ROTATION_0};
Stream blobStream = {streamId++, StreamType::OUTPUT,
static_cast<uint32_t> (blobIter.width),
static_cast<uint32_t> (blobIter.height),
static_cast<PixelFormat> (blobIter.format),
GRALLOC_USAGE_HW_VIDEO_ENCODER, 0,
StreamRotation::ROTATION_0};
::android::hardware::hidl_vec<Stream> streams = {
videoStream, blobStream};
StreamConfiguration config = {streams,
StreamConfigurationMode::NORMAL_MODE};
ret = session->configureStreams(config,
[](Status s, HalStreamConfiguration halConfig) {
ASSERT_EQ(Status::OK, s);
ASSERT_EQ(2u, halConfig.streams.size());
});
ASSERT_TRUE(ret.isOk());
}
}
free_camera_metadata(staticMeta);
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Generate and verify a camera capture request
TEST_F(CameraHidlTest, processCaptureRequestPreview) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
uint64_t bufferId = 1;
uint32_t frameNumber = 1;
::android::hardware::hidl_vec<uint8_t> settings;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
Stream previewStream;
HalStreamConfiguration halStreamConfig;
sp<ICameraDeviceSession> session;
configurePreviewStream(name, env, &previewThreshold,
&session /*out*/, &previewStream /*out*/,
&halStreamConfig /*out*/);
RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
Return<void> ret;
ret = session->constructDefaultRequestSettings(reqTemplate,
[&](auto status, const auto& req) {
ASSERT_EQ(Status::OK, status);
settings = req; });
ASSERT_TRUE(ret.isOk());
sp<GraphicBuffer> gb = new GraphicBuffer(
previewStream.width, previewStream.height,
static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat),
1, android_convertGralloc1To0Usage(
halStreamConfig.streams[0].producerUsage,
halStreamConfig.streams[0].consumerUsage));
ASSERT_NE(nullptr, gb.get());
StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
bufferId, hidl_handle(gb->getNativeBuffer()->handle),
BufferStatus::OK, nullptr, nullptr};
::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
outputBuffer};
StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
BufferStatus::ERROR, nullptr, nullptr};
CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
emptyInputBuffer, outputBuffers};
{
std::unique_lock<std::mutex> l(mLock);
mResultBuffers.clear();
mResultFrameNumber = frameNumber;
}
Status status = Status::INTERNAL_ERROR;
uint32_t numRequestProcessed = 0;
hidl_vec<BufferCache> cachesToRemove;
Return<void> returnStatus = session->processCaptureRequest(
{request},
cachesToRemove,
[&status, &numRequestProcessed] (auto s, uint32_t n) {
status = s;
numRequestProcessed = n;
});
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, status);
ASSERT_EQ(numRequestProcessed, 1u);
{
std::unique_lock<std::mutex> l(mLock);
while (0 == mResultBuffers.size()) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(kStreamBufferTimeoutSec);
ASSERT_NE(std::cv_status::timeout,
mResultCondition.wait_until(l, timeout));
}
ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status);
ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId);
request.frameNumber++;
//Empty settings should be supported after the first call
//for repeating requests.
request.settings.setToExternal(nullptr, 0, true);
mResultBuffers.clear();
mResultFrameNumber++;
}
returnStatus = session->processCaptureRequest(
{request},
cachesToRemove,
[&status, &numRequestProcessed] (auto s, uint32_t n) {
status = s;
numRequestProcessed = n;
});
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, status);
ASSERT_EQ(numRequestProcessed, 1u);
{
std::unique_lock<std::mutex> l(mLock);
while (0 == mResultBuffers.size()) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(kStreamBufferTimeoutSec);
ASSERT_NE(std::cv_status::timeout,
mResultCondition.wait_until(l, timeout));
}
ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status);
ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId);
}
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Test whether an incorrect capture request with missing settings will
// be reported correctly.
TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputPreviewStreams;
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
uint64_t bufferId = 1;
uint32_t frameNumber = 1;
::android::hardware::hidl_vec<uint8_t> settings;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
Stream previewStream;
HalStreamConfiguration halStreamConfig;
sp<ICameraDeviceSession> session;
configurePreviewStream(name, env, &previewThreshold,
&session /*out*/, &previewStream /*out*/,
&halStreamConfig /*out*/);
sp<GraphicBuffer> gb = new GraphicBuffer(
previewStream.width, previewStream.height,
static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat),
1, android_convertGralloc1To0Usage(
halStreamConfig.streams[0].producerUsage,
halStreamConfig.streams[0].consumerUsage));
StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
bufferId, hidl_handle(gb->getNativeBuffer()->handle),
BufferStatus::OK, nullptr, nullptr};
::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
outputBuffer};
StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
BufferStatus::ERROR, nullptr, nullptr};
CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
emptyInputBuffer, outputBuffers};
//Settings were not correctly initialized, we should fail here
Status status = Status::OK;
uint32_t numRequestProcessed = 0;
hidl_vec<BufferCache> cachesToRemove;
Return<void> ret = session->processCaptureRequest(
{request},
cachesToRemove,
[&status, &numRequestProcessed] (auto s, uint32_t n) {
status = s;
numRequestProcessed = n;
});
ASSERT_TRUE(ret.isOk());
ASSERT_EQ(Status::INTERNAL_ERROR, status);
ASSERT_EQ(numRequestProcessed, 0u);
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Check whether an invalid capture request with missing output buffers
// will be reported correctly.
TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputBlobStreams;
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
uint32_t frameNumber = 1;
::android::hardware::hidl_vec<uint8_t> settings;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
Stream previewStream;
HalStreamConfiguration halStreamConfig;
sp<ICameraDeviceSession> session;
configurePreviewStream(name, env, &previewThreshold,
&session /*out*/, &previewStream /*out*/,
&halStreamConfig /*out*/);
RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
Return<void> ret;
ret = session->constructDefaultRequestSettings(reqTemplate,
[&](auto status, const auto& req) {
ASSERT_EQ(Status::OK, status);
settings = req; });
ASSERT_TRUE(ret.isOk());
::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers;
StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
BufferStatus::ERROR, nullptr, nullptr};
CaptureRequest request = {frameNumber, 0/* fmqSettingsSize */, settings,
emptyInputBuffer, emptyOutputBuffers};
//Output buffers are missing, we should fail here
Status status = Status::OK;
uint32_t numRequestProcessed = 0;
hidl_vec<BufferCache> cachesToRemove;
ret = session->processCaptureRequest(
{request},
cachesToRemove,
[&status, &numRequestProcessed] (auto s, uint32_t n) {
status = s;
numRequestProcessed = n;
});
ASSERT_TRUE(ret.isOk());
ASSERT_EQ(Status::INTERNAL_ERROR, status);
ASSERT_EQ(numRequestProcessed, 0u);
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Generate, trigger and flush a preview request
TEST_F(CameraHidlTest, flushPreviewRequest) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputPreviewStreams;
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
uint64_t bufferId = 1;
uint32_t frameNumber = 1;
::android::hardware::hidl_vec<uint8_t> settings;
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
Stream previewStream;
HalStreamConfiguration halStreamConfig;
sp<ICameraDeviceSession> session;
configurePreviewStream(name, env, &previewThreshold,
&session /*out*/, &previewStream /*out*/,
&halStreamConfig /*out*/);
RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
Return<void> ret;
ret = session->constructDefaultRequestSettings(reqTemplate,
[&](auto status, const auto& req) {
ASSERT_EQ(Status::OK, status);
settings = req; });
ASSERT_TRUE(ret.isOk());
sp<GraphicBuffer> gb = new GraphicBuffer(
previewStream.width, previewStream.height,
static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat),
1, android_convertGralloc1To0Usage(
halStreamConfig.streams[0].producerUsage,
halStreamConfig.streams[0].consumerUsage));
ASSERT_NE(nullptr, gb.get());
StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
bufferId, hidl_handle(gb->getNativeBuffer()->handle),
BufferStatus::OK, nullptr, nullptr};
::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
outputBuffer};
const StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
BufferStatus::ERROR, nullptr, nullptr};
CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
emptyInputBuffer, outputBuffers};
{
std::unique_lock<std::mutex> l(mLock);
mResultBuffers.clear();
mErrors.clear();
mResultFrameNumber = frameNumber;
}
Status status = Status::INTERNAL_ERROR;
uint32_t numRequestProcessed = 0;
hidl_vec<BufferCache> cachesToRemove;
ret = session->processCaptureRequest(
{request},
cachesToRemove,
[&status, &numRequestProcessed] (auto s, uint32_t n) {
status = s;
numRequestProcessed = n;
});
ASSERT_TRUE(ret.isOk());
ASSERT_EQ(Status::OK, status);
ASSERT_EQ(numRequestProcessed, 1u);
//Flush before waiting for request to complete.
Return<Status> returnStatus = session->flush();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
{
std::unique_lock<std::mutex> l(mLock);
while ((0 == mResultBuffers.size()) && (0 == mErrors.size())) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(kStreamBufferTimeoutSec);
ASSERT_NE(std::cv_status::timeout,
mResultCondition.wait_until(l, timeout));
}
if (mErrors.empty()) {
ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status);
ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId);
} else {
for (auto &error : mErrors) {
switch (error.errorCode) {
case ErrorCode::ERROR_REQUEST:
case ErrorCode::ERROR_RESULT:
//Expected
break;
case ErrorCode::ERROR_BUFFER:
//Expected as well
ASSERT_EQ(frameNumber, error.frameNumber);
ASSERT_EQ(previewStream.id, error.errorStreamId);
break;
case ErrorCode::ERROR_DEVICE:
default:
FAIL() <<"Unexpected error:" << static_cast<uint32_t> (error.errorCode);
}
}
}
}
ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Verify that camera flushes correctly without any pending requests.
TEST_F(CameraHidlTest, flushEmpty) {
CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
std::vector<AvailableStream> outputPreviewStreams;
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
for (const auto& name : cameraDeviceNames) {
if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
Stream previewStream;
HalStreamConfiguration halStreamConfig;
sp<ICameraDeviceSession> session;
configurePreviewStream(name, env, &previewThreshold,
&session /*out*/, &previewStream /*out*/,
&halStreamConfig /*out*/);
{
std::unique_lock<std::mutex> l(mLock);
mResultBuffers.clear();
mErrors.clear();
mResultFrameNumber = 0;
}
Return<Status> returnStatus = session->flush();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
{
std::unique_lock<std::mutex> l(mLock);
auto timeout = std::chrono::system_clock::now() +
std::chrono::milliseconds(kEmptyFlushTimeoutMSec);
ASSERT_EQ(std::cv_status::timeout,
mResultCondition.wait_until(l, timeout));
ASSERT_TRUE(mErrors.empty());
ASSERT_TRUE(mResultBuffers.empty());
}
Return<void> ret = session->close();
ASSERT_TRUE(ret.isOk());
}
}
}
// Retrieve all valid output stream resolutions from the camera
// static characteristics.
Status CameraHidlTest::getAvailableOutputStreams(camera_metadata_t *staticMeta,
std::vector<AvailableStream> &outputStreams,
const AvailableStream *threshold) {
if (nullptr == staticMeta) {
return Status::ILLEGAL_ARGUMENT;
}
camera_metadata_ro_entry entry;
int rc = find_camera_metadata_ro_entry(staticMeta,
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry);
if ((0 != rc) || (0 != (entry.count % 4))) {
return Status::ILLEGAL_ARGUMENT;
}
for (size_t i = 0; i < entry.count; i+=4) {
if (ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT ==
entry.data.i32[i + 3]) {
if(nullptr == threshold) {
AvailableStream s = {entry.data.i32[i+1],
entry.data.i32[i+2], entry.data.i32[i]};
outputStreams.push_back(s);
} else {
if ((threshold->format == entry.data.i32[i]) &&
(threshold->width >= entry.data.i32[i+1]) &&
(threshold->height >= entry.data.i32[i+2])) {
AvailableStream s = {entry.data.i32[i+1],
entry.data.i32[i+2], threshold->format};
outputStreams.push_back(s);
}
}
}
}
return Status::OK;
}
// Check if constrained mode is supported by using the static
// camera characteristics.
Status CameraHidlTest::isConstrainedModeAvailable(camera_metadata_t *staticMeta) {
Status ret = Status::METHOD_NOT_SUPPORTED;
if (nullptr == staticMeta) {
return Status::ILLEGAL_ARGUMENT;
}
camera_metadata_ro_entry entry;
int rc = find_camera_metadata_ro_entry(staticMeta,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
if (0 != rc) {
return Status::ILLEGAL_ARGUMENT;
}
for (size_t i = 0; i < entry.count; i++) {
if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO ==
entry.data.u8[i]) {
ret = Status::OK;
break;
}
}
return ret;
}
// Pick the largest supported HFR mode from the static camera
// characteristics.
Status CameraHidlTest::pickConstrainedModeSize(camera_metadata_t *staticMeta,
AvailableStream &hfrStream) {
if (nullptr == staticMeta) {
return Status::ILLEGAL_ARGUMENT;
}
camera_metadata_ro_entry entry;
int rc = find_camera_metadata_ro_entry(staticMeta,
ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS, &entry);
if (0 != rc) {
return Status::METHOD_NOT_SUPPORTED;
} else if (0 != (entry.count % 5)) {
return Status::ILLEGAL_ARGUMENT;
}
hfrStream = {0, 0,
static_cast<uint32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
for (size_t i = 0; i < entry.count; i+=5) {
int32_t w = entry.data.i32[i];
int32_t h = entry.data.i32[i+1];
if ((hfrStream.width * hfrStream.height) < (w *h)) {
hfrStream.width = w;
hfrStream.height = h;
}
}
return Status::OK;
}
// Check whether ZSL is available using the static camera
// characteristics.
Status CameraHidlTest::isZSLModeAvailable(camera_metadata_t *staticMeta) {
Status ret = Status::METHOD_NOT_SUPPORTED;
if (nullptr == staticMeta) {
return Status::ILLEGAL_ARGUMENT;
}
camera_metadata_ro_entry entry;
int rc = find_camera_metadata_ro_entry(staticMeta,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
if (0 != rc) {
return Status::ILLEGAL_ARGUMENT;
}
for (size_t i = 0; i < entry.count; i++) {
if ((ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING ==
entry.data.u8[i]) ||
(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING ==
entry.data.u8[i]) ){
ret = Status::OK;
break;
}
}
return ret;
}
// Retrieve the reprocess input-output format map from the static
// camera characteristics.
Status CameraHidlTest::getZSLInputOutputMap(camera_metadata_t *staticMeta,
std::vector<AvailableZSLInputOutput> &inputOutputMap) {
if (nullptr == staticMeta) {
return Status::ILLEGAL_ARGUMENT;
}
camera_metadata_ro_entry entry;
int rc = find_camera_metadata_ro_entry(staticMeta,
ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP, &entry);
if ((0 != rc) || (0 >= entry.count)) {
return Status::ILLEGAL_ARGUMENT;
}
const int32_t* contents = &entry.data.i32[0];
for (size_t i = 0; i < entry.count; ) {
int32_t inputFormat = contents[i++];
int32_t length = contents[i++];
for (int32_t j = 0; j < length; j++) {
int32_t outputFormat = contents[i+j];
AvailableZSLInputOutput zslEntry = {inputFormat, outputFormat};
inputOutputMap.push_back(zslEntry);
}
i += length;
}
return Status::OK;
}
// Search for the largest stream size for a given format.
Status CameraHidlTest::findLargestSize(
const std::vector<AvailableStream> &streamSizes, int32_t format,
AvailableStream &result) {
result = {0, 0, 0};
for (auto &iter : streamSizes) {
if (format == iter.format) {
if ((result.width * result.height) < (iter.width * iter.height)) {
result = iter;
}
}
}
return (result.format == format) ? Status::OK : Status::ILLEGAL_ARGUMENT;
}
// Check whether the camera device supports specific focus mode.
Status CameraHidlTest::isAutoFocusModeAvailable(
::android::CameraParameters &cameraParams,
const char *mode) {
::android::String8 focusModes(cameraParams.get(
CameraParameters::KEY_SUPPORTED_FOCUS_MODES));
if (focusModes.contains(mode)) {
return Status::OK;
}
return Status::METHOD_NOT_SUPPORTED;
}
// Open a device session and configure a preview stream.
void CameraHidlTest::configurePreviewStream(const std::string &name,
const CameraHidlEnvironment* env,
const AvailableStream *previewThreshold,
sp<ICameraDeviceSession> *session /*out*/,
Stream *previewStream /*out*/,
HalStreamConfiguration *halStreamConfig /*out*/) {
ASSERT_NE(nullptr, env);
ASSERT_NE(nullptr, session);
ASSERT_NE(nullptr, previewStream);
ASSERT_NE(nullptr, halStreamConfig);
std::vector<AvailableStream> outputPreviewStreams;
::android::sp<ICameraDevice> device3_2;
ALOGI("configureStreams: Testing camera device %s", name.c_str());
Return<void> ret;
ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
(int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device3_2 = device;
});
ASSERT_TRUE(ret.isOk());
sp<DeviceCb> cb = new DeviceCb(this);
ret = device3_2->open(
cb,
[&](auto status, const auto& newSession) {
ALOGI("device::open returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(newSession, nullptr);
*session = newSession;
});
ASSERT_TRUE(ret.isOk());
camera_metadata_t *staticMeta;
ret = device3_2->getCameraCharacteristics([&] (Status s,
CameraMetadata metadata) {
ASSERT_EQ(Status::OK, s);
staticMeta = clone_camera_metadata(
reinterpret_cast<const camera_metadata_t*>(metadata.data()));
ASSERT_NE(nullptr, staticMeta);
});
ASSERT_TRUE(ret.isOk());
outputPreviewStreams.clear();
auto rc = getAvailableOutputStreams(staticMeta,
outputPreviewStreams, previewThreshold);
free_camera_metadata(staticMeta);
ASSERT_EQ(Status::OK, rc);
ASSERT_FALSE(outputPreviewStreams.empty());
*previewStream = {0, StreamType::OUTPUT,
static_cast<uint32_t> (outputPreviewStreams[0].width),
static_cast<uint32_t> (outputPreviewStreams[0].height),
static_cast<PixelFormat> (outputPreviewStreams[0].format),
0, 0, StreamRotation::ROTATION_0};
::android::hardware::hidl_vec<Stream> streams = {*previewStream};
StreamConfiguration config = {streams,
StreamConfigurationMode::NORMAL_MODE};
ret = (*session)->configureStreams(config, [&] (Status s,
HalStreamConfiguration halConfig) {
ASSERT_EQ(Status::OK, s);
ASSERT_EQ(1u, halConfig.streams.size());
*halStreamConfig = halConfig;
});
ASSERT_TRUE(ret.isOk());
}
// Open a device session with empty callbacks and return static metadata.
void CameraHidlTest::openEmptyDeviceSession(const std::string &name,
const CameraHidlEnvironment* env,
sp<ICameraDeviceSession> *session /*out*/,
camera_metadata_t **staticMeta /*out*/) {
ASSERT_NE(nullptr, env);
ASSERT_NE(nullptr, session);
ASSERT_NE(nullptr, staticMeta);
::android::sp<ICameraDevice> device3_2;
ALOGI("configureStreams: Testing camera device %s", name.c_str());
Return<void> ret;
ret = env->mProvider->getCameraDeviceInterface_V3_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
(int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device3_2 = device;
});
ASSERT_TRUE(ret.isOk());
sp<EmptyDeviceCb> cb = new EmptyDeviceCb();
ret = device3_2->open(cb, [&](auto status, const auto& newSession) {
ALOGI("device::open returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(newSession, nullptr);
*session = newSession;
});
ASSERT_TRUE(ret.isOk());
ret = device3_2->getCameraCharacteristics([&] (Status s,
CameraMetadata metadata) {
ASSERT_EQ(Status::OK, s);
*staticMeta = clone_camera_metadata(
reinterpret_cast<const camera_metadata_t*>(metadata.data()));
ASSERT_NE(nullptr, *staticMeta);
});
ASSERT_TRUE(ret.isOk());
}
// Open a particular camera device.
void CameraHidlTest::openCameraDevice(const std::string &name,
const CameraHidlEnvironment* env,
sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device1 /*out*/) {
ASSERT_TRUE(nullptr != env);
ASSERT_TRUE(nullptr != device1);
Return<void> ret;
ret = env->mProvider->getCameraDeviceInterface_V1_x(
name,
[&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V1_x returns status:%d",
(int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
*device1 = device;
});
ASSERT_TRUE(ret.isOk());
sp<Camera1DeviceCb> deviceCb = new Camera1DeviceCb(this);
Return<Status> returnStatus = (*device1)->open(deviceCb);
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
}
// Initialize and configure a preview window.
void CameraHidlTest::setupPreviewWindow(
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
sp<BufferItemConsumer> *bufferItemConsumer /*out*/,
sp<BufferItemHander> *bufferHandler /*out*/) {
ASSERT_NE(nullptr, device.get());
ASSERT_NE(nullptr, bufferItemConsumer);
ASSERT_NE(nullptr, bufferHandler);
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
*bufferItemConsumer = new BufferItemConsumer(consumer,
GraphicBuffer::USAGE_HW_TEXTURE); //Use GLConsumer default usage flags
ASSERT_NE(nullptr, (*bufferItemConsumer).get());
*bufferHandler = new BufferItemHander(*bufferItemConsumer);
ASSERT_NE(nullptr, (*bufferHandler).get());
(*bufferItemConsumer)->setFrameAvailableListener(*bufferHandler);
sp<Surface> surface = new Surface(producer);
sp<PreviewWindowCb> previewCb = new PreviewWindowCb(surface);
auto rc = device->setPreviewWindow(previewCb);
ASSERT_TRUE(rc.isOk());
ASSERT_EQ(Status::OK, rc);
}
// Stop camera preview and close camera.
void CameraHidlTest::stopPreviewAndClose(
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
Return<void> ret = device->stopPreview();
ASSERT_TRUE(ret.isOk());
ret = device->close();
ASSERT_TRUE(ret.isOk());
}
// Enable a specific camera message type.
void CameraHidlTest::enableMsgType(unsigned int msgType,
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
Return<void> ret = device->enableMsgType(msgType);
ASSERT_TRUE(ret.isOk());
Return<bool> returnBoolStatus = device->msgTypeEnabled(msgType);
ASSERT_TRUE(returnBoolStatus.isOk());
ASSERT_TRUE(returnBoolStatus);
}
// Disable a specific camera message type.
void CameraHidlTest::disableMsgType(unsigned int msgType,
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
Return<void> ret = device->disableMsgType(msgType);
ASSERT_TRUE(ret.isOk());
Return<bool> returnBoolStatus = device->msgTypeEnabled(msgType);
ASSERT_TRUE(returnBoolStatus.isOk());
ASSERT_FALSE(returnBoolStatus);
}
// Wait until a specific frame notification arrives.
void CameraHidlTest::waitForFrameLocked(DataCallbackMsg msgFrame,
std::unique_lock<std::mutex> &l) {
while (msgFrame != mDataMessageTypeReceived) {
auto timeout = std::chrono::system_clock::now() +
std::chrono::seconds(kStreamBufferTimeoutSec);
ASSERT_NE(std::cv_status::timeout,
mResultCondition.wait_until(l, timeout));
}
}
// Start preview on a particular camera device
void CameraHidlTest::startPreview(
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) {
Return<Status> returnStatus = device->startPreview();
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
}
// Retrieve camera parameters.
void CameraHidlTest::getParameters(
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
CameraParameters *cameraParams /*out*/) {
ASSERT_NE(nullptr, cameraParams);
Return<void> ret;
ret = device->getParameters([&] (const ::android::hardware::hidl_string& params) {
ASSERT_FALSE(params.empty());
::android::String8 paramString(params.c_str());
(*cameraParams).unflatten(paramString);
});
ASSERT_TRUE(ret.isOk());
}
// Set camera parameters.
void CameraHidlTest::setParameters(
const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
const CameraParameters &cameraParams) {
Return<Status> returnStatus = device->setParameters(
cameraParams.flatten().string());
ASSERT_TRUE(returnStatus.isOk());
ASSERT_EQ(Status::OK, returnStatus);
}
int main(int argc, char **argv) {
::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
int status = RUN_ALL_TESTS();
ALOGI("Test result = %d", status);
return status;
}