/* * Copyright (C) 2015 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_NDEBUG 0 #define LOG_TAG "NativeCamera" #include <log/log.h> #include <chrono> #include <condition_variable> #include <string> #include <map> #include <mutex> #include <vector> #include <unistd.h> #include <assert.h> #include <jni.h> #include <stdio.h> #include <string.h> #include <android/native_window_jni.h> #include "camera/NdkCameraError.h" #include "camera/NdkCameraManager.h" #include "camera/NdkCameraDevice.h" #include "camera/NdkCameraCaptureSession.h" #include "media/NdkImage.h" #include "media/NdkImageReader.h" #define LOG_ERROR(buf, ...) sprintf(buf, __VA_ARGS__); \ ALOGE("%s", buf); namespace { const int MAX_ERROR_STRING_LEN = 512; char errorString[MAX_ERROR_STRING_LEN]; } class CameraServiceListener { public: static void onAvailable(void* obj, const char* cameraId) { ALOGV("Camera %s onAvailable", cameraId); if (obj == nullptr) { return; } CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); thiz->mOnAvailableCount++; thiz->mAvailableMap[cameraId] = true; return; } static void onUnavailable(void* obj, const char* cameraId) { ALOGV("Camera %s onUnavailable", cameraId); if (obj == nullptr) { return; } CameraServiceListener* thiz = reinterpret_cast<CameraServiceListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); thiz->mOnUnavailableCount++; thiz->mAvailableMap[cameraId] = false; return; } void resetCount() { std::lock_guard<std::mutex> lock(mMutex); mOnAvailableCount = 0; mOnUnavailableCount = 0; return; } int getAvailableCount() { std::lock_guard<std::mutex> lock(mMutex); return mOnAvailableCount; } int getUnavailableCount() { std::lock_guard<std::mutex> lock(mMutex); return mOnUnavailableCount; } bool isAvailable(const char* cameraId) { std::lock_guard<std::mutex> lock(mMutex); if (mAvailableMap.count(cameraId) == 0) { return false; } return mAvailableMap[cameraId]; } private: std::mutex mMutex; int mOnAvailableCount = 0; int mOnUnavailableCount = 0; std::map<std::string, bool> mAvailableMap; }; class CameraDeviceListener { public: static void onDisconnected(void* obj, ACameraDevice* device) { ALOGV("Camera %s is disconnected!", ACameraDevice_getId(device)); if (obj == nullptr) { return; } CameraDeviceListener* thiz = reinterpret_cast<CameraDeviceListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); thiz->mOnDisconnect++; return; } static void onError(void* obj, ACameraDevice* device, int errorCode) { ALOGV("Camera %s receive error %d!", ACameraDevice_getId(device), errorCode); if (obj == nullptr) { return; } CameraDeviceListener* thiz = reinterpret_cast<CameraDeviceListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); thiz->mOnError++; thiz->mLatestError = errorCode; return; } private: std::mutex mMutex; int mOnDisconnect = 0; int mOnError = 0; int mLatestError = 0; }; class CaptureSessionListener { public: static void onClosed(void* obj, ACameraCaptureSession *session) { // TODO: might want an API to query cameraId even session is closed? ALOGV("Session %p is closed!", session); if (obj == nullptr) { return; } CaptureSessionListener* thiz = reinterpret_cast<CaptureSessionListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); thiz->mIsClosed = true; thiz->mOnClosed++; // Should never > 1 } static void onReady(void* obj, ACameraCaptureSession *session) { ALOGV("%s", __FUNCTION__); if (obj == nullptr) { return; } CaptureSessionListener* thiz = reinterpret_cast<CaptureSessionListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); ACameraDevice* device = nullptr; camera_status_t ret = ACameraCaptureSession_getDevice(session, &device); // There will be one onReady fired after session closed if (ret != ACAMERA_OK && !thiz->mIsClosed) { ALOGE("%s Getting camera device from session callback failed!", __FUNCTION__); thiz->mInError = true; } ALOGV("Session for camera %s is ready!", ACameraDevice_getId(device)); thiz->mIsIdle = true; thiz->mOnReady++; } static void onActive(void* obj, ACameraCaptureSession *session) { ALOGV("%s", __FUNCTION__); if (obj == nullptr) { return; } CaptureSessionListener* thiz = reinterpret_cast<CaptureSessionListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); ACameraDevice* device = nullptr; camera_status_t ret = ACameraCaptureSession_getDevice(session, &device); if (ret != ACAMERA_OK) { ALOGE("%s Getting camera device from session callback failed!", __FUNCTION__); thiz->mInError = true; } ALOGV("Session for camera %s is busy!", ACameraDevice_getId(device)); thiz->mIsIdle = false; thiz->mOnActive; } bool isClosed() { std::lock_guard<std::mutex> lock(mMutex); return mIsClosed; } bool isIdle() { std::lock_guard<std::mutex> lock(mMutex); return mIsIdle; } bool isInError() { std::lock_guard<std::mutex> lock(mMutex); return mInError; } int onClosedCount() { std::lock_guard<std::mutex> lock(mMutex); return mOnClosed; } int onReadyCount() { std::lock_guard<std::mutex> lock(mMutex); return mOnReady; } int onActiveCount() { std::lock_guard<std::mutex> lock(mMutex); return mOnActive; } void reset() { std::lock_guard<std::mutex> lock(mMutex); mIsClosed = false; mIsIdle = true; mInError = false; mOnClosed = 0; mOnReady = 0; mOnActive = 0; } private: std::mutex mMutex; bool mIsClosed = false; bool mIsIdle = true; bool mInError = false; // should always stay false int mOnClosed = 0; int mOnReady = 0; int mOnActive = 0; }; class CaptureResultListener { public: ~CaptureResultListener() { std::unique_lock<std::mutex> l(mMutex); clearSavedRequestsLocked(); } static void onCaptureStart(void* /*obj*/, ACameraCaptureSession* /*session*/, const ACaptureRequest* /*request*/, int64_t /*timestamp*/) { //Not used for now } static void onCaptureProgressed(void* /*obj*/, ACameraCaptureSession* /*session*/, ACaptureRequest* /*request*/, const ACameraMetadata* /*result*/) { //Not used for now } static void onCaptureCompleted(void* obj, ACameraCaptureSession* /*session*/, ACaptureRequest* request, const ACameraMetadata* result) { ALOGV("%s", __FUNCTION__); if ((obj == nullptr) || (result == nullptr)) { return; } CaptureResultListener* thiz = reinterpret_cast<CaptureResultListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); ACameraMetadata_const_entry entry; auto ret = ACameraMetadata_getConstEntry(result, ACAMERA_SYNC_FRAME_NUMBER, &entry); if (ret != ACAMERA_OK) { ALOGE("Error: Sync frame number missing from result!"); return; } if (thiz->mSaveCompletedRequests) { thiz->mCompletedRequests.push_back(ACaptureRequest_copy(request)); } thiz->mLastCompletedFrameNumber = entry.data.i64[0]; thiz->mResultCondition.notify_one(); } static void onCaptureFailed(void* obj, ACameraCaptureSession* /*session*/, ACaptureRequest* /*request*/, ACameraCaptureFailure* failure) { ALOGV("%s", __FUNCTION__); if ((obj == nullptr) || (failure == nullptr)) { return; } CaptureResultListener* thiz = reinterpret_cast<CaptureResultListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); thiz->mLastFailedFrameNumber = failure->frameNumber; thiz->mResultCondition.notify_one(); } static void onCaptureSequenceCompleted(void* obj, ACameraCaptureSession* /*session*/, int sequenceId, int64_t frameNumber) { ALOGV("%s", __FUNCTION__); if (obj == nullptr) { return; } CaptureResultListener* thiz = reinterpret_cast<CaptureResultListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); thiz->mLastSequenceIdCompleted = sequenceId; thiz->mLastSequenceFrameNumber = frameNumber; thiz->mResultCondition.notify_one(); } static void onCaptureSequenceAborted(void* /*obj*/, ACameraCaptureSession* /*session*/, int /*sequenceId*/) { //Not used for now } static void onCaptureBufferLost(void* obj, ACameraCaptureSession* /*session*/, ACaptureRequest* /*request*/, ANativeWindow* /*window*/, int64_t frameNumber) { ALOGV("%s", __FUNCTION__); if (obj == nullptr) { return; } CaptureResultListener* thiz = reinterpret_cast<CaptureResultListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); thiz->mLastLostFrameNumber = frameNumber; thiz->mResultCondition.notify_one(); } int64_t getCaptureSequenceLastFrameNumber(int64_t sequenceId, uint32_t timeoutSec) { int64_t ret = -1; std::unique_lock<std::mutex> l(mMutex); while (mLastSequenceIdCompleted != sequenceId) { auto timeout = std::chrono::system_clock::now() + std::chrono::seconds(timeoutSec); if (std::cv_status::timeout == mResultCondition.wait_until(l, timeout)) { break; } } if (mLastSequenceIdCompleted == sequenceId) { ret = mLastSequenceFrameNumber; } return ret; } bool waitForFrameNumber(int64_t frameNumber, uint32_t timeoutSec) { bool ret = false; std::unique_lock<std::mutex> l(mMutex); while ((mLastCompletedFrameNumber != frameNumber) && (mLastLostFrameNumber != frameNumber) && (mLastFailedFrameNumber != frameNumber)) { auto timeout = std::chrono::system_clock::now() + std::chrono::seconds(timeoutSec); if (std::cv_status::timeout == mResultCondition.wait_until(l, timeout)) { break; } } if ((mLastCompletedFrameNumber == frameNumber) || (mLastLostFrameNumber == frameNumber) || (mLastFailedFrameNumber == frameNumber)) { ret = true; } return ret; } void setRequestSave(bool enable) { std::unique_lock<std::mutex> l(mMutex); if (!enable) { clearSavedRequestsLocked(); } mSaveCompletedRequests = enable; } // The lifecycle of returned ACaptureRequest* is still managed by CaptureResultListener void getCompletedRequests(std::vector<ACaptureRequest*>* out) { std::unique_lock<std::mutex> l(mMutex); *out = mCompletedRequests; } void reset() { std::lock_guard<std::mutex> lock(mMutex); mLastSequenceIdCompleted = -1; mLastSequenceFrameNumber = -1; mLastCompletedFrameNumber = -1; mLastLostFrameNumber = -1; mLastFailedFrameNumber = -1; mSaveCompletedRequests = false; clearSavedRequestsLocked(); } private: std::mutex mMutex; std::condition_variable mResultCondition; int mLastSequenceIdCompleted = -1; int64_t mLastSequenceFrameNumber = -1; int64_t mLastCompletedFrameNumber = -1; int64_t mLastLostFrameNumber = -1; int64_t mLastFailedFrameNumber = -1; bool mSaveCompletedRequests = false; std::vector<ACaptureRequest*> mCompletedRequests; void clearSavedRequestsLocked() { for (ACaptureRequest* req : mCompletedRequests) { ACaptureRequest_free(req); } mCompletedRequests.clear(); } }; class ImageReaderListener { public: // count, acquire, validate, and delete AImage when a new image is available static void validateImageCb(void* obj, AImageReader* reader) { ALOGV("%s", __FUNCTION__); if (obj == nullptr) { return; } ImageReaderListener* thiz = reinterpret_cast<ImageReaderListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); thiz->mOnImageAvailableCount++; AImage* img = nullptr; media_status_t ret = AImageReader_acquireNextImage(reader, &img); if (ret != AMEDIA_OK || img == nullptr) { ALOGE("%s: acquire image from reader %p failed! ret: %d, img %p", __FUNCTION__, reader, ret, img); return; } // TODO: validate image content int32_t format = -1; ret = AImage_getFormat(img, &format); if (ret != AMEDIA_OK || format == -1) { ALOGE("%s: get format for image %p failed! ret: %d, format %d", __FUNCTION__, img, ret, format); } // Save jpeg to SD card if (thiz->mDumpFilePathBase && format == AIMAGE_FORMAT_JPEG) { int32_t numPlanes = 0; ret = AImage_getNumberOfPlanes(img, &numPlanes); if (ret != AMEDIA_OK || numPlanes != 1) { ALOGE("%s: get numPlanes for image %p failed! ret: %d, numPlanes %d", __FUNCTION__, img, ret, numPlanes); AImage_delete(img); return; } int32_t width = -1, height = -1; ret = AImage_getWidth(img, &width); if (ret != AMEDIA_OK || width <= 0) { ALOGE("%s: get width for image %p failed! ret: %d, width %d", __FUNCTION__, img, ret, width); AImage_delete(img); return; } ret = AImage_getHeight(img, &height); if (ret != AMEDIA_OK || height <= 0) { ALOGE("%s: get height for image %p failed! ret: %d, height %d", __FUNCTION__, img, ret, height); AImage_delete(img); return; } uint8_t* data = nullptr; int dataLength = 0; ret = AImage_getPlaneData(img, /*planeIdx*/0, &data, &dataLength); if (ret != AMEDIA_OK || data == nullptr || dataLength <= 0) { ALOGE("%s: get jpeg data for image %p failed! ret: %d, data %p, len %d", __FUNCTION__, img, ret, data, dataLength); AImage_delete(img); return; } #if 0 char dumpFilePath[512]; sprintf(dumpFilePath, "%s/%dx%d.jpg", thiz->mDumpFilePathBase, width, height); ALOGI("Writing jpeg file to %s", dumpFilePath); FILE* file = fopen(dumpFilePath,"w+"); if (file != nullptr) { fwrite(data, 1, dataLength, file); fflush(file); fclose(file); } #endif } AImage_delete(img); } // count, acquire image but not delete the image static void acquireImageCb(void* obj, AImageReader* reader) { ALOGV("%s", __FUNCTION__); if (obj == nullptr) { return; } ImageReaderListener* thiz = reinterpret_cast<ImageReaderListener*>(obj); std::lock_guard<std::mutex> lock(thiz->mMutex); thiz->mOnImageAvailableCount++; // Acquire, but not closing. AImage* img = nullptr; media_status_t ret = AImageReader_acquireNextImage(reader, &img); if (ret != AMEDIA_OK || img == nullptr) { ALOGE("%s: acquire image from reader %p failed! ret: %d, img %p", __FUNCTION__, reader, ret, img); return; } return; } int onImageAvailableCount() { std::lock_guard<std::mutex> lock(mMutex); return mOnImageAvailableCount; } void setDumpFilePathBase(const char* path) { std::lock_guard<std::mutex> lock(mMutex); mDumpFilePathBase = path; } private: // TODO: add mReader to make sure each listener is associated to one reader? std::mutex mMutex; int mOnImageAvailableCount = 0; const char* mDumpFilePathBase = nullptr; }; class StaticInfo { public: explicit StaticInfo(ACameraMetadata* chars) : mChars(chars) {} bool isColorOutputSupported() { return isCapabilitySupported(ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE); } bool isCapabilitySupported(acamera_metadata_enum_android_request_available_capabilities_t cap) { ACameraMetadata_const_entry entry; ACameraMetadata_getConstEntry(mChars, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entry); for (uint32_t i = 0; i < entry.count; i++) { if (entry.data.u8[i] == cap) { return true; } } return false; } private: const ACameraMetadata* mChars; }; class PreviewTestCase { public: ~PreviewTestCase() { resetCamera(); deInit(); if (mCameraManager) { ACameraManager_delete(mCameraManager); mCameraManager = nullptr; } } PreviewTestCase() { // create is guaranteed to succeed; createManager(); } // Free all resources except camera manager void resetCamera() { mSessionListener.reset(); mResultListener.reset(); if (mSession) { ACameraCaptureSession_close(mSession); mSession = nullptr; } if (mDevice) { ACameraDevice_close(mDevice); mDevice = nullptr; } if (mImgReader) { AImageReader_delete(mImgReader); // No need to call ANativeWindow_release on imageReaderAnw mImgReaderAnw = nullptr; mImgReader = nullptr; } if (mPreviewAnw) { ANativeWindow_release(mPreviewAnw); mPreviewAnw = nullptr; } if (mOutputs) { ACaptureSessionOutputContainer_free(mOutputs); mOutputs = nullptr; } if (mPreviewOutput) { ACaptureSessionOutput_free(mPreviewOutput); mPreviewOutput = nullptr; } if (mImgReaderOutput) { ACaptureSessionOutput_free(mImgReaderOutput); mImgReaderOutput = nullptr; } if (mPreviewRequest) { ACaptureRequest_free(mPreviewRequest); mPreviewRequest = nullptr; } if (mStillRequest) { ACaptureRequest_free(mStillRequest); mStillRequest = nullptr; } if (mReqPreviewOutput) { ACameraOutputTarget_free(mReqPreviewOutput); mReqPreviewOutput = nullptr; } if (mReqImgReaderOutput) { ACameraOutputTarget_free(mReqImgReaderOutput); mReqImgReaderOutput = nullptr; } mImgReaderInited = false; mPreviewInited = false; } camera_status_t initWithErrorLog() { camera_status_t ret = ACameraManager_getCameraIdList( mCameraManager, &mCameraIdList); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Get camera id list failed: ret %d", ret); return ret; } ret = ACameraManager_registerAvailabilityCallback(mCameraManager, &mServiceCb); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Register availability callback failed: ret %d", ret); return ret; } mMgrInited = true; return ACAMERA_OK; } camera_status_t deInit () { if (!mMgrInited) { return ACAMERA_OK; } camera_status_t ret = ACameraManager_unregisterAvailabilityCallback( mCameraManager, &mServiceCb); if (ret != ACAMERA_OK) { ALOGE("Unregister availability callback failed: ret %d", ret); return ret; } if (mCameraIdList) { ACameraManager_deleteCameraIdList(mCameraIdList); mCameraIdList = nullptr; } mMgrInited = false; return ACAMERA_OK; } int getNumCameras() { if (!mMgrInited || !mCameraIdList) { return -1; } return mCameraIdList->numCameras; } const char* getCameraId(int idx) { if (!mMgrInited || !mCameraIdList || idx < 0 || idx >= mCameraIdList->numCameras) { return nullptr; } return mCameraIdList->cameraIds[idx]; } camera_status_t updateOutput(JNIEnv* env, ACaptureSessionOutput *output) { if (mSession == nullptr) { ALOGE("Testcase cannot update output configuration session %p", mSession); return ACAMERA_ERROR_UNKNOWN; } return ACameraCaptureSession_updateSharedOutput(mSession, output); } camera_status_t openCamera(const char* cameraId) { if (mDevice) { ALOGE("Cannot open camera before closing previously open one"); return ACAMERA_ERROR_INVALID_PARAMETER; } mCameraId = cameraId; return ACameraManager_openCamera(mCameraManager, cameraId, &mDeviceCb, &mDevice); } camera_status_t closeCamera() { camera_status_t ret = ACameraDevice_close(mDevice); mDevice = nullptr; return ret; } bool isCameraAvailable(const char* cameraId) { if (!mMgrInited) { ALOGE("Camera service listener has not been registered!"); } return mServiceListener.isAvailable(cameraId); } media_status_t initImageReaderWithErrorLog( int32_t width, int32_t height, int32_t format, int32_t maxImages, AImageReader_ImageListener* listener) { if (mImgReader || mImgReaderAnw) { LOG_ERROR(errorString, "Cannot init image reader before closing existing one"); return AMEDIA_ERROR_UNKNOWN; } media_status_t ret = AImageReader_new( width, height, format, maxImages, &mImgReader); if (ret != AMEDIA_OK) { LOG_ERROR(errorString, "Create image reader. ret %d", ret); return ret; } if (mImgReader == nullptr) { LOG_ERROR(errorString, "null image reader created"); return AMEDIA_ERROR_UNKNOWN; } ret = AImageReader_setImageListener(mImgReader, listener); if (ret != AMEDIA_OK) { LOG_ERROR(errorString, "Set AImageReader listener failed. ret %d", ret); return ret; } ret = AImageReader_getWindow(mImgReader, &mImgReaderAnw); if (ret != AMEDIA_OK) { LOG_ERROR(errorString, "AImageReader_getWindow failed. ret %d", ret); return ret; } if (mImgReaderAnw == nullptr) { LOG_ERROR(errorString, "Null ANW from AImageReader!"); return AMEDIA_ERROR_UNKNOWN; } mImgReaderInited = true; return AMEDIA_OK; } ANativeWindow* initPreviewAnw(JNIEnv* env, jobject jSurface) { if (mPreviewAnw) { ALOGE("Cannot init preview twice!"); return nullptr; } mPreviewAnw = ANativeWindow_fromSurface(env, jSurface); mPreviewInited = true; return mPreviewAnw; } camera_status_t createCaptureSessionWithLog(bool isPreviewShared = false, ACaptureRequest *sessionParameters = nullptr) { if (mSession) { LOG_ERROR(errorString, "Cannot create session before closing existing one"); return ACAMERA_ERROR_UNKNOWN; } if (!mMgrInited || (!mImgReaderInited && !mPreviewInited)) { LOG_ERROR(errorString, "Cannot create session. mgrInit %d readerInit %d previewInit %d", mMgrInited, mImgReaderInited, mPreviewInited); return ACAMERA_ERROR_UNKNOWN; } camera_status_t ret = ACaptureSessionOutputContainer_create(&mOutputs); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Create capture session output container failed. ret %d", ret); return ret; } if (mImgReaderInited) { ret = ACaptureSessionOutput_create(mImgReaderAnw, &mImgReaderOutput); if (ret != ACAMERA_OK || mImgReaderOutput == nullptr) { LOG_ERROR(errorString, "Sesssion image reader output create fail! ret %d output %p", ret, mImgReaderOutput); if (ret == ACAMERA_OK) { ret = ACAMERA_ERROR_UNKNOWN; // ret OK but output is null } return ret; } ret = ACaptureSessionOutputContainer_add(mOutputs, mImgReaderOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Sesssion image reader output add failed! ret %d", ret); return ret; } } if (mPreviewInited) { if (isPreviewShared) { ret = ACaptureSessionSharedOutput_create(mPreviewAnw, &mPreviewOutput); } else { ret = ACaptureSessionOutput_create(mPreviewAnw, &mPreviewOutput); } if (ret != ACAMERA_OK || mPreviewOutput == nullptr) { LOG_ERROR(errorString, "Sesssion preview output create fail! ret %d output %p", ret, mPreviewOutput); if (ret == ACAMERA_OK) { ret = ACAMERA_ERROR_UNKNOWN; // ret OK but output is null } return ret; } ret = ACaptureSessionOutputContainer_add(mOutputs, mPreviewOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Sesssion preview output add failed! ret %d", ret); return ret; } } ret = ACameraDevice_createCaptureSessionWithSessionParameters( mDevice, mOutputs, sessionParameters, &mSessionCb, &mSession); if (ret != ACAMERA_OK || mSession == nullptr) { LOG_ERROR(errorString, "Create session for camera %s failed. ret %d session %p", mCameraId, ret, mSession); if (ret == ACAMERA_OK) { ret = ACAMERA_ERROR_UNKNOWN; // ret OK but session is null } return ret; } return ACAMERA_OK; } void closeSession() { if (mSession != nullptr) { ACameraCaptureSession_close(mSession); } if (mOutputs) { ACaptureSessionOutputContainer_free(mOutputs); mOutputs = nullptr; } if (mPreviewOutput) { ACaptureSessionOutput_free(mPreviewOutput); mPreviewOutput = nullptr; } if (mImgReaderOutput) { ACaptureSessionOutput_free(mImgReaderOutput); mImgReaderOutput = nullptr; } mSession = nullptr; } camera_status_t createRequestsWithErrorLog() { if (mPreviewRequest || mStillRequest) { LOG_ERROR(errorString, "Cannot create requests before deleteing existing one"); return ACAMERA_ERROR_UNKNOWN; } if (mDevice == nullptr || (!mPreviewInited && !mImgReaderInited)) { LOG_ERROR(errorString, "Cannot create request. device %p previewInit %d readeInit %d", mDevice, mPreviewInited, mImgReaderInited); return ACAMERA_ERROR_UNKNOWN; } camera_status_t ret; if (mPreviewInited) { ret = ACameraDevice_createCaptureRequest( mDevice, TEMPLATE_PREVIEW, &mPreviewRequest); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s create preview request failed. ret %d", mCameraId, ret); return ret; } ret = ACameraOutputTarget_create(mPreviewAnw, &mReqPreviewOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s create request preview output target failed. ret %d", mCameraId, ret); return ret; } ret = ACaptureRequest_addTarget(mPreviewRequest, mReqPreviewOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s add preview request output failed. ret %d", mCameraId, ret); return ret; } } else { ALOGI("Preview not inited. Will not create preview request!"); } if (mImgReaderInited) { ret = ACameraDevice_createCaptureRequest( mDevice, TEMPLATE_STILL_CAPTURE, &mStillRequest); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s create still request failed. ret %d", mCameraId, ret); return ret; } ret = ACameraOutputTarget_create(mImgReaderAnw, &mReqImgReaderOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s create request reader output target failed. ret %d", mCameraId, ret); return ret; } ret = ACaptureRequest_addTarget(mStillRequest, mReqImgReaderOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s add still request output failed. ret %d", mCameraId, ret); return ret; } if (mPreviewInited) { ret = ACaptureRequest_addTarget(mStillRequest, mReqPreviewOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s add still request preview output failed. ret %d", mCameraId, ret); return ret; } } } else { ALOGI("AImageReader not inited. Will not create still request!"); } return ACAMERA_OK; } // The output ACaptureRequest* is still managed by testcase class camera_status_t getStillRequest(ACaptureRequest** out) { if (mStillRequest == nullptr) { ALOGE("Camera %s Still capture request hasn't been created", mCameraId); return ACAMERA_ERROR_INVALID_PARAMETER; } *out = mStillRequest; return ACAMERA_OK; } camera_status_t getPreviewRequest(ACaptureRequest** out) { if (mPreviewRequest == nullptr) { ALOGE("Camera %s Preview capture request hasn't been created", mCameraId); return ACAMERA_ERROR_INVALID_PARAMETER; } *out = mPreviewRequest; return ACAMERA_OK; } camera_status_t startPreview(int *sequenceId = nullptr) { if (mSession == nullptr || mPreviewRequest == nullptr) { ALOGE("Testcase cannot start preview: session %p, preview request %p", mSession, mPreviewRequest); return ACAMERA_ERROR_UNKNOWN; } int previewSeqId; camera_status_t ret; if (sequenceId == nullptr) { ret = ACameraCaptureSession_setRepeatingRequest( mSession, nullptr, 1, &mPreviewRequest, &previewSeqId); } else { ret = ACameraCaptureSession_setRepeatingRequest( mSession, &mResultCb, 1, &mPreviewRequest, sequenceId); } return ret; } camera_status_t updateRepeatingRequest(ACaptureRequest *updatedRequest, int *sequenceId = nullptr) { if (mSession == nullptr || updatedRequest == nullptr) { ALOGE("Testcase cannot update repeating request: session %p, updated request %p", mSession, updatedRequest); return ACAMERA_ERROR_UNKNOWN; } int previewSeqId; camera_status_t ret; if (sequenceId == nullptr) { ret = ACameraCaptureSession_setRepeatingRequest( mSession, nullptr, 1, &updatedRequest, &previewSeqId); } else { ret = ACameraCaptureSession_setRepeatingRequest( mSession, &mResultCb, 1, &updatedRequest, sequenceId); } return ret; } int64_t getCaptureSequenceLastFrameNumber(int64_t sequenceId, uint32_t timeoutSec) { return mResultListener.getCaptureSequenceLastFrameNumber(sequenceId, timeoutSec); } bool waitForFrameNumber(int64_t frameNumber, uint32_t timeoutSec) { return mResultListener.waitForFrameNumber(frameNumber, timeoutSec); } camera_status_t takePicture() { if (mSession == nullptr || mStillRequest == nullptr) { ALOGE("Testcase cannot take picture: session %p, still request %p", mSession, mStillRequest); return ACAMERA_ERROR_UNKNOWN; } int seqId; return ACameraCaptureSession_capture( mSession, nullptr, 1, &mStillRequest, &seqId); } camera_status_t capture(ACaptureRequest* request, ACameraCaptureSession_captureCallbacks* listener, /*out*/int* seqId) { if (mSession == nullptr || request == nullptr) { ALOGE("Testcase cannot capture session: session %p, request %p", mSession, request); return ACAMERA_ERROR_UNKNOWN; } return ACameraCaptureSession_capture( mSession, listener, 1, &request, seqId); } camera_status_t resetWithErrorLog() { camera_status_t ret; closeSession(); for (int i = 0; i < 50; i++) { usleep(100000); // sleep 100ms if (mSessionListener.isClosed()) { ALOGI("Session take ~%d ms to close", i*100); break; } } if (!mSessionListener.isClosed() || mSessionListener.onClosedCount() != 1) { LOG_ERROR(errorString, "Session for camera %s close error. isClosde %d close count %d", mCameraId, mSessionListener.isClosed(), mSessionListener.onClosedCount()); return ACAMERA_ERROR_UNKNOWN; } mSessionListener.reset(); mResultListener.reset(); ret = closeCamera(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Close camera device %s failure. ret %d", mCameraId, ret); return ret; } resetCamera(); return ACAMERA_OK; } CaptureSessionListener* getSessionListener() { return &mSessionListener; } ACameraDevice* getCameraDevice() { return mDevice; } ACaptureSessionOutput *getPreviewOutput() { return mPreviewOutput; } private: ACameraManager* createManager() { if (!mCameraManager) { mCameraManager = ACameraManager_create(); } return mCameraManager; } CameraServiceListener mServiceListener; ACameraManager_AvailabilityCallbacks mServiceCb { &mServiceListener, CameraServiceListener::onAvailable, CameraServiceListener::onUnavailable }; CameraDeviceListener mDeviceListener; ACameraDevice_StateCallbacks mDeviceCb { &mDeviceListener, CameraDeviceListener::onDisconnected, CameraDeviceListener::onError }; CaptureSessionListener mSessionListener; ACameraCaptureSession_stateCallbacks mSessionCb { &mSessionListener, CaptureSessionListener::onClosed, CaptureSessionListener::onReady, CaptureSessionListener::onActive }; CaptureResultListener mResultListener; ACameraCaptureSession_captureCallbacks mResultCb { &mResultListener, CaptureResultListener::onCaptureStart, CaptureResultListener::onCaptureProgressed, CaptureResultListener::onCaptureCompleted, CaptureResultListener::onCaptureFailed, CaptureResultListener::onCaptureSequenceCompleted, CaptureResultListener::onCaptureSequenceAborted, CaptureResultListener::onCaptureBufferLost }; ACameraIdList* mCameraIdList = nullptr; ACameraDevice* mDevice = nullptr; AImageReader* mImgReader = nullptr; ANativeWindow* mImgReaderAnw = nullptr; ANativeWindow* mPreviewAnw = nullptr; ACameraManager* mCameraManager = nullptr; ACaptureSessionOutputContainer* mOutputs = nullptr; ACaptureSessionOutput* mPreviewOutput = nullptr; ACaptureSessionOutput* mImgReaderOutput = nullptr; ACameraCaptureSession* mSession = nullptr; ACaptureRequest* mPreviewRequest = nullptr; ACaptureRequest* mStillRequest = nullptr; ACameraOutputTarget* mReqPreviewOutput = nullptr; ACameraOutputTarget* mReqImgReaderOutput = nullptr; const char* mCameraId; bool mMgrInited = false; // cameraId, serviceListener bool mImgReaderInited = false; bool mPreviewInited = false; }; jint throwAssertionError(JNIEnv* env, const char* message) { jclass assertionClass; const char* className = "junit/framework/AssertionFailedError"; assertionClass = env->FindClass(className); if (assertionClass == nullptr) { ALOGE("Native throw error: cannot find class %s", className); return -1; } return env->ThrowNew(assertionClass, message); } extern "C" jboolean Java_android_hardware_camera2_cts_NativeCameraManagerTest_\ testCameraManagerGetAndCloseNative( JNIEnv* env, jclass /*clazz*/) { bool pass = false; ALOGV("%s", __FUNCTION__); ACameraManager* cameraManager2 = nullptr; ACameraManager* cameraManager3 = nullptr; ACameraManager* cameraManager4 = nullptr; camera_status_t ret = ACAMERA_OK; ACameraManager* cameraManager = ACameraManager_create(); if (cameraManager == nullptr) { LOG_ERROR(errorString, "ACameraManager_create returns nullptr"); goto cleanup; } ACameraManager_delete(cameraManager); cameraManager = nullptr; // Test get/close multiple instances cameraManager = ACameraManager_create(); cameraManager2 = ACameraManager_create(); if (cameraManager2 == nullptr) { LOG_ERROR(errorString, "ACameraManager_create 2 returns nullptr"); goto cleanup; } ACameraManager_delete(cameraManager); cameraManager = nullptr; cameraManager3 = ACameraManager_create(); if (cameraManager3 == nullptr) { LOG_ERROR(errorString, "ACameraManager_create 3 returns nullptr"); goto cleanup; } cameraManager4 = ACameraManager_create(); if (cameraManager4 == nullptr) { LOG_ERROR(errorString, "ACameraManager_create 4 returns nullptr"); goto cleanup; } ACameraManager_delete(cameraManager3); ACameraManager_delete(cameraManager2); ACameraManager_delete(cameraManager4); pass = true; cleanup: if (cameraManager) { ACameraManager_delete(cameraManager); } ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "fail"); if (!pass) { throwAssertionError(env, errorString); } return pass; } extern "C" jboolean Java_android_hardware_camera2_cts_NativeCameraManagerTest_\ testCameraManagerGetCameraIdsNative( JNIEnv* env, jclass /*clazz*/) { ALOGV("%s", __FUNCTION__); bool pass = false; ACameraManager* mgr = ACameraManager_create(); ACameraIdList *cameraIdList = nullptr; camera_status_t ret = ACameraManager_getCameraIdList(mgr, &cameraIdList); if (ret != ACAMERA_OK || cameraIdList == nullptr) { LOG_ERROR(errorString, "Get camera id list failed: ret %d, cameraIdList %p", ret, cameraIdList); goto cleanup; } ALOGI("Number of cameras: %d", cameraIdList->numCameras); for (int i = 0; i < cameraIdList->numCameras; i++) { ALOGI("Camera ID: %s", cameraIdList->cameraIds[i]); } ACameraManager_deleteCameraIdList(cameraIdList); cameraIdList = nullptr; pass = true; cleanup: if (mgr) { ACameraManager_delete(mgr); } if (cameraIdList) { ACameraManager_deleteCameraIdList(cameraIdList); } ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "fail"); if (!pass) { throwAssertionError(env, errorString); } return pass; } extern "C" jboolean Java_android_hardware_camera2_cts_NativeCameraManagerTest_\ testCameraManagerAvailabilityCallbackNative( JNIEnv* env, jclass /*clazz*/) { ALOGV("%s", __FUNCTION__); bool pass = false; ACameraManager* mgr = ACameraManager_create(); ACameraIdList *cameraIdList = nullptr; camera_status_t ret = ACameraManager_getCameraIdList(mgr, &cameraIdList); int numCameras = cameraIdList->numCameras; CameraServiceListener listener; ACameraManager_AvailabilityCallbacks cbs { &listener, CameraServiceListener::onAvailable, CameraServiceListener::onUnavailable}; ret = ACameraManager_registerAvailabilityCallback(mgr, &cbs); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Register availability callback failed: ret %d", ret); goto cleanup; } sleep(1); // sleep a second to give some time for callbacks to happen // Should at least get onAvailable for each camera once if (listener.getAvailableCount() < numCameras) { LOG_ERROR(errorString, "Expect at least %d available callback but only got %d", numCameras, listener.getAvailableCount()); goto cleanup; } ret = ACameraManager_unregisterAvailabilityCallback(mgr, &cbs); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Unregister availability callback failed: ret %d", ret); goto cleanup; } pass = true; cleanup: if (cameraIdList) { ACameraManager_deleteCameraIdList(cameraIdList); } if (mgr) { ACameraManager_delete(mgr); } ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); if (!pass) { throwAssertionError(env, errorString); } return pass; } extern "C" jboolean Java_android_hardware_camera2_cts_NativeCameraManagerTest_\ testCameraManagerCharacteristicsNative( JNIEnv* env, jclass /*clazz*/) { ALOGV("%s", __FUNCTION__); bool pass = false; ACameraManager* mgr = ACameraManager_create(); ACameraIdList *cameraIdList = nullptr; ACameraMetadata* chars = nullptr; int numCameras = 0; camera_status_t ret = ACameraManager_getCameraIdList(mgr, &cameraIdList); if (ret != ACAMERA_OK || cameraIdList == nullptr) { LOG_ERROR(errorString, "Get camera id list failed: ret %d, cameraIdList %p", ret, cameraIdList); goto cleanup; } numCameras = cameraIdList->numCameras; for (int i = 0; i < numCameras; i++) { ret = ACameraManager_getCameraCharacteristics( mgr, cameraIdList->cameraIds[i], &chars); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Get camera characteristics failed: ret %d", ret); goto cleanup; } int32_t numTags = 0; const uint32_t* tags = nullptr; ret = ACameraMetadata_getAllTags(chars, &numTags, &tags); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Get camera characteristics tags failed: ret %d", ret); goto cleanup; } for (int tid = 0; tid < numTags; tid++) { uint32_t tagId = tags[tid]; ALOGV("%s capture request contains key %u", __FUNCTION__, tagId); uint32_t sectionId = tagId >> 16; if (sectionId >= ACAMERA_SECTION_COUNT && sectionId < ACAMERA_VENDOR) { LOG_ERROR(errorString, "Unknown tagId %u, sectionId %u", tagId, sectionId); goto cleanup; } } ACameraMetadata_const_entry entry; ret = ACameraMetadata_getConstEntry(chars, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entry); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Get const available capabilities key failed. ret %d", ret); goto cleanup; } // Check the entry is actually legit if (entry.tag != ACAMERA_REQUEST_AVAILABLE_CAPABILITIES || entry.count == 0 || entry.type != ACAMERA_TYPE_BYTE || entry.data.i32 == nullptr) { LOG_ERROR(errorString, "Bad available capabilities key: tag: %d (expected %d), count %u (expect > 0), " "type %d (expected %d), data %p (expected not null)", entry.tag, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, entry.count, entry.type, ACAMERA_TYPE_BYTE, entry.data.i32); goto cleanup; } // All camera supports BC except depth only cameras bool supportBC = false, supportDepth = false; for (uint32_t i = 0; i < entry.count; i++) { if (entry.data.u8[i] == ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) { supportBC = true; } if (entry.data.u8[i] == ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT) { supportDepth = true; } } if (!(supportBC || supportDepth)) { LOG_ERROR(errorString, "Error: camera device %s does not support either BC or DEPTH", cameraIdList->cameraIds[i]); goto cleanup; } // Check get unknown value fails uint32_t badTag = (uint32_t) ACAMERA_VENDOR_START - 1; ret = ACameraMetadata_getConstEntry(chars, badTag, &entry); if (ret == ACAMERA_OK) { LOG_ERROR(errorString, "Error: get unknown tag should fail!"); goto cleanup; } ACameraMetadata_free(chars); chars = nullptr; } pass = true; cleanup: if (chars) { ACameraMetadata_free(chars); } ACameraManager_deleteCameraIdList(cameraIdList); ACameraManager_delete(mgr); ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); if (!pass) { throwAssertionError(env, errorString); } return pass; } extern "C" jboolean Java_android_hardware_camera2_cts_NativeCameraDeviceTest_\ testCameraDeviceOpenAndCloseNative( JNIEnv* env, jclass /*clazz*/) { ALOGV("%s", __FUNCTION__); int numCameras = 0; bool pass = false; PreviewTestCase testCase; camera_status_t ret = testCase.initWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } numCameras = testCase.getNumCameras(); if (numCameras < 0) { LOG_ERROR(errorString, "Testcase returned negavtive number of cameras: %d", numCameras); goto cleanup; } for (int i = 0; i < numCameras; i++) { const char* cameraId = testCase.getCameraId(i); if (cameraId == nullptr) { LOG_ERROR(errorString, "Testcase returned null camera id for camera %d", i); goto cleanup; } ret = testCase.openCamera(cameraId); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret); goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be unavailable now", cameraId); goto cleanup; } ret = testCase.closeCamera(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Close camera device %s failure. ret %d", cameraId, ret); goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (!testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be available now", cameraId); goto cleanup; } } ret = testCase.deInit(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Testcase deInit failed: ret %d", ret); goto cleanup; } pass = true; cleanup: ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); if (!pass) { throwAssertionError(env, errorString); } return pass; } extern "C" jboolean Java_android_hardware_camera2_cts_NativeCameraDeviceTest_\ testCameraDeviceCreateCaptureRequestNative( JNIEnv* env, jclass /*clazz*/) { ALOGV("%s", __FUNCTION__); bool pass = false; ACameraManager* mgr = ACameraManager_create(); ACameraIdList* cameraIdList = nullptr; ACameraDevice* device = nullptr; ACaptureRequest* request = nullptr; ACameraMetadata* chars = nullptr; camera_status_t ret = ACameraManager_getCameraIdList(mgr, &cameraIdList); int numCameras = cameraIdList->numCameras; for (int i = 0; i < numCameras; i++) { CameraDeviceListener deviceListener; const char* cameraId = cameraIdList->cameraIds[i]; ACameraDevice_StateCallbacks deviceCb { &deviceListener, CameraDeviceListener::onDisconnected, CameraDeviceListener::onError }; ret = ACameraManager_openCamera(mgr, cameraId, &deviceCb, &device); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret); goto cleanup; } ret = ACameraManager_getCameraCharacteristics(mgr, cameraId, &chars); if (ret != ACAMERA_OK || chars == nullptr) { LOG_ERROR(errorString, "Get camera %s characteristics failure. ret %d, chars %p", cameraId, ret, chars); goto cleanup; } StaticInfo staticInfo(chars); for (int t = TEMPLATE_PREVIEW; t <= TEMPLATE_MANUAL; t++) { ACameraDevice_request_template templateId = static_cast<ACameraDevice_request_template>(t); ret = ACameraDevice_createCaptureRequest(device, templateId, &request); if (ret == ACAMERA_ERROR_INVALID_PARAMETER) { // template not supported. skip continue; } if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Create capture request failed!: ret %d", ret); goto cleanup; } int32_t numTags = 0; const uint32_t* tags = nullptr; ret = ACaptureRequest_getAllTags(request, &numTags, &tags); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Get capture request tags failed: ret %d", ret); goto cleanup; } for (int tid = 0; tid < numTags; tid++) { uint32_t tagId = tags[tid]; ALOGV("%s capture request contains key %u", __FUNCTION__, tagId); uint32_t sectionId = tagId >> 16; if (sectionId >= ACAMERA_SECTION_COUNT && sectionId < ACAMERA_VENDOR) { LOG_ERROR(errorString, "Unknown tagId %u, sectionId %u", tagId, sectionId); goto cleanup; } } void* context = nullptr; ret = ACaptureRequest_getUserContext(request, &context); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Get capture request context failed: ret %d", ret); goto cleanup; } if (context != nullptr) { LOG_ERROR(errorString, "Capture request context is not null: %p", context); goto cleanup; } intptr_t magic_num = 0xBEEF; ret = ACaptureRequest_setUserContext(request, (void*) magic_num); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Set capture request context failed: ret %d", ret); goto cleanup; } ret = ACaptureRequest_getUserContext(request, &context); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Get capture request context failed: ret %d", ret); goto cleanup; } if (context != (void*) magic_num) { LOG_ERROR(errorString, "Capture request context is wrong: %p", context); goto cleanup; } // try get/set capture request fields ACameraMetadata_const_entry entry; ret = ACaptureRequest_getConstEntry(request, ACAMERA_CONTROL_AE_MODE, &entry); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Get AE mode key failed. ret %d", ret); goto cleanup; } if (entry.tag != ACAMERA_CONTROL_AE_MODE || entry.type != ACAMERA_TYPE_BYTE ||\ entry.count != 1) { LOG_ERROR(errorString, "Bad AE mode key. tag 0x%x (expect 0x%x), type %d (expect %d), " "count %d (expect %d)", entry.tag, ACAMERA_CONTROL_AE_MODE, entry.type, ACAMERA_TYPE_BYTE, entry.count, 1); goto cleanup; } if (t == TEMPLATE_MANUAL) { if (entry.data.u8[0] != ACAMERA_CONTROL_AE_MODE_OFF) { LOG_ERROR(errorString, "Error: MANUAL template AE mode %d (expect %d)", entry.data.u8[0], ACAMERA_CONTROL_AE_MODE_OFF); goto cleanup; } // try set AE_MODE_ON uint8_t aeMode = ACAMERA_CONTROL_AE_MODE_ON; ret = ACaptureRequest_setEntry_u8( request, ACAMERA_CONTROL_AE_MODE, /*count*/ 1, &aeMode); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Error: Camera %s template %d: update AE mode key fail. ret %d", cameraId, t, ret); goto cleanup; } ret = ACaptureRequest_getConstEntry( request, ACAMERA_CONTROL_AE_MODE, &entry); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Get AE mode key failed. ret %d", ret); goto cleanup; } if (entry.data.u8[0] != aeMode) { LOG_ERROR(errorString, "Error: AE mode key is not updated. expect %d but get %d", aeMode, entry.data.u8[0]); goto cleanup; } } else { if (staticInfo.isColorOutputSupported()) { if (entry.data.u8[0] != ACAMERA_CONTROL_AE_MODE_ON) { LOG_ERROR(errorString, "Error: Template %d has wrong AE mode %d (expect %d)", t, entry.data.u8[0], ACAMERA_CONTROL_AE_MODE_ON); goto cleanup; } // try set AE_MODE_OFF if (staticInfo.isCapabilitySupported( ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { uint8_t aeMode = ACAMERA_CONTROL_AE_MODE_OFF; ret = ACaptureRequest_setEntry_u8( request, ACAMERA_CONTROL_AE_MODE, /*count*/ 1, &aeMode); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Error: Camera %s template %d: update AE mode key fail. ret %d", cameraId, t, ret); goto cleanup; } ret = ACaptureRequest_getConstEntry( request, ACAMERA_CONTROL_AE_MODE, &entry); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Get AE mode key failed. ret %d", ret); goto cleanup; } if (entry.data.u8[0] != aeMode) { LOG_ERROR(errorString, "Error: AE mode key is not updated. expect %d but get %d", aeMode, entry.data.u8[0]); goto cleanup; } } } } ACaptureRequest_free(request); request = nullptr; } ACameraMetadata_free(chars); chars = nullptr; ACameraDevice_close(device); device = nullptr; } pass = true; cleanup: if (cameraIdList) { ACameraManager_deleteCameraIdList(cameraIdList); } if (request) { ACaptureRequest_free(request); } if (chars) { ACameraMetadata_free(chars); } if (device) { ACameraDevice_close(device); } if (mgr) { ACameraManager_delete(mgr); } ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); if (!pass) { throwAssertionError(env, errorString); } return pass; } extern "C" jboolean Java_android_hardware_camera2_cts_NativeCameraDeviceTest_\ testCameraDeviceSessionOpenAndCloseNative( JNIEnv* env, jclass /*clazz*/, jobject jPreviewSurface) { ALOGV("%s", __FUNCTION__); int numCameras = 0; bool pass = false; PreviewTestCase testCase; camera_status_t ret = testCase.initWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } numCameras = testCase.getNumCameras(); if (numCameras < 0) { LOG_ERROR(errorString, "Testcase returned negavtive number of cameras: %d", numCameras); goto cleanup; } for (int i = 0; i < numCameras; i++) { const char* cameraId = testCase.getCameraId(i); if (cameraId == nullptr) { LOG_ERROR(errorString, "Testcase returned null camera id for camera %d", i); goto cleanup; } ret = testCase.openCamera(cameraId); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret); goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be unavailable now", cameraId); goto cleanup; } ANativeWindow* previewAnw = testCase.initPreviewAnw(env, jPreviewSurface); if (previewAnw == nullptr) { LOG_ERROR(errorString, "Null ANW from preview surface!"); goto cleanup; } CaptureSessionListener* sessionListener = testCase.getSessionListener(); if (sessionListener == nullptr) { LOG_ERROR(errorString, "Session listener camera %s is null", cameraId); goto cleanup; } // Try open/close session multiple times for (int j = 0; j < 5; j++) { ret = testCase.createCaptureSessionWithLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (!sessionListener->isIdle()) { LOG_ERROR(errorString, "Session for camera %s should be idle right after creation", cameraId); goto cleanup; } testCase.closeSession(); usleep(100000); // sleep to give some time for callbacks to happen if (!sessionListener->isClosed() || sessionListener->onClosedCount() != 1) { LOG_ERROR(errorString, "Session for camera %s close error. isClosde %d close count %d", cameraId, sessionListener->isClosed(), sessionListener->onClosedCount()); goto cleanup; } sessionListener->reset(); } // Try open/close really fast ret = testCase.createCaptureSessionWithLog(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Create session for camera %s failed. ret %d", cameraId, ret); goto cleanup; } testCase.closeSession(); usleep(100000); // sleep to give some time for callbacks to happen if (!sessionListener->isClosed() || sessionListener->onClosedCount() != 1) { LOG_ERROR(errorString, "Session for camera %s close error. isClosde %d close count %d", cameraId, sessionListener->isClosed(), sessionListener->onClosedCount()); goto cleanup; } ret = testCase.resetWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (!testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be available now", cameraId); goto cleanup; } } ret = testCase.deInit(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Testcase deInit failed: ret %d", ret); goto cleanup; } pass = true; cleanup: ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); if (!pass) { throwAssertionError(env, errorString); } return pass; } extern "C" jboolean Java_android_hardware_camera2_cts_NativeCameraDeviceTest_\ testCameraDeviceSharedOutputUpdate( JNIEnv* env, jclass /*clazz*/, jobject jPreviewSurface, jobject jSharedSurface) { ALOGV("%s", __FUNCTION__); int numCameras = 0; bool pass = false; PreviewTestCase testCase; int sequenceId = -1; int64_t lastFrameNumber = 0; bool frameArrived = false; ANativeWindow* previewAnw = nullptr; ANativeWindow* sharedAnw = ANativeWindow_fromSurface(env, jSharedSurface); ACaptureRequest* updatedRequest = nullptr; ACameraOutputTarget* reqPreviewOutput = nullptr; ACameraOutputTarget* reqSharedOutput = nullptr; ACaptureSessionOutput *previewOutput = nullptr; uint32_t timeoutSec = 1; uint32_t runPreviewSec = 2; camera_status_t ret = testCase.initWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } numCameras = testCase.getNumCameras(); if (numCameras < 0) { LOG_ERROR(errorString, "Testcase returned negavtive number of cameras: %d", numCameras); goto cleanup; } for (int i = 0; i < numCameras; i++) { const char* cameraId = testCase.getCameraId(i); if (cameraId == nullptr) { LOG_ERROR(errorString, "Testcase returned null camera id for camera %d", i); goto cleanup; } ret = testCase.openCamera(cameraId); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret); goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be unavailable now", cameraId); goto cleanup; } previewAnw = testCase.initPreviewAnw(env, jPreviewSurface); if (previewAnw == nullptr) { LOG_ERROR(errorString, "Null ANW from preview surface!"); goto cleanup; } ret = testCase.createCaptureSessionWithLog(true); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } ret = testCase.createRequestsWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } ret = testCase.startPreview(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Start preview failed!"); goto cleanup; } sleep(runPreviewSec); previewOutput = testCase.getPreviewOutput(); //Try some bad input ret = ACaptureSessionSharedOutput_add(previewOutput, previewAnw); if (ret != ACAMERA_ERROR_INVALID_PARAMETER) { LOG_ERROR(errorString, "ACaptureSessionSharedOutput_add should return invalid " "parameter! %d", ret); goto cleanup; } ret = ACaptureSessionSharedOutput_remove(previewOutput, previewAnw); if (ret != ACAMERA_ERROR_INVALID_PARAMETER) { LOG_ERROR(errorString, "ACaptureSessionSharedOutput_remove should return invalid " "parameter! %d", ret); goto cleanup; } //Now try with valid input ret = ACaptureSessionSharedOutput_add(previewOutput, sharedAnw); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "ACaptureSessionSharedOutput_add failed!") goto cleanup; } ret = testCase.updateOutput(env, previewOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Failed to update output configuration!") goto cleanup; } ret = ACameraDevice_createCaptureRequest( testCase.getCameraDevice(), TEMPLATE_PREVIEW, &updatedRequest); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s create preview request failed. ret %d", cameraId, ret); goto cleanup; } ret = ACameraOutputTarget_create(previewAnw, &reqPreviewOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s create request preview output target failed. ret %d", cameraId, ret); goto cleanup; } ret = ACaptureRequest_addTarget(updatedRequest, reqPreviewOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s add preview request output failed. ret %d", cameraId, ret); goto cleanup; } ret = ACameraOutputTarget_create(sharedAnw, &reqSharedOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s create request preview output target failed. ret %d", cameraId, ret); goto cleanup; } ret = ACaptureRequest_addTarget(updatedRequest, reqSharedOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s add preview request output failed. ret %d", cameraId, ret); goto cleanup; } ret = testCase.updateRepeatingRequest(updatedRequest, &sequenceId); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s failed to update repeated request. ret %d", cameraId, ret); goto cleanup; } sleep(runPreviewSec); ret = ACaptureSessionSharedOutput_remove(previewOutput, sharedAnw); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "ACaptureSessionSharedOutput_remove failed!"); goto cleanup; } //Try removing shared output which still has pending camera requests ret = testCase.updateOutput(env, previewOutput); if (ret != ACAMERA_ERROR_INVALID_PARAMETER) { LOG_ERROR(errorString, "updateOutput should fail!"); goto cleanup; } //Remove the shared output correctly by updating the repeating request //first ret = ACaptureRequest_removeTarget(updatedRequest, reqSharedOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s remove target output failed. ret %d", cameraId, ret); goto cleanup; } ret = testCase.updateRepeatingRequest(updatedRequest); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s failed to update repeated request. ret %d", cameraId, ret); goto cleanup; } //Then wait for all old requests to flush lastFrameNumber = testCase.getCaptureSequenceLastFrameNumber(sequenceId, timeoutSec); if (lastFrameNumber < 0) { LOG_ERROR(errorString, "Camera %s failed to acquire last frame number!", cameraId); goto cleanup; } frameArrived = testCase.waitForFrameNumber(lastFrameNumber, timeoutSec); if (!frameArrived) { LOG_ERROR(errorString, "Camera %s timed out waiting on last frame number!", cameraId); goto cleanup; } ret = testCase.updateOutput(env, previewOutput); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "updateOutput failed!"); goto cleanup; } sleep(runPreviewSec); ret = testCase.resetWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (!testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be available now", cameraId); goto cleanup; } } ret = testCase.deInit(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Testcase deInit failed: ret %d", ret); goto cleanup; } pass = true; cleanup: if (updatedRequest != nullptr) { ACaptureRequest_free(updatedRequest); updatedRequest = nullptr; } if (reqPreviewOutput != nullptr) { ACameraOutputTarget_free(reqPreviewOutput); reqPreviewOutput = nullptr; } if (reqSharedOutput != nullptr) { ACameraOutputTarget_free(reqSharedOutput); reqSharedOutput = nullptr; } if (sharedAnw) { ANativeWindow_release(sharedAnw); sharedAnw = nullptr; } ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); if (!pass) { throwAssertionError(env, errorString); } return pass; } extern "C" jboolean Java_android_hardware_camera2_cts_NativeCameraDeviceTest_\ testCameraDeviceSimplePreviewNative( JNIEnv* env, jclass /*clazz*/, jobject jPreviewSurface) { ALOGV("%s", __FUNCTION__); int numCameras = 0; bool pass = false; PreviewTestCase testCase; camera_status_t ret = testCase.initWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } numCameras = testCase.getNumCameras(); if (numCameras < 0) { LOG_ERROR(errorString, "Testcase returned negavtive number of cameras: %d", numCameras); goto cleanup; } for (int i = 0; i < numCameras; i++) { const char* cameraId = testCase.getCameraId(i); if (cameraId == nullptr) { LOG_ERROR(errorString, "Testcase returned null camera id for camera %d", i); goto cleanup; } ret = testCase.openCamera(cameraId); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret); goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be unavailable now", cameraId); goto cleanup; } ANativeWindow* previewAnw = testCase.initPreviewAnw(env, jPreviewSurface); if (previewAnw == nullptr) { LOG_ERROR(errorString, "Null ANW from preview surface!"); goto cleanup; } ret = testCase.createCaptureSessionWithLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } ret = testCase.createRequestsWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } ret = testCase.startPreview(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Start preview failed!"); goto cleanup; } sleep(3); ret = testCase.resetWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (!testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be available now", cameraId); goto cleanup; } } ret = testCase.deInit(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Testcase deInit failed: ret %d", ret); goto cleanup; } pass = true; cleanup: ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); if (!pass) { throwAssertionError(env, errorString); } return pass; } extern "C" jboolean Java_android_hardware_camera2_cts_NativeCameraDeviceTest_\ testCameraDevicePreviewWithSessionParametersNative( JNIEnv* env, jclass /*clazz*/, jobject jPreviewSurface) { ALOGV("%s", __FUNCTION__); int numCameras = 0; bool pass = false; ACameraManager* mgr = ACameraManager_create(); ACameraMetadata* chars = nullptr; PreviewTestCase testCase; camera_status_t ret = testCase.initWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } numCameras = testCase.getNumCameras(); if (numCameras < 0) { LOG_ERROR(errorString, "Testcase returned negavtive number of cameras: %d", numCameras); goto cleanup; } for (int i = 0; i < numCameras; i++) { const char* cameraId = testCase.getCameraId(i); if (cameraId == nullptr) { LOG_ERROR(errorString, "Testcase returned null camera id for camera %d", i); goto cleanup; } ret = ACameraManager_getCameraCharacteristics( mgr, cameraId, &chars); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Get camera characteristics failed: ret %d", ret); goto cleanup; } ACameraMetadata_const_entry sessionParamKeys{}; ret = ACameraMetadata_getConstEntry(chars, ACAMERA_REQUEST_AVAILABLE_SESSION_KEYS, &sessionParamKeys); if ((ret != ACAMERA_OK) || (sessionParamKeys.count == 0)) { ACameraMetadata_free(chars); chars = nullptr; continue; } ret = testCase.openCamera(cameraId); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret); goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be unavailable now", cameraId); goto cleanup; } ANativeWindow* previewAnw = testCase.initPreviewAnw(env, jPreviewSurface); if (previewAnw == nullptr) { LOG_ERROR(errorString, "Null ANW from preview surface!"); goto cleanup; } ret = testCase.createRequestsWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } ACaptureRequest *previewRequest = nullptr; ret = testCase.getPreviewRequest(&previewRequest); if ((ret != ACAMERA_OK) || (previewRequest == nullptr)) { LOG_ERROR(errorString, "Preview request query failed!"); goto cleanup; } ret = testCase.createCaptureSessionWithLog(/*isPreviewShared*/ false, previewRequest); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } ret = testCase.startPreview(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Start preview failed!"); goto cleanup; } sleep(3); ret = testCase.resetWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (!testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be available now", cameraId); goto cleanup; } ACameraMetadata_free(chars); chars = nullptr; } ret = testCase.deInit(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Testcase deInit failed: ret %d", ret); goto cleanup; } pass = true; cleanup: if (chars) { ACameraMetadata_free(chars); } ACameraManager_delete(mgr); ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); if (!pass) { throwAssertionError(env, errorString); } return pass; } bool nativeImageReaderTestBase( JNIEnv* env, jstring jOutPath, AImageReader_ImageCallback cb) { const int NUM_TEST_IMAGES = 10; const int TEST_WIDTH = 640; const int TEST_HEIGHT = 480; media_status_t mediaRet = AMEDIA_ERROR_UNKNOWN; int numCameras = 0; bool pass = false; PreviewTestCase testCase; const char* outPath = (jOutPath == nullptr) ? nullptr : env->GetStringUTFChars(jOutPath, nullptr); if (outPath != nullptr) { ALOGI("%s: out path is %s", __FUNCTION__, outPath); } camera_status_t ret = testCase.initWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } numCameras = testCase.getNumCameras(); if (numCameras < 0) { LOG_ERROR(errorString, "Testcase returned negavtive number of cameras: %d", numCameras); goto cleanup; } for (int i = 0; i < numCameras; i++) { const char* cameraId = testCase.getCameraId(i); if (cameraId == nullptr) { LOG_ERROR(errorString, "Testcase returned null camera id for camera %d", i); goto cleanup; } ret = testCase.openCamera(cameraId); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret); goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be unavailable now", cameraId); goto cleanup; } ImageReaderListener readerListener; AImageReader_ImageListener readerCb { &readerListener, cb }; readerListener.setDumpFilePathBase(outPath); mediaRet = testCase.initImageReaderWithErrorLog( TEST_WIDTH, TEST_HEIGHT, AIMAGE_FORMAT_JPEG, NUM_TEST_IMAGES, &readerCb); if (mediaRet != AMEDIA_OK) { // Don't log error here. testcase did it goto cleanup; } ret = testCase.createCaptureSessionWithLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } ret = testCase.createRequestsWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } CaptureResultListener resultListener; ACameraCaptureSession_captureCallbacks resultCb { &resultListener, CaptureResultListener::onCaptureStart, CaptureResultListener::onCaptureProgressed, CaptureResultListener::onCaptureCompleted, CaptureResultListener::onCaptureFailed, CaptureResultListener::onCaptureSequenceCompleted, CaptureResultListener::onCaptureSequenceAborted, CaptureResultListener::onCaptureBufferLost }; resultListener.setRequestSave(true); ACaptureRequest* requestTemplate = nullptr; ret = testCase.getStillRequest(&requestTemplate); if (ret != ACAMERA_OK || requestTemplate == nullptr) { // Don't log error here. testcase did it goto cleanup; } // Do some still capture int lastSeqId = -1; for (intptr_t capture = 0; capture < NUM_TEST_IMAGES; capture++) { ACaptureRequest* req = ACaptureRequest_copy(requestTemplate); ACaptureRequest_setUserContext(req, (void*) capture); int seqId; ret = testCase.capture(req, &resultCb, &seqId); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s capture(%" PRIdPTR ") failed. ret %d", cameraId, capture, ret); goto cleanup; } if (capture == NUM_TEST_IMAGES - 1) { lastSeqId = seqId; } ACaptureRequest_free(req); } // wait until last sequence complete resultListener.getCaptureSequenceLastFrameNumber(lastSeqId, /*timeoutSec*/ 3); std::vector<ACaptureRequest*> completedRequests; resultListener.getCompletedRequests(&completedRequests); if (completedRequests.size() != NUM_TEST_IMAGES) { LOG_ERROR(errorString, "Camera %s fails to capture %d capture results. Got %zu", cameraId, NUM_TEST_IMAGES, completedRequests.size()); goto cleanup; } for (intptr_t i = 0; i < NUM_TEST_IMAGES; i++) { intptr_t userContext = -1; ret = ACaptureRequest_getUserContext(completedRequests[i], (void**) &userContext); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s fails to get request user context", cameraId); goto cleanup; } if (userContext != i) { LOG_ERROR(errorString, "Camera %s fails to return matching user context. " "Expect %" PRIdPTR ", got %" PRIdPTR, cameraId, i, userContext); goto cleanup; } } // wait until all capture finished for (int i = 0; i < 50; i++) { usleep(100000); // sleep 100ms if (readerListener.onImageAvailableCount() == NUM_TEST_IMAGES) { ALOGI("Session take ~%d ms to capture %d images", i*100, NUM_TEST_IMAGES); break; } } if (readerListener.onImageAvailableCount() != NUM_TEST_IMAGES) { LOG_ERROR(errorString, "Camera %s timeout capturing %d images. Got %d", cameraId, NUM_TEST_IMAGES, readerListener.onImageAvailableCount()); goto cleanup; } ret = testCase.resetWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (!testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be available now", cameraId); goto cleanup; } } ret = testCase.deInit(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Testcase deInit failed: ret %d", ret); goto cleanup; } pass = true; cleanup: if (outPath != nullptr) { env->ReleaseStringUTFChars(jOutPath, outPath); } ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); if (!pass) { throwAssertionError(env, errorString); } return pass; } extern "C" jboolean Java_android_hardware_camera2_cts_NativeImageReaderTest_\ testJpegNative( JNIEnv* env, jclass /*clazz*/, jstring jOutPath) { ALOGV("%s", __FUNCTION__); return nativeImageReaderTestBase(env, jOutPath, ImageReaderListener::validateImageCb); } extern "C" jboolean Java_android_hardware_camera2_cts_NativeImageReaderTest_\ testImageReaderCloseAcquiredImagesNative( JNIEnv* env, jclass /*clazz*/) { ALOGV("%s", __FUNCTION__); return nativeImageReaderTestBase(env, nullptr, ImageReaderListener::acquireImageCb); } extern "C" jboolean Java_android_hardware_camera2_cts_NativeStillCaptureTest_\ testStillCaptureNative( JNIEnv* env, jclass /*clazz*/, jstring jOutPath, jobject jPreviewSurface) { ALOGV("%s", __FUNCTION__); const int NUM_TEST_IMAGES = 10; const int TEST_WIDTH = 640; const int TEST_HEIGHT = 480; media_status_t mediaRet = AMEDIA_ERROR_UNKNOWN; int numCameras = 0; bool pass = false; PreviewTestCase testCase; const char* outPath = env->GetStringUTFChars(jOutPath, nullptr); ALOGI("%s: out path is %s", __FUNCTION__, outPath); camera_status_t ret = testCase.initWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } numCameras = testCase.getNumCameras(); if (numCameras < 0) { LOG_ERROR(errorString, "Testcase returned negavtive number of cameras: %d", numCameras); goto cleanup; } for (int i = 0; i < numCameras; i++) { const char* cameraId = testCase.getCameraId(i); if (cameraId == nullptr) { LOG_ERROR(errorString, "Testcase returned null camera id for camera %d", i); goto cleanup; } ret = testCase.openCamera(cameraId); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Open camera device %s failure. ret %d", cameraId, ret); goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be unavailable now", cameraId); goto cleanup; } ImageReaderListener readerListener; AImageReader_ImageListener readerCb { &readerListener, ImageReaderListener::validateImageCb }; readerListener.setDumpFilePathBase(outPath); mediaRet = testCase.initImageReaderWithErrorLog( TEST_WIDTH, TEST_HEIGHT, AIMAGE_FORMAT_JPEG, NUM_TEST_IMAGES, &readerCb); if (mediaRet != AMEDIA_OK) { // Don't log error here. testcase did it goto cleanup; } ANativeWindow* previewAnw = testCase.initPreviewAnw(env, jPreviewSurface); if (previewAnw == nullptr) { LOG_ERROR(errorString, "Null ANW from preview surface!"); goto cleanup; } ret = testCase.createCaptureSessionWithLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } ret = testCase.createRequestsWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } ret = testCase.startPreview(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Start preview failed!"); goto cleanup; } // Let preview run some time sleep(3); // Do some still capture for (int capture = 0; capture < NUM_TEST_IMAGES; capture++) { ret = testCase.takePicture(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Camera %s capture(%d) failed. ret %d", cameraId, capture, ret); goto cleanup; } } // wait until all capture finished for (int i = 0; i < 50; i++) { usleep(100000); // sleep 100ms if (readerListener.onImageAvailableCount() == NUM_TEST_IMAGES) { ALOGI("Session take ~%d ms to capture %d images", i*100, NUM_TEST_IMAGES); break; } } if (readerListener.onImageAvailableCount() != NUM_TEST_IMAGES) { LOG_ERROR(errorString, "Camera %s timeout capturing %d images. Got %d", cameraId, NUM_TEST_IMAGES, readerListener.onImageAvailableCount()); goto cleanup; } ret = testCase.resetWithErrorLog(); if (ret != ACAMERA_OK) { // Don't log error here. testcase did it goto cleanup; } usleep(100000); // sleep to give some time for callbacks to happen if (!testCase.isCameraAvailable(cameraId)) { LOG_ERROR(errorString, "Camera %s should be available now", cameraId); goto cleanup; } } ret = testCase.deInit(); if (ret != ACAMERA_OK) { LOG_ERROR(errorString, "Testcase deInit failed: ret %d", ret); goto cleanup; } pass = true; cleanup: env->ReleaseStringUTFChars(jOutPath, outPath); ALOGI("%s %s", __FUNCTION__, pass ? "pass" : "failed"); if (!pass) { throwAssertionError(env, errorString); } return pass; }