diff options
| author | 2014-06-19 23:28:06 +0000 | |
|---|---|---|
| committer | 2014-06-19 20:37:59 +0000 | |
| commit | 6e335c44c62c3f735efd333bcf0d459a843f90b8 (patch) | |
| tree | 783f5881cd52f7954bc6185455ec470a1eeab1a9 | |
| parent | 5781fec20a3fd18a696704c8c7875f4df73633ee (diff) | |
| parent | 4c913801141163362dd5bb7c9784c83f69c11054 (diff) | |
Merge "Camera: Implement HAL1 and higher HAL API coexistence"
5 files changed, 234 insertions, 7 deletions
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 0705e0ce8e1b..44fc3b6a8423 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -172,6 +172,11 @@ public class Camera { private static final int NO_ERROR = 0; private static final int EACCESS = -13; private static final int ENODEV = -19; + private static final int EBUSY = -16; + private static final int EINVAL = -22; + private static final int ENOSYS = -38; + private static final int EUSERS = -87; + private static final int EOPNOTSUPP = -95; /** * Broadcast Action: A new picture is taken by the camera, and the entry of @@ -190,6 +195,22 @@ public class Camera { public static final String ACTION_NEW_VIDEO = "android.hardware.action.NEW_VIDEO"; /** + * Camera HAL device API version 1.0 + * @hide + */ + public static final int CAMERA_HAL_API_VERSION_1_0 = 0x100; + + /** + * A constant meaning the normal camera connect/open will be used. + * @hide + */ + public static final int CAMERA_HAL_API_VERSION_NORMAL_OPEN = -2; + + /** + * Used to indicate HAL version un-specified. + */ + private static final int CAMERA_HAL_API_VERSION_UNSPECIFIED = -1; + /** * Hardware face detection. It does not use much CPU. */ private static final int CAMERA_FACE_DETECTION_HW = 0; @@ -331,6 +352,111 @@ public class Camera { return null; } + /** + * Creates a new Camera object to access a particular hardware camera with + * given hal API version. If the same camera is opened by other applications + * or the hal API version is not supported by this device, this will throw a + * RuntimeException. + * <p> + * You must call {@link #release()} when you are done using the camera, + * otherwise it will remain locked and be unavailable to other applications. + * <p> + * Your application should only have one Camera object active at a time for + * a particular hardware camera. + * <p> + * Callbacks from other methods are delivered to the event loop of the + * thread which called open(). If this thread has no event loop, then + * callbacks are delivered to the main application event loop. If there is + * no main application event loop, callbacks are not delivered. + * <p class="caution"> + * <b>Caution:</b> On some devices, this method may take a long time to + * complete. It is best to call this method from a worker thread (possibly + * using {@link android.os.AsyncTask}) to avoid blocking the main + * application UI thread. + * + * @param cameraId The hardware camera to access, between 0 and + * {@link #getNumberOfCameras()}-1. + * @param halVersion The HAL API version this camera device to be opened as. When + * it is {@value #CAMERA_HAL_API_VERSION_NORMAL_OPEN}, the methods will be equivalent + * to {@link #open}, but more detailed error information will be returned to managed code. + * @return a new Camera object, connected, locked and ready for use. + * @throws RuntimeException if opening the camera fails (for example, if the + * camera is in use by another process or device policy manager has disabled + * the camera). + * @see android.app.admin.DevicePolicyManager#getCameraDisabled(android.content.ComponentName) + * + * @hide + */ + public static Camera openLegacy(int cameraId, int halVersion) { + return new Camera(cameraId, halVersion); + } + + /** + * Create a legacy camera object. + * + * @param cameraId The hardware camera to access, between 0 and + * {@link #getNumberOfCameras()}-1. + * @param halVersion The HAL API version this camera device to be opened as. + */ + private Camera(int cameraId, int halVersion) { + int err = cameraInit(cameraId, halVersion); + if (checkInitErrors(err)) { + switch(err) { + case EACCESS: + throw new RuntimeException("Fail to connect to camera service"); + case ENODEV: + throw new RuntimeException("Camera initialization failed"); + case ENOSYS: + throw new RuntimeException("Camera initialization failed because some methods" + + " are not implemented"); + case EOPNOTSUPP: + throw new RuntimeException("Camera initialization failed because the hal" + + " version is not supported by this device"); + case EINVAL: + throw new RuntimeException("Camera initialization failed because the input" + + " arugments are invalid"); + case EBUSY: + throw new RuntimeException("Camera initialization failed because the camera" + + " device was already opened"); + case EUSERS: + throw new RuntimeException("Camera initialization failed because the max" + + " number of camera devices were already opened"); + default: + // Should never hit this. + throw new RuntimeException("Unknown camera error"); + } + } + } + + private int cameraInit(int cameraId, int halVersion) { + // This function should be only called by Camera(int cameraId, int halVersion). + if (halVersion < CAMERA_HAL_API_VERSION_1_0 && + halVersion != CAMERA_HAL_API_VERSION_NORMAL_OPEN) { + throw new IllegalArgumentException("Invalid HAL version " + halVersion); + } + + mShutterCallback = null; + mRawImageCallback = null; + mJpegCallback = null; + mPreviewCallback = null; + mPostviewCallback = null; + mUsingPreviewAllocation = false; + mZoomListener = null; + + Looper looper; + if ((looper = Looper.myLooper()) != null) { + mEventHandler = new EventHandler(this, looper); + } else if ((looper = Looper.getMainLooper()) != null) { + mEventHandler = new EventHandler(this, looper); + } else { + mEventHandler = null; + } + + String packageName = ActivityThread.currentPackageName(); + + return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName); + } + Camera(int cameraId) { int err = cameraInit(cameraId); if (checkInitErrors(err)) { @@ -369,7 +495,8 @@ public class Camera { String packageName = ActivityThread.currentPackageName(); - return native_setup(new WeakReference<Camera>(this), cameraId, packageName); + return native_setup(new WeakReference<Camera>(this), cameraId, + CAMERA_HAL_API_VERSION_UNSPECIFIED, packageName); } /** @@ -396,7 +523,7 @@ public class Camera { release(); } - private native final int native_setup(Object camera_this, int cameraId, + private native final int native_setup(Object camera_this, int cameraId, int halVersion, String packageName); private native final void native_release(); diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl index 31896f55b09f..2bc3dd40a980 100644 --- a/core/java/android/hardware/ICameraService.aidl +++ b/core/java/android/hardware/ICameraService.aidl @@ -74,4 +74,11 @@ interface ICameraService int getLegacyParameters(int cameraId, out String[] parameters); // Determines if a particular API version is supported; see ICameraService.h for version defines int supportsCameraApi(int cameraId, int apiVersion); + + int connectLegacy(ICameraClient client, int cameraId, + int halVersion, + String clientPackageName, + int clientUid, + // Container for an ICamera object + out BinderHolder device); } diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 3a533310ea99..4c9feca6e719 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -466,7 +466,7 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, // connect to camera service static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, - jobject weak_this, jint cameraId, jstring clientPackageName) + jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName) { // Convert jstring to String16 const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL); @@ -474,8 +474,18 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, String16 clientName(rawClientName, rawClientNameLen); env->ReleaseStringChars(clientPackageName, rawClientName); - sp<Camera> camera = Camera::connect(cameraId, clientName, - Camera::USE_CALLING_UID); + sp<Camera> camera; + if (halVersion == ICameraService::CAMERA_HAL_API_VERSION_UNSPECIFIED) { + // Default path: hal version is unspecified, do normal camera open. + camera = Camera::connect(cameraId, clientName, + Camera::USE_CALLING_UID); + } else { + jint status = Camera::connectLegacy(cameraId, halVersion, clientName, + Camera::USE_CALLING_UID, camera); + if (status != NO_ERROR) { + return status; + } + } if (camera == NULL) { return -EACCES; @@ -510,7 +520,6 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, // finalizer is invoked later. static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) { - // TODO: Change to ALOGV ALOGV("release camera"); JNICameraContext* context = NULL; sp<Camera> camera; @@ -891,7 +900,7 @@ static JNINativeMethod camMethods[] = { "(ILandroid/hardware/Camera$CameraInfo;)V", (void*)android_hardware_Camera_getCameraInfo }, { "native_setup", - "(Ljava/lang/Object;ILjava/lang/String;)I", + "(Ljava/lang/Object;IILjava/lang/String;)I", (void*)android_hardware_Camera_native_setup }, { "native_release", "()V", diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java index 7dba21da4c9d..b6bb578fe920 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java @@ -205,6 +205,37 @@ public class CameraBinderTest extends AndroidTestCase { } } + @SmallTest + public void testConnectLegacy() throws Exception { + final int CAMERA_HAL_API_VERSION_1_0 = 0x100; + for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) { + ICamera cameraUser = null; + ICameraClient dummyCallbacks = new DummyCameraClient(); + + String clientPackageName = getContext().getPackageName(); + + BinderHolder holder = new BinderHolder(); + + try { + CameraBinderDecorator.newInstance(mUtils.getCameraService()) + .connectLegacy(dummyCallbacks, cameraId, CAMERA_HAL_API_VERSION_1_0, + clientPackageName, + CameraBinderTestUtils.USE_CALLING_UID, holder); + cameraUser = ICamera.Stub.asInterface(holder.getBinder()); + assertNotNull(String.format("Camera %s was null", cameraId), cameraUser); + + Log.v(TAG, String.format("Camera %s connected as HAL1 legacy device", cameraId)); + } catch (RuntimeException e) { + // Not all camera device support openLegacy. + Log.i(TAG, "Unable to open camera as HAL1 legacy camera device " + e); + } finally { + if (cameraUser != null) { + cameraUser.disconnect(); + } + } + } + } + static class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub { /* diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraOpenTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraOpenTest.java new file mode 100644 index 000000000000..14bbe44c1516 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraOpenTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 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. + */ + +package com.android.mediaframeworktest.unit; + +import android.hardware.Camera; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +/** + * <pre> + * adb shell am instrument \ + * -e class 'com.android.mediaframeworktest.unit.CameraOpenTest' \ + * -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner + * </pre> + */ +public class CameraOpenTest extends junit.framework.TestCase { + private static String TAG = "CameraOpenTest"; + + private Camera mCamera; + + /** + * Test @hide android.hardware.Camera#openLegacy API that cannot be tested in CTS. + */ + @SmallTest + public void testOpenLegacy() { + int nCameras = Camera.getNumberOfCameras(); + for (int id = 0; id < nCameras; id++) { + try { + mCamera.openLegacy(id, Camera.CAMERA_HAL_API_VERSION_1_0); + } catch (RuntimeException e) { + Log.i(TAG, "Unable to open camera as HAL1 legacy camera device " + e); + } finally { + if (mCamera != null) { + mCamera.release(); + } + } + } + } +} |