| /* |
| * 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 kCameraPassthroughServiceName[] = "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() { |
| // TODO: test the binderized mode |
| mProvider = ::testing::VtsHalHidlTargetTestBase::getService<ICameraProvider>(kCameraPassthroughServiceName); |
| // TODO: handle the device doesn't have any camera case |
| 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(); |
| int result = validate_camera_metadata_structure(metadata, &expectedSize); |
| ASSERT_TRUE(result == 0 || result == CAMERA_METADATA_VALIDATION_SHIFTED); |
| 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(); |
| int result = validate_camera_metadata_structure( |
| metadata, &expectedSize); |
| ASSERT_TRUE(result == 0 || result == CAMERA_METADATA_VALIDATION_SHIFTED); |
| 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; |
| } |