summaryrefslogtreecommitdiffstats
path: root/camera2/portability/src/com/android/ex
diff options
context:
space:
mode:
authorSol Boucher <solb@google.com>2014-06-09 12:05:13 -0700
committerSol Boucher <solb@google.com>2014-07-08 15:17:16 -0700
commita0842b40441db5332a5290f941021636b1182761 (patch)
treef87677f9a18112b5b8e4bcff2a502c8a416fa70d /camera2/portability/src/com/android/ex
parent858edec400cf5c7cf3171f877f81bbc891fc4bcc (diff)
downloadandroid_frameworks_ex-a0842b40441db5332a5290f941021636b1182761.tar.gz
android_frameworks_ex-a0842b40441db5332a5290f941021636b1182761.tar.bz2
android_frameworks_ex-a0842b40441db5332a5290f941021636b1182761.zip
camera2-portability: Add support for previews using the camera2 API
At the moment, only SurfaceTextures (and not SurfaceViews/SurfaceHolders) are supported. The tests still only cover Stringifier and IntegralStringifier. Change-Id: Ie643c58f8383cd3b9f59c16e0b79239df0ca068d
Diffstat (limited to 'camera2/portability/src/com/android/ex')
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java784
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Capabilities.java383
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java47
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java352
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraCapabilities.java241
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/CameraAgent.java345
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/CameraAgentFactory.java12
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/CameraCapabilities.java104
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/CameraCapabilitiesFactory.java2
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/CameraSettings.java16
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/CameraStateHolder.java10
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/DispatchThread.java2
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/Size.java27
13 files changed, 1723 insertions, 602 deletions
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
new file mode 100644
index 0000000..ec1f794
--- /dev/null
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
@@ -0,0 +1,784 @@
+/*
+ * Copyright (C) 2014 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.ex.camera2.portability;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.view.Surface;
+
+import com.android.ex.camera2.portability.debug.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A class to implement {@link CameraAgent} of the Android camera2 framework.
+ */
+class AndroidCamera2AgentImpl extends CameraAgent {
+ private static final Log.Tag TAG = new Log.Tag("AndCam2AgntImp");
+
+ private final Camera2Handler mCameraHandler;
+ private final HandlerThread mCameraHandlerThread;
+ private final CameraStateHolder mCameraState;
+ private final DispatchThread mDispatchThread;
+ private final CameraManager mCameraManager;
+
+ /**
+ * Number of camera devices. The length of {@code mCameraDevices} does not reveal this
+ * information because that list may contain since-invalidated indices.
+ */
+ private int mNumCameraDevices;
+
+ /**
+ * Transformation between integral camera indices and the {@link java.lang.String} indices used
+ * by the underlying API. Note that devices may disappear because they've been disconnected or
+ * have otherwise gone offline. Because we need to keep the meanings of whatever indices we
+ * expose stable, we cannot simply remove them in such a case; instead, we insert {@code null}s
+ * to invalidate any such indices. Whenever new devices appear, they are appended to the end of
+ * the list, and thereby assigned the lowest index that has never yet been used.
+ */
+ private final List<String> mCameraDevices;
+
+ AndroidCamera2AgentImpl(Context context) {
+ mCameraHandlerThread = new HandlerThread("Camera2 Handler Thread");
+ mCameraHandlerThread.start();
+ mCameraHandler = new Camera2Handler(mCameraHandlerThread.getLooper());
+ mCameraState = new AndroidCamera2StateHolder();
+ mDispatchThread = new DispatchThread(mCameraHandler, mCameraHandlerThread);
+ mDispatchThread.start();
+ mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
+
+ mNumCameraDevices = 0;
+ mCameraDevices = new ArrayList<String>();
+ updateCameraDevices();
+ }
+
+ /**
+ * Updates the camera device index assignments stored in {@link mCameraDevices}, without
+ * reappropriating any currently-assigned index.
+ * @return Whether the operation was successful
+ */
+ private boolean updateCameraDevices() {
+ try {
+ String[] currentCameraDevices = mCameraManager.getCameraIdList();
+ Set<String> currentSet = new HashSet<String>(Arrays.asList(currentCameraDevices));
+
+ // Invalidate the indices assigned to any camera devices that are no longer present
+ for (int index = 0; index < mCameraDevices.size(); ++index) {
+ if (!currentSet.contains(mCameraDevices.get(index))) {
+ mCameraDevices.set(index, null);
+ --mNumCameraDevices;
+ }
+ }
+
+ // Assign fresh indices to any new camera devices
+ currentSet.removeAll(mCameraDevices); // The devices we didn't know about
+ for (String device : currentCameraDevices) {
+ if (currentSet.contains(device)) {
+ mCameraDevices.add(device);
+ ++mNumCameraDevices;
+ }
+ }
+
+ return true;
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Could not get device listing from camera subsystem", ex);
+ return false;
+ }
+ }
+
+ // TODO: Implement
+ @Override
+ public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
+ Handler handler) {}
+
+ // TODO: Implement
+ @Override
+ public void recycle() {}
+
+ // TODO: Some indices may now be invalid; ensure everyone can handle that and update the docs
+ @Override
+ public CameraDeviceInfo getCameraDeviceInfo() {
+ updateCameraDevices();
+ return new AndroidCamera2DeviceInfo(mCameraManager, mCameraDevices.toArray(new String[0]),
+ mNumCameraDevices);
+ }
+
+ @Override
+ protected Handler getCameraHandler() {
+ return mCameraHandler;
+ }
+
+ @Override
+ protected DispatchThread getDispatchThread() {
+ return mDispatchThread;
+ }
+
+ private class Camera2Handler extends HistoryHandler {
+ private CameraOpenCallback mOpenCallback;
+ private int mCameraIndex;
+ private String mCameraId;
+ private CameraDevice mCamera;
+ private AndroidCamera2ProxyImpl mCameraProxy;
+ private CaptureRequest.Builder mPreviewRequestBuilder;
+ private Size mPreviewSize;
+ private Size mPhotoSize;
+ private SurfaceTexture mPreviewTexture;
+ private Surface mPreviewSurface;
+ private CameraCaptureSession mPreviewSession;
+
+ Camera2Handler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(final Message msg) {
+ super.handleMessage(msg);
+ try {
+ switch(msg.what) {
+ case CameraActions.OPEN_CAMERA:
+ case CameraActions.RECONNECT: {
+ CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj;
+ int cameraIndex = msg.arg1;
+
+ if (mCameraState.getState() != AndroidCamera2StateHolder.CAMERA_UNOPENED) {
+ openCallback.onDeviceOpenedAlready(cameraIndex,
+ generateHistoryString(cameraIndex));
+ break;
+ }
+
+ mOpenCallback = openCallback;
+ mCameraIndex = cameraIndex;
+ mCameraId = mCameraDevices.get(mCameraIndex);
+
+ if (mCameraId == null) {
+ mOpenCallback.onCameraDisabled(msg.arg1);
+ break;
+ }
+ mCameraManager.openCamera(mCameraId, mCameraDeviceStateListener, this);
+
+ break;
+ }
+
+ case CameraActions.RELEASE: {
+ if (mCameraState.getState() == AndroidCamera2StateHolder.CAMERA_UNOPENED) {
+ Log.e(TAG, "Ignoring release at inappropriate time");
+ }
+
+ if (mCameraState.getState() ==
+ AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) {
+ closePreviewSession();
+ }
+ if (mCamera != null) {
+ mCamera.close();
+ mCamera = null;
+ }
+ mCameraProxy = null;
+ mPreviewRequestBuilder = null;
+ if (mPreviewSurface != null) {
+ mPreviewSurface.release();
+ mPreviewSurface = null;
+ }
+ mPreviewTexture = null;
+ mPreviewSize = null;
+ mPhotoSize = null;
+ mCameraIndex = 0;
+ mCameraId = null;
+ mCameraState.setState(AndroidCamera2StateHolder.CAMERA_UNOPENED);
+ break;
+ }
+
+ /*case CameraActions.UNLOCK: {
+ break;
+ }
+
+ case CameraActions.LOCK: {
+ break;
+ }*/
+
+ case CameraActions.SET_PREVIEW_TEXTURE_ASYNC: {
+ setPreviewTexture((SurfaceTexture) msg.obj);
+ break;
+ }
+
+ case CameraActions.START_PREVIEW_ASYNC: {
+ if (mCameraState.getState() !=
+ AndroidCamera2StateHolder.CAMERA_PREVIEW_READY ||
+ mPreviewSession == null) {
+ // TODO: Provide better feedback here?
+ Log.e(TAG, "Refusing to start preview at inappropriate time");
+ break;
+ }
+
+ final CameraStartPreviewCallbackForward cbForward =
+ (CameraStartPreviewCallbackForward) msg.obj;
+ CameraCaptureSession.CaptureListener cbDispatcher = null;
+ if (cbForward != null) {
+ cbDispatcher = new CameraCaptureSession.CaptureListener() {
+ @Override
+ public void onCaptureStarted(CameraCaptureSession session,
+ CaptureRequest request,
+ long timestamp) {
+ cbForward.onPreviewStarted();
+ }};
+ }
+ mPreviewSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
+ cbDispatcher/*listener*/, this/*handler*/);
+ mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
+ break;
+ }
+
+ case CameraActions.STOP_PREVIEW: {
+ if (mCameraState.getState() !=
+ AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE ||
+ mPreviewSession == null) {
+ Log.e(TAG, "Refusing to stop preview at inappropriate time");
+ }
+
+ mPreviewSession.stopRepeating();
+ mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
+ break;
+ }
+
+ /*case CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER: {
+ break;
+ }
+
+ case CameraActions.ADD_CALLBACK_BUFFER: {
+ break;
+ }
+
+ case CameraActions.SET_PREVIEW_DISPLAY_ASYNC: {
+ break;
+ }
+
+ case CameraActions.SET_PREVIEW_CALLBACK: {
+ break;
+ }
+
+ case CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK: {
+ break;
+ }
+
+ case CameraActions.SET_PARAMETERS: {
+ break;
+ }
+
+ case CameraActions.GET_PARAMETERS: {
+ break;
+ }
+
+ case CameraActions.REFRESH_PARAMETERS: {
+ break;
+ }*/
+
+ case CameraActions.APPLY_SETTINGS: {
+ CameraSettings settings = (CameraSettings) msg.obj;
+ applyToRequest(settings);
+ break;
+ }
+
+ /*case CameraActions.AUTO_FOCUS: {
+ break;
+ }
+
+ case CameraActions.CANCEL_AUTO_FOCUS: {
+ break;
+ }
+
+ case CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK: {
+ break;
+ }
+
+ case CameraActions.SET_ZOOM_CHANGE_LISTENER: {
+ break;
+ }
+
+ case CameraActions.SET_FACE_DETECTION_LISTENER: {
+ break;
+ }
+
+ case CameraActions.START_FACE_DETECTION: {
+ break;
+ }
+
+ case CameraActions.STOP_FACE_DETECTION: {
+ break;
+ }
+
+ case CameraActions.SET_ERROR_CALLBACK: {
+ break;
+ }
+
+ case CameraActions.ENABLE_SHUTTER_SOUND: {
+ break;
+ }
+
+ case CameraActions.SET_DISPLAY_ORIENTATION: {
+ break;
+ }
+
+ case CameraActions.CAPTURE_PHOTO: {
+ break;
+ }*/
+
+ default: {
+ // TODO: Rephrase once everything has been implemented
+ throw new RuntimeException("Unimplemented CameraProxy message=" + msg.what);
+ }
+ }
+ } catch (final Exception ex) {
+ if (msg.what != CameraActions.RELEASE && mCamera != null) {
+ mCamera.close();
+ mCamera = null;
+ } else if (mCamera == null) {
+ if (msg.what == CameraActions.OPEN_CAMERA) {
+ if (mOpenCallback != null) {
+ mOpenCallback.onDeviceOpenFailure(mCameraIndex,
+ generateHistoryString(mCameraIndex));
+ }
+ } else {
+ Log.w(TAG, "Cannot handle message " + msg.what + ", mCamera is null");
+ }
+ return;
+ }
+
+ if (ex instanceof RuntimeException) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ sCameraExceptionCallback.onCameraException((RuntimeException) ex);
+ }});
+ }
+ }
+ }
+
+ public CameraSettings buildSettings(AndroidCamera2Capabilities caps) {
+ return new AndroidCamera2Settings(caps, mPreviewRequestBuilder, mPreviewSize,
+ mPhotoSize);
+ }
+
+ // TODO: Finish implementation to add support for all settings
+ private void applyToRequest(CameraSettings settings) {
+ // TODO: If invoked when in PREVIEW_READY state, a new preview size will not take effect
+ AndroidCamera2Capabilities.IntegralStringifier intifier =
+ mCameraProxy.getSpecializedCapabilities().getIntegralStringifier();
+ mPreviewSize = settings.getCurrentPreviewSize();
+ mPhotoSize = settings.getCurrentPhotoSize();
+ mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
+ intifier.intify(settings.getCurrentFocusMode()));
+ if (settings.getCurrentFlashMode() != CameraCapabilities.FlashMode.NO_FLASH) {
+ mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,
+ intifier.intify(settings.getCurrentFlashMode()));
+ }
+ if (settings.getCurrentSceneMode() != CameraCapabilities.SceneMode.NO_SCENE_MODE) {
+ mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE,
+ intifier.intify(settings.getCurrentSceneMode()));
+ }
+
+ // If we're already ready to preview, this doesn't regress our state
+ if (mCameraState.getState() != AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) {
+ mCameraState.setState(AndroidCamera2StateHolder.CAMERA_CONFIGURED);
+ }
+ }
+
+ private void setPreviewTexture(SurfaceTexture surfaceTexture) {
+ // TODO: Must be called after providing a .*Settings populated with sizes
+ // TODO: We don't technically offer a selection of sizes tailored to SurfaceTextures!
+
+ // TODO: Handle this error condition with a callback or exception
+ if (mCameraState.getState() != AndroidCamera2StateHolder.CAMERA_CONFIGURED) {
+ Log.e(TAG, "Ignoring texture setting at inappropriate time");
+ return;
+ }
+
+ // Avoid initializing another capture session unless we absolutely have to
+ if (surfaceTexture == mPreviewTexture) {
+ Log.i(TAG, "Optimizing out redundant preview texture setting");
+ return;
+ }
+
+ if (mPreviewSession != null) {
+ closePreviewSession();
+ }
+
+ mPreviewTexture = surfaceTexture;
+ surfaceTexture.setDefaultBufferSize(mPreviewSize.width(), mPreviewSize.height());
+
+ if (mPreviewSurface != null) {
+ mPreviewRequestBuilder.removeTarget(mPreviewSurface);
+ mPreviewSurface.release();
+ }
+ mPreviewSurface = new Surface(surfaceTexture);
+ mPreviewRequestBuilder.addTarget(mPreviewSurface);
+
+ try {
+ mCamera.createCaptureSession(Arrays.asList(mPreviewSurface),
+ mCameraPreviewStateListener, this);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to create camera capture session", ex);
+ }
+ }
+
+ private void closePreviewSession() {
+ try {
+ mPreviewSession.abortCaptures();
+ mPreviewSession = null;
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to close existing camera capture session", ex);
+ }
+ mCameraState.setState(AndroidCamera2StateHolder.CAMERA_CONFIGURED);
+ }
+
+ private CameraDevice.StateListener mCameraDeviceStateListener =
+ new CameraDevice.StateListener() {
+ @Override
+ public void onOpened(CameraDevice camera) {
+ mCamera = camera;
+ if (mOpenCallback != null) {
+ try {
+ CameraCharacteristics props =
+ mCameraManager.getCameraCharacteristics(mCameraId);
+ mCameraProxy = new AndroidCamera2ProxyImpl(mCameraIndex, mCamera,
+ getCameraDeviceInfo().getCharacteristics(mCameraIndex), props);
+ mPreviewRequestBuilder =
+ camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ mCameraState.setState(AndroidCamera2StateHolder.CAMERA_UNCONFIGURED);
+ mOpenCallback.onCameraOpened(mCameraProxy);
+ } catch (CameraAccessException ex) {
+ mOpenCallback.onDeviceOpenFailure(mCameraIndex,
+ generateHistoryString(mCameraIndex));
+ }
+ }
+ }
+
+ @Override
+ public void onDisconnected(CameraDevice camera) {
+ Log.w(TAG, "Camera device '" + mCameraIndex + "' was disconnected");
+ }
+
+ @Override
+ public void onError(CameraDevice camera, int error) {
+ Log.e(TAG, "Camera device '" + mCameraIndex + "' encountered error code '" +
+ error + '\'');
+ if (mOpenCallback != null) {
+ mOpenCallback.onDeviceOpenFailure(mCameraIndex,
+ generateHistoryString(mCameraIndex));
+ }
+ }};
+
+ private CameraCaptureSession.StateListener mCameraPreviewStateListener =
+ new CameraCaptureSession.StateListener() {
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ mPreviewSession = session;
+ mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ // TODO: Invoke a callback
+ Log.e(TAG, "Failed to configure the camera for capture");
+ }};
+ }
+
+ private class AndroidCamera2ProxyImpl extends CameraAgent.CameraProxy {
+ private final int mCameraIndex;
+ private final CameraDevice mCamera;
+ private final CameraDeviceInfo.Characteristics mCharacteristics;
+ private final AndroidCamera2Capabilities mCapabilities;
+
+ public AndroidCamera2ProxyImpl(int cameraIndex, CameraDevice camera,
+ CameraDeviceInfo.Characteristics characteristics,
+ CameraCharacteristics properties) {
+ mCameraIndex = cameraIndex;
+ mCamera = camera;
+ mCharacteristics = characteristics;
+ mCapabilities = new AndroidCamera2Capabilities(properties);
+ }
+
+ // TODO: Implement
+ @Override
+ public android.hardware.Camera getCamera() { return null; }
+
+ @Override
+ public int getCameraId() {
+ return mCameraIndex;
+ }
+
+ @Override
+ public CameraDeviceInfo.Characteristics getCharacteristics() {
+ return mCharacteristics;
+ }
+
+ @Override
+ public CameraCapabilities getCapabilities() {
+ return mCapabilities;
+ }
+
+ private AndroidCamera2Capabilities getSpecializedCapabilities() {
+ return mCapabilities;
+ }
+
+ // TODO: Implement
+ @Override
+ public void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb) {}
+
+ // TODO: Implement
+ @Override
+ public void setOneShotPreviewCallback(Handler handler, CameraPreviewDataCallback cb) {}
+
+ // TODO: Implement
+ @Override
+ public void setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb)
+ {}
+
+ // TODO: Implement
+ @Override
+ public void autoFocus(Handler handler, CameraAFCallback cb) {}
+
+ // TODO: Remove this method override once we handle this message
+ @Override
+ public void cancelAutoFocus() {}
+
+ // TODO: Implement
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+ @Override
+ public void setAutoFocusMoveCallback(Handler handler, CameraAFMoveCallback cb) {}
+
+ // TODO: Implement
+ @Override
+ public void takePicture(Handler handler,
+ CameraShutterCallback shutter,
+ CameraPictureCallback raw,
+ CameraPictureCallback postview,
+ CameraPictureCallback jpeg) {}
+
+ // TODO: Remove this method override once we handle the message
+ @Override
+ public void setDisplayOrientation(int degrees) {}
+
+ // TODO: Implement
+ @Override
+ public void setZoomChangeListener(android.hardware.Camera.OnZoomChangeListener listener) {}
+
+ // TODO: Implement
+ @Override
+ public void setFaceDetectionCallback(Handler handler, CameraFaceDetectionCallback callback)
+ {}
+
+ // TODO: Remove this method override once we handle this message
+ @Override
+ public void startFaceDetection() {}
+
+ // TODO: Implement
+ @Override
+ public void setErrorCallback(Handler handler, CameraErrorCallback cb) {}
+
+ // TODO: Implement
+ @Override
+ public void setParameters(android.hardware.Camera.Parameters params) {}
+
+ // TODO: Implement
+ @Override
+ public android.hardware.Camera.Parameters getParameters() { return null; }
+
+ @Override
+ public CameraSettings getSettings() {
+ return mCameraHandler.buildSettings(mCapabilities);
+ }
+
+ @Override
+ public boolean applySettings(CameraSettings settings) {
+ return applySettingsHelper(settings, AndroidCamera2StateHolder.CAMERA_UNCONFIGURED |
+ AndroidCamera2StateHolder.CAMERA_CONFIGURED |
+ AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
+ }
+
+ // TODO: Implement
+ @Override
+ public String dumpDeviceSettings() { return null; }
+
+ @Override
+ public Handler getCameraHandler() {
+ return AndroidCamera2AgentImpl.this.getCameraHandler();
+ }
+
+ @Override
+ public DispatchThread getDispatchThread() {
+ return AndroidCamera2AgentImpl.this.getDispatchThread();
+ }
+
+ @Override
+ public CameraStateHolder getCameraState() {
+ return mCameraState;
+ }
+ }
+
+ private static class AndroidCamera2StateHolder extends CameraStateHolder {
+ // Usage flow: openCamera() -> applySettings() -> setPreviewTexture() -> startPreview()
+ /* Camera states */
+ /** No camera device is opened. */
+ public static final int CAMERA_UNOPENED = 1;
+ /** A camera is opened, but no settings have been provided. */
+ public static final int CAMERA_UNCONFIGURED = 2;
+ /** The open camera has been configured by providing it with settings. */
+ public static final int CAMERA_CONFIGURED = 3;
+ /** A capture session is ready to stream a preview, but still has no repeating request. */
+ public static final int CAMERA_PREVIEW_READY = 4;
+ /** A preview is currently being streamed. */
+ public static final int CAMERA_PREVIEW_ACTIVE = 5;
+
+ private int mState;
+
+ public AndroidCamera2StateHolder() {
+ this(CAMERA_UNOPENED);
+ }
+
+ public AndroidCamera2StateHolder(int state) {
+ setState(state);
+ }
+
+ @Override
+ public synchronized void setState(int state) {
+ mState = state;
+ this.notifyAll();
+ }
+
+ @Override
+ public synchronized int getState() {
+ return mState;
+ }
+ }
+
+ private static class AndroidCamera2DeviceInfo implements CameraDeviceInfo {
+ private final CameraManager mCameraManager;
+ private final String[] mCameraIds;
+ private final int mNumberOfCameras;
+ private final int mFirstBackCameraId;
+ private final int mFirstFrontCameraId;
+
+ public AndroidCamera2DeviceInfo(CameraManager cameraManager,
+ String[] cameraIds, int numberOfCameras) {
+ mCameraManager = cameraManager;
+ mCameraIds = cameraIds;
+ mNumberOfCameras = numberOfCameras;
+
+ int firstBackId = NO_DEVICE;
+ int firstFrontId = NO_DEVICE;
+ for (int id = 0; id < cameraIds.length; ++id) {
+ try {
+ int lensDirection = cameraManager.getCameraCharacteristics(cameraIds[id])
+ .get(CameraCharacteristics.LENS_FACING);
+ if (firstBackId == NO_DEVICE &&
+ lensDirection == CameraCharacteristics.LENS_FACING_BACK) {
+ firstBackId = id;
+ }
+ if (firstFrontId == NO_DEVICE &&
+ lensDirection == CameraCharacteristics.LENS_FACING_FRONT) {
+ firstFrontId = id;
+ }
+ } catch (CameraAccessException ex) {
+ Log.w(TAG, "Couldn't get characteristics of camera '" + id + "'", ex);
+ }
+ }
+ mFirstBackCameraId = firstBackId;
+ mFirstFrontCameraId = firstFrontId;
+ }
+
+ @Override
+ public Characteristics getCharacteristics(int cameraId) {
+ String actualId = mCameraIds[cameraId];
+ try {
+ CameraCharacteristics info = mCameraManager.getCameraCharacteristics(actualId);
+ return new AndroidCharacteristics2(info);
+ } catch (CameraAccessException ex) {
+ return null;
+ }
+ }
+
+ @Override
+ public int getNumberOfCameras() {
+ return mNumberOfCameras;
+ }
+
+ @Override
+ public int getFirstBackCameraId() {
+ return mFirstBackCameraId;
+ }
+
+ @Override
+ public int getFirstFrontCameraId() {
+ return mFirstFrontCameraId;
+ }
+
+ private static class AndroidCharacteristics2 implements Characteristics {
+ private CameraCharacteristics mCameraInfo;
+
+ AndroidCharacteristics2(CameraCharacteristics cameraInfo) {
+ mCameraInfo = cameraInfo;
+ }
+
+ @Override
+ public boolean isFacingBack() {
+ return mCameraInfo.get(CameraCharacteristics.LENS_FACING)
+ .equals(CameraCharacteristics.LENS_FACING_BACK);
+ }
+
+ @Override
+ public boolean isFacingFront() {
+ return mCameraInfo.get(CameraCharacteristics.LENS_FACING)
+ .equals(CameraCharacteristics.LENS_FACING_FRONT);
+ }
+
+ @Override
+ public int getSensorOrientation() {
+ return mCameraInfo.get(CameraCharacteristics.SENSOR_ORIENTATION);
+ }
+
+ @Override
+ public boolean canDisableShutterSound() {
+ // The new API doesn't support this operation, so don't encourage people to try it.
+ // TODO: What kind of assumptions have callers made about this result's meaning?
+ return false;
+ }
+ }
+ }
+
+ private static final CameraExceptionCallback sCameraExceptionCallback =
+ new CameraExceptionCallback() {
+ @Override
+ public synchronized void onCameraException(RuntimeException e) {
+ throw e;
+ }
+ };
+}
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Capabilities.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Capabilities.java
new file mode 100644
index 0000000..03c9ba6
--- /dev/null
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Capabilities.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2014 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.ex.camera2.portability;
+
+import static android.hardware.camera2.CameraCharacteristics.*;
+
+import android.graphics.Point;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.ImageReader;
+import android.media.MediaRecorder;
+import android.util.Range;
+import android.util.Rational;
+import android.view.SurfaceHolder;
+
+import com.android.ex.camera2.portability.debug.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * The subclass of {@link CameraCapabilities} for Android Camera 2 API.
+ */
+public class AndroidCamera2Capabilities extends CameraCapabilities {
+ private static Log.Tag TAG = new Log.Tag("AndCam2Capabs");
+
+ private IntegralStringifier mIntStringifier;
+
+ AndroidCamera2Capabilities(CameraCharacteristics p) {
+ super(new IntegralStringifier());
+ mIntStringifier = (IntegralStringifier) getStringifier();
+
+ StreamConfigurationMap s = p.get(SCALER_STREAM_CONFIGURATION_MAP);
+
+ for (Range<Integer> fpsRange : p.get(CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES)) {
+ mSupportedPreviewFpsRange.add(new int[] { fpsRange.getLower(), fpsRange.getUpper() });
+ }
+
+ // TODO: We only support SurfaceView preview rendering
+ mSupportedPreviewSizes.addAll(Size.buildListFromAndroidSizes(Arrays.asList(
+ s.getOutputSizes(SurfaceHolder.class))));
+ for (int format : s.getOutputFormats()) {
+ mSupportedPreviewFormats.add(format);
+ }
+
+ // TODO: We only support MediaRecorder videos capture
+ mSupportedVideoSizes.addAll(Size.buildListFromAndroidSizes(Arrays.asList(
+ s.getOutputSizes(MediaRecorder.class))));
+
+ // TODO: We only support ImageReader image capture
+ mSupportedPhotoSizes.addAll(Size.buildListFromAndroidSizes(Arrays.asList(
+ s.getOutputSizes(ImageReader.class))));
+ mSupportedPhotoFormats.addAll(mSupportedPreviewFormats);
+
+ buildSceneModes(p);
+ buildFlashModes(p);
+ buildFocusModes(p);
+ buildWhiteBalances(p);
+ // TODO: Populate mSupportedFeatures
+
+ // TODO: Populate mPreferredPreviewSizeForVideo
+
+ Range<Integer> ecRange = p.get(CONTROL_AE_COMPENSATION_RANGE);
+ mMinExposureCompensation = ecRange.getLower();
+ mMaxExposureCompensation = ecRange.getUpper();
+
+ Rational ecStep = p.get(CONTROL_AE_COMPENSATION_STEP);
+ mExposureCompensationStep = (float) ecStep.getNumerator() / ecStep.getDenominator();
+
+ mMaxNumOfFacesSupported = p.get(STATISTICS_INFO_MAX_FACE_COUNT);
+ mMaxNumOfFocusAreas = p.get(CONTROL_MAX_REGIONS_AF);
+ mMaxNumOfMeteringArea = p.get(CONTROL_MAX_REGIONS_AE);
+
+ // TODO: Populate mMaxZoomRatio
+ // TODO: Populate mHorizontalViewAngle
+ // TODO: Populate mVerticalViewAngle
+ // TODO: Populate mZoomRatioList
+ // TODO: Populate mMaxZoomIndex
+ }
+
+ public IntegralStringifier getIntegralStringifier() {
+ return mIntStringifier;
+ }
+
+ private void buildSceneModes(CameraCharacteristics p) {
+ for (int scene : p.get(CONTROL_AVAILABLE_SCENE_MODES)) {
+ SceneMode equiv = mIntStringifier.sceneModeFromInt(scene);
+ if (equiv != SceneMode.NO_SCENE_MODE) {
+ // equiv isn't a default generated because we couldn't handle this mode, so add it
+ mSupportedSceneModes.add(equiv);
+ }
+ }
+ }
+
+ private void buildFlashModes(CameraCharacteristics p) {
+ mSupportedFlashModes.add(FlashMode.OFF);
+ if (p.get(FLASH_INFO_AVAILABLE)) {
+ mSupportedFlashModes.add(FlashMode.ON);
+ mSupportedFlashModes.add(FlashMode.TORCH);
+ // TODO: New modes aren't represented here
+ }
+ }
+
+ private void buildFocusModes(CameraCharacteristics p) {
+ for (int focus : p.get(CONTROL_AF_AVAILABLE_MODES)) {
+ FocusMode equiv = mIntStringifier.focusModeFromInt(focus);
+ if (equiv != FocusMode.AUTO || focus == CONTROL_AF_MODE_AUTO) {
+ // equiv isn't a default generated because we couldn't handle this mode, so add it
+ mSupportedFocusModes.add(equiv);
+ }
+ }
+ }
+
+ private void buildWhiteBalances(CameraCharacteristics p) {
+ for (int bal : p.get(CONTROL_AWB_AVAILABLE_MODES)) {
+ WhiteBalance equiv = mIntStringifier.whiteBalanceFromInt(bal);
+ if (equiv != WhiteBalance.AUTO || bal == CONTROL_AWB_MODE_AUTO) {
+ // equiv isn't a default generated because we couldn't handle this mode, so add it
+ mSupportedWhiteBalances.add(equiv);
+ }
+ }
+ }
+
+ public static class IntegralStringifier extends Stringifier {
+ /**
+ * Converts the focus mode to API-related integer representation.
+ *
+ * @param fm The focus mode to convert.
+ * @return The corresponding {@code int} used by the camera framework
+ * API, or {@link CONTROL_AF_MODE_AUTO} if that fails.
+ */
+ public int intify(FocusMode fm) {
+ switch (fm) {
+ case AUTO:
+ return CONTROL_AF_MODE_AUTO;
+ case CONTINUOUS_PICTURE:
+ return CONTROL_AF_MODE_CONTINUOUS_PICTURE;
+ case CONTINUOUS_VIDEO:
+ return CONTROL_AF_MODE_CONTINUOUS_VIDEO;
+ case EXTENDED_DOF:
+ return CONTROL_AF_MODE_EDOF;
+ case FIXED:
+ return CONTROL_AF_MODE_OFF;
+ case MACRO:
+ return CONTROL_AF_MODE_MACRO;
+ // TODO: New modes aren't represented here
+ }
+ return CONTROL_AF_MODE_AUTO;
+ }
+
+ /**
+ * Converts the API-related integer representation of the focus mode to
+ * the abstract representation.
+ *
+ * @param val The integral representation.
+ * @return The mode represented by the input integer, or the focus mode
+ * with the lowest ordinal if it cannot be converted.
+ */
+ public FocusMode focusModeFromInt(int fm) {
+ switch (fm) {
+ case CONTROL_AF_MODE_AUTO:
+ return FocusMode.AUTO;
+ case CONTROL_AF_MODE_CONTINUOUS_PICTURE:
+ return FocusMode.CONTINUOUS_PICTURE;
+ case CONTROL_AF_MODE_CONTINUOUS_VIDEO:
+ return FocusMode.CONTINUOUS_VIDEO;
+ case CONTROL_AF_MODE_EDOF:
+ return FocusMode.EXTENDED_DOF;
+ case CONTROL_AF_MODE_OFF:
+ return FocusMode.FIXED;
+ case CONTROL_AF_MODE_MACRO:
+ return FocusMode.MACRO;
+ // TODO: New modes aren't represented here
+ }
+ return FocusMode.values()[0];
+ }
+
+ /**
+ * Converts the flash mode to API-related integer representation.
+ *
+ * @param fm The flash mode to convert.
+ * @return The corresponding {@code int} used by the camera framework
+ * API, or {@link CONTROL_AF_MODE_AUTO} if that fails.
+ */
+ public int intify(FlashMode flm) {
+ switch (flm) {
+ case OFF:
+ return FLASH_MODE_OFF;
+ case ON:
+ return FLASH_MODE_SINGLE;
+ case TORCH:
+ return FLASH_MODE_TORCH;
+ // TODO: New modes aren't represented here
+ }
+ return FLASH_MODE_OFF;
+ }
+
+ /**
+ * Converts the API-related integer representation of the flash mode to
+ * the abstract representation.
+ *
+ * @param flm The integral representation.
+ * @return The mode represented by the input integer, or the flash mode
+ * with the lowest ordinal if it cannot be converted.
+ */
+ public FlashMode flashModeFromInt(int flm) {
+ switch (flm) {
+ case FLASH_MODE_OFF:
+ return FlashMode.OFF;
+ case FLASH_MODE_SINGLE:
+ return FlashMode.ON;
+ case FLASH_MODE_TORCH:
+ return FlashMode.TORCH;
+ // TODO: New modes aren't represented here
+ }
+ return FlashMode.values()[0];
+ }
+
+ /**
+ * Converts the scene mode to API-related integer representation.
+ *
+ * @param fm The scene mode to convert.
+ * @return The corresponding {@code int} used by the camera framework
+ * API, or {@link CONTROL_SCENE_MODE_DISABLED} if that fails.
+ */
+ public int intify(SceneMode sm) {
+ switch (sm) {
+ case AUTO:
+ return CONTROL_SCENE_MODE_DISABLED;
+ case ACTION:
+ return CONTROL_SCENE_MODE_ACTION;
+ case BARCODE:
+ return CONTROL_SCENE_MODE_BARCODE;
+ case BEACH:
+ return CONTROL_SCENE_MODE_BEACH;
+ case CANDLELIGHT:
+ return CONTROL_SCENE_MODE_CANDLELIGHT;
+ case FIREWORKS:
+ return CONTROL_SCENE_MODE_FIREWORKS;
+ case LANDSCAPE:
+ return CONTROL_SCENE_MODE_LANDSCAPE;
+ case NIGHT:
+ return CONTROL_SCENE_MODE_NIGHT;
+ case PARTY:
+ return CONTROL_SCENE_MODE_PARTY;
+ case PORTRAIT:
+ return CONTROL_SCENE_MODE_PORTRAIT;
+ case SNOW:
+ return CONTROL_SCENE_MODE_SNOW;
+ case SPORTS:
+ return CONTROL_SCENE_MODE_SPORTS;
+ case STEADYPHOTO:
+ return CONTROL_SCENE_MODE_STEADYPHOTO;
+ case SUNSET:
+ return CONTROL_SCENE_MODE_SUNSET;
+ case THEATRE:
+ return CONTROL_SCENE_MODE_THEATRE;
+ // TODO: New modes aren't represented here
+ }
+ return CONTROL_SCENE_MODE_DISABLED;
+ }
+
+ /**
+ * Converts the API-related integer representation of the scene mode to
+ * the abstract representation.
+ *
+ * @param sm The integral representation.
+ * @return The mode represented by the input integer, or the scene mode
+ * with the lowest ordinal if it cannot be converted.
+ */
+ public SceneMode sceneModeFromInt(int sm) {
+ switch (sm) {
+ case CONTROL_SCENE_MODE_DISABLED:
+ return SceneMode.AUTO;
+ case CONTROL_SCENE_MODE_ACTION:
+ return SceneMode.ACTION;
+ case CONTROL_SCENE_MODE_BARCODE:
+ return SceneMode.BARCODE;
+ case CONTROL_SCENE_MODE_BEACH:
+ return SceneMode.BEACH;
+ case CONTROL_SCENE_MODE_CANDLELIGHT:
+ return SceneMode.CANDLELIGHT;
+ case CONTROL_SCENE_MODE_FIREWORKS:
+ return SceneMode.FIREWORKS;
+ case CONTROL_SCENE_MODE_LANDSCAPE:
+ return SceneMode.LANDSCAPE;
+ case CONTROL_SCENE_MODE_NIGHT:
+ return SceneMode.NIGHT;
+ case CONTROL_SCENE_MODE_PARTY:
+ return SceneMode.PARTY;
+ case CONTROL_SCENE_MODE_PORTRAIT:
+ return SceneMode.PORTRAIT;
+ case CONTROL_SCENE_MODE_SNOW:
+ return SceneMode.SNOW;
+ case CONTROL_SCENE_MODE_SPORTS:
+ return SceneMode.SPORTS;
+ case CONTROL_SCENE_MODE_STEADYPHOTO:
+ return SceneMode.STEADYPHOTO;
+ case CONTROL_SCENE_MODE_SUNSET:
+ return SceneMode.SUNSET;
+ case CONTROL_SCENE_MODE_THEATRE:
+ return SceneMode.THEATRE;
+ // TODO: New modes aren't represented here
+ }
+ return SceneMode.values()[0];
+ }
+
+ /**
+ * Converts the white balance to API-related integer representation.
+ *
+ * @param fm The white balance to convert.
+ * @return The corresponding {@code int} used by the camera framework
+ * API, or {@link CONTROL_SCENE_MODE_DISABLED} if that fails.
+ */
+ public int intify(WhiteBalance wb) {
+ switch (wb) {
+ case AUTO:
+ return CONTROL_AWB_MODE_AUTO;
+ case CLOUDY_DAYLIGHT:
+ return CONTROL_AWB_MODE_CLOUDY_DAYLIGHT;
+ case DAYLIGHT:
+ return CONTROL_AWB_MODE_DAYLIGHT;
+ case FLUORESCENT:
+ return CONTROL_AWB_MODE_FLUORESCENT;
+ case INCANDESCENT:
+ return CONTROL_AWB_MODE_INCANDESCENT;
+ case SHADE:
+ return CONTROL_AWB_MODE_SHADE;
+ case TWILIGHT:
+ return CONTROL_AWB_MODE_TWILIGHT;
+ case WARM_FLUORESCENT:
+ return CONTROL_AWB_MODE_WARM_FLUORESCENT;
+ // TODO: New modes aren't represented here
+ }
+ return CONTROL_AWB_MODE_AUTO;
+ }
+
+ /**
+ * Converts the API-related integer representation of the white balance
+ * to the abstract representation.
+ *
+ * @param wb The integral representation.
+ * @return The balance represented by the input integer, or the white
+ * balance with the lowest ordinal if it cannot be converted.
+ */
+ public WhiteBalance whiteBalanceFromInt(int wb) {
+ switch (wb) {
+ case CONTROL_AWB_MODE_AUTO:
+ return WhiteBalance.AUTO;
+ case CONTROL_AWB_MODE_CLOUDY_DAYLIGHT:
+ return WhiteBalance.CLOUDY_DAYLIGHT;
+ case CONTROL_AWB_MODE_DAYLIGHT:
+ return WhiteBalance.DAYLIGHT;
+ case CONTROL_AWB_MODE_FLUORESCENT:
+ return WhiteBalance.FLUORESCENT;
+ case CONTROL_AWB_MODE_INCANDESCENT:
+ return WhiteBalance.INCANDESCENT;
+ case CONTROL_AWB_MODE_SHADE:
+ return WhiteBalance.SHADE;
+ case CONTROL_AWB_MODE_TWILIGHT:
+ return WhiteBalance.TWILIGHT;
+ case CONTROL_AWB_MODE_WARM_FLUORESCENT:
+ return WhiteBalance.WARM_FLUORESCENT;
+ // TODO: New modes aren't represented here
+ }
+ return WhiteBalance.values()[0];
+ }
+ }
+}
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java
new file mode 100644
index 0000000..e21e177
--- /dev/null
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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.ex.camera2.portability;
+
+import android.hardware.camera2.CaptureRequest;
+
+/**
+ * The subclass of {@link CameraSettings} for Android Camera 2 API.
+ */
+public class AndroidCamera2Settings extends CameraSettings {
+ // TODO: Implement more completely
+ public AndroidCamera2Settings(AndroidCamera2Capabilities capabilities,
+ CaptureRequest.Builder request,
+ Size preview, Size photo) {
+ // TODO: Support zoom
+ setZoomRatio(1.0f);
+ setZoomIndex(0);
+
+ // TODO: Set exposure compensation
+
+ AndroidCamera2Capabilities.IntegralStringifier stringifier =
+ capabilities.getIntegralStringifier();
+ setFocusMode(stringifier.focusModeFromInt(request.get(CaptureRequest.CONTROL_AF_MODE)));
+ setFlashMode(stringifier.flashModeFromInt(request.get(CaptureRequest.FLASH_MODE)));
+ setSceneMode(stringifier.sceneModeFromInt(request.get(CaptureRequest.CONTROL_SCENE_MODE)));
+
+ // This is mutability-safe because those setters copy the Size objects
+ setPreviewSize(preview);
+ setPhotoSize(photo);
+
+ // TODO: Initialize formats, too
+ }
+}
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java
index 7388519..328c8f4 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java
@@ -43,8 +43,8 @@ import java.util.StringTokenizer;
/**
* A class to implement {@link CameraAgent} of the Android camera framework.
*/
-class AndroidCameraAgentImpl implements CameraAgent {
- private static final Log.Tag TAG = new Log.Tag("AndroidCamMgrImpl");
+class AndroidCameraAgentImpl extends CameraAgent {
+ private static final Log.Tag TAG = new Log.Tag("AndCamAgntImp");
private Parameters mParameters;
private boolean mParametersIsDirty;
@@ -70,7 +70,7 @@ class AndroidCameraAgentImpl implements CameraAgent {
mCameraHandlerThread.start();
mCameraHandler = new CameraHandler(mCameraHandlerThread.getLooper());
mCameraExceptionCallbackHandler = mCameraHandler;
- mCameraState = new CameraStateHolder();
+ mCameraState = new AndroidCameraStateHolder();
mDispatchThread = new DispatchThread(mCameraHandler, mCameraHandlerThread);
mDispatchThread.start();
}
@@ -95,6 +95,16 @@ class AndroidCameraAgentImpl implements CameraAgent {
return AndroidCameraDeviceInfo.create();
}
+ @Override
+ protected Handler getCameraHandler() {
+ return mCameraHandler;
+ }
+
+ @Override
+ protected DispatchThread getDispatchThread() {
+ return mDispatchThread;
+ }
+
private static class AndroidCameraDeviceInfo implements CameraDeviceInfo {
private final Camera.CameraInfo[] mCameraInfos;
private final int mNumberOfCameras;
@@ -289,7 +299,7 @@ class AndroidCameraAgentImpl implements CameraAgent {
case CameraActions.OPEN_CAMERA: {
final CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj;
final int cameraId = msg.arg1;
- if (mCameraState.getState() != CameraStateHolder.CAMERA_UNOPENED) {
+ if (mCameraState.getState() != AndroidCameraStateHolder.CAMERA_UNOPENED) {
openCallback.onDeviceOpenedAlready(cameraId, generateHistoryString(cameraId));
break;
}
@@ -305,7 +315,7 @@ class AndroidCameraAgentImpl implements CameraAgent {
AndroidCameraDeviceInfo.create().getCharacteristics(cameraId);
mCapabilities = new AndroidCameraCapabilities(mParamsToSet);
- mCameraState.setState(CameraStateHolder.CAMERA_IDLE);
+ mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE);
if (openCallback != null) {
openCallback.onCameraOpened(
new AndroidCameraProxyImpl(cameraId, mCamera,
@@ -322,7 +332,7 @@ class AndroidCameraAgentImpl implements CameraAgent {
case CameraActions.RELEASE: {
if (mCamera != null) {
mCamera.release();
- mCameraState.setState(CameraStateHolder.CAMERA_UNOPENED);
+ mCameraState.setState(AndroidCameraStateHolder.CAMERA_UNOPENED);
mCamera = null;
} else {
Log.w(TAG, "Releasing camera without any camera opened.");
@@ -344,7 +354,7 @@ class AndroidCameraAgentImpl implements CameraAgent {
break;
}
- mCameraState.setState(CameraStateHolder.CAMERA_IDLE);
+ mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE);
if (cbForward != null) {
cbForward.onCameraOpened(
new AndroidCameraProxyImpl(cameraId, mCamera, mCharacteristics,
@@ -355,13 +365,13 @@ class AndroidCameraAgentImpl implements CameraAgent {
case CameraActions.UNLOCK: {
mCamera.unlock();
- mCameraState.setState(CameraStateHolder.CAMERA_UNLOCKED);
+ mCameraState.setState(AndroidCameraStateHolder.CAMERA_UNLOCKED);
break;
}
case CameraActions.LOCK: {
mCamera.lock();
- mCameraState.setState(CameraStateHolder.CAMERA_IDLE);
+ mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE);
break;
}
@@ -410,14 +420,14 @@ class AndroidCameraAgentImpl implements CameraAgent {
}
case CameraActions.AUTO_FOCUS: {
- mCameraState.setState(CameraStateHolder.CAMERA_FOCUSING);
+ mCameraState.setState(AndroidCameraStateHolder.CAMERA_FOCUSING);
mCamera.autoFocus((AutoFocusCallback) msg.obj);
break;
}
case CameraActions.CANCEL_AUTO_FOCUS: {
mCamera.cancelAutoFocus();
- mCameraState.setState(CameraStateHolder.CAMERA_IDLE);
+ mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE);
break;
}
@@ -495,7 +505,7 @@ class AndroidCameraAgentImpl implements CameraAgent {
}
case CameraActions.CAPTURE_PHOTO: {
- mCameraState.setState(CameraStateHolder.CAMERA_CAPTURING);
+ mCameraState.setState(AndroidCameraStateHolder.CAMERA_CAPTURING);
capture((CaptureCallbacks) msg.obj);
break;
}
@@ -508,7 +518,7 @@ class AndroidCameraAgentImpl implements CameraAgent {
if (msg.what != CameraActions.RELEASE && mCamera != null) {
try {
mCamera.release();
- mCameraState.setState(CameraStateHolder.CAMERA_UNOPENED);
+ mCameraState.setState(AndroidCameraStateHolder.CAMERA_UNOPENED);
} catch (Exception ex) {
Log.e(TAG, "Fail to release the camera.");
}
@@ -608,46 +618,11 @@ class AndroidCameraAgentImpl implements CameraAgent {
}
}
- @Override
- public void openCamera(final Handler handler, final int cameraId,
- final CameraOpenCallback callback) {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.obtainMessage(CameraActions.OPEN_CAMERA, cameraId, 0,
- CameraOpenCallbackForward.getNewInstance(handler, callback)).sendToTarget();
- }
- });
- }
-
- @Override
- public void closeCamera(CameraProxy camera, boolean synced) {
- if (synced) {
- final WaitDoneBundle bundle = new WaitDoneBundle();
-
- mDispatchThread.runJobSync(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.obtainMessage(CameraActions.RELEASE).sendToTarget();
- mCameraHandler.post(bundle.mUnlockRunnable);
- }
- }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera release");
- } else {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.removeCallbacksAndMessages(null);
- mCameraHandler.obtainMessage(CameraActions.RELEASE).sendToTarget();
- }
- });
- }
- }
-
/**
* A class which implements {@link CameraAgent.CameraProxy} and
* camera handler thread.
*/
- private class AndroidCameraProxyImpl implements CameraAgent.CameraProxy {
+ private class AndroidCameraProxyImpl extends CameraAgent.CameraProxy {
private final int mCameraId;
/* TODO: remove this Camera instance. */
private final Camera mCamera;
@@ -684,112 +659,6 @@ class AndroidCameraAgentImpl implements CameraAgent {
}
@Override
- public void reconnect(final Handler handler, final CameraOpenCallback cb) {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.obtainMessage(CameraActions.RECONNECT, mCameraId, 0,
- CameraOpenCallbackForward.getNewInstance(handler, cb)).sendToTarget();
- }
- });
- }
-
- @Override
- public void unlock() {
- final WaitDoneBundle bundle = new WaitDoneBundle();
- mDispatchThread.runJobSync(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.sendEmptyMessage(CameraActions.UNLOCK);
- mCameraHandler.post(bundle.mUnlockRunnable);
- }
- }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera unlock");
- }
-
- @Override
- public void lock() {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.sendEmptyMessage(CameraActions.LOCK);
- }
- });
- }
-
- @Override
- public void setPreviewTexture(final SurfaceTexture surfaceTexture) {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler
- .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
- .sendToTarget();
- }
- });
- }
-
- @Override
- public void setPreviewTextureSync(final SurfaceTexture surfaceTexture) {
- final WaitDoneBundle bundle = new WaitDoneBundle();
- mDispatchThread.runJobSync(new Runnable() {
- @Override
- public void run() {
- mCameraHandler
- .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
- .sendToTarget();
- mCameraHandler.post(bundle.mUnlockRunnable);
- }
- }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "set preview texture");
- }
-
- @Override
- public void setPreviewDisplay(final SurfaceHolder surfaceHolder) {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler
- .obtainMessage(CameraActions.SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder)
- .sendToTarget();
- }
- });
- }
-
- @Override
- public void startPreview() {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler
- .obtainMessage(CameraActions.START_PREVIEW_ASYNC, null).sendToTarget();
- }
- });
- }
-
- @Override
- public void startPreviewWithCallback(final Handler handler,
- final CameraStartPreviewCallback cb) {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.obtainMessage(CameraActions.START_PREVIEW_ASYNC,
- CameraStartPreviewCallbackForward.getNewInstance(handler, cb)).sendToTarget();
- }
- });
- }
-
- @Override
- public void stopPreview() {
- final WaitDoneBundle bundle = new WaitDoneBundle();
- mDispatchThread.runJobSync(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.sendEmptyMessage(CameraActions.STOP_PREVIEW);
- mCameraHandler.post(bundle.mUnlockRunnable);
- }
- }, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "stop preview");
- }
-
- @Override
public void setPreviewDataCallback(
final Handler handler, final CameraPreviewDataCallback cb) {
mDispatchThread.runJob(new Runnable() {
@@ -802,6 +671,7 @@ class AndroidCameraAgentImpl implements CameraAgent {
}
});
}
+
@Override
public void setOneShotPreviewCallback(final Handler handler,
final CameraPreviewDataCallback cb) {
@@ -831,25 +701,14 @@ class AndroidCameraAgentImpl implements CameraAgent {
}
@Override
- public void addCallbackBuffer(final byte[] callbackBuffer) {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.obtainMessage(CameraActions.ADD_CALLBACK_BUFFER, callbackBuffer)
- .sendToTarget();
- }
- });
- }
-
- @Override
public void autoFocus(final Handler handler, final CameraAFCallback cb) {
final AutoFocusCallback afCallback = new AutoFocusCallback() {
@Override
public void onAutoFocus(final boolean b, Camera camera) {
- if (mCameraState.getState() != CameraStateHolder.CAMERA_FOCUSING) {
+ if (mCameraState.getState() != AndroidCameraStateHolder.CAMERA_FOCUSING) {
Log.w(TAG, "onAutoFocus callback returning when not focusing");
} else {
- mCameraState.setState(CameraStateHolder.CAMERA_IDLE);
+ mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE);
}
handler.post(new Runnable() {
@Override
@@ -862,24 +721,13 @@ class AndroidCameraAgentImpl implements CameraAgent {
mDispatchThread.runJob(new Runnable() {
@Override
public void run() {
- mCameraState.waitForStates(CameraStateHolder.CAMERA_IDLE);
+ mCameraState.waitForStates(AndroidCameraStateHolder.CAMERA_IDLE);
mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, afCallback)
.sendToTarget();
}
});
}
- @Override
- public void cancelAutoFocus() {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.removeMessages(CameraActions.AUTO_FOCUS);
- mCameraHandler.sendEmptyMessage(CameraActions.CANCEL_AUTO_FOCUS);
- }
- });
- }
-
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void setAutoFocusMoveCallback(
@@ -903,10 +751,10 @@ class AndroidCameraAgentImpl implements CameraAgent {
final PictureCallback jpegCallback = new PictureCallback() {
@Override
public void onPictureTaken(final byte[] data, Camera camera) {
- if (mCameraState.getState() != CameraStateHolder.CAMERA_CAPTURING) {
+ if (mCameraState.getState() != AndroidCameraStateHolder.CAMERA_CAPTURING) {
Log.w(TAG, "picture callback returning when not capturing");
} else {
- mCameraState.setState(CameraStateHolder.CAMERA_IDLE);
+ mCameraState.setState(AndroidCameraStateHolder.CAMERA_IDLE);
}
handler.post(new Runnable() {
@Override
@@ -920,8 +768,8 @@ class AndroidCameraAgentImpl implements CameraAgent {
mDispatchThread.runJob(new Runnable() {
@Override
public void run() {
- mCameraState.waitForStates(
- CameraStateHolder.CAMERA_IDLE | CameraStateHolder.CAMERA_UNLOCKED);
+ mCameraState.waitForStates(CameraStateHolder.CAMERA_IDLE |
+ AndroidCameraStateHolder.CAMERA_UNLOCKED);
mCameraHandler.requestTakePicture(ShutterCallbackForward
.getNewInstance(handler, AndroidCameraProxyImpl.this, shutter),
PictureCallbackForward
@@ -935,17 +783,6 @@ class AndroidCameraAgentImpl implements CameraAgent {
}
@Override
- public void setDisplayOrientation(final int degrees) {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.obtainMessage(CameraActions.SET_DISPLAY_ORIENTATION, degrees, 0)
- .sendToTarget();
- }
- });
- }
-
- @Override
public void setZoomChangeListener(final OnZoomChangeListener listener) {
mDispatchThread.runJob(new Runnable() {
@Override
@@ -971,26 +808,6 @@ class AndroidCameraAgentImpl implements CameraAgent {
}
@Override
- public void startFaceDetection() {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.sendEmptyMessage(CameraActions.START_FACE_DETECTION);
- }
- });
- }
-
- @Override
- public void stopFaceDetection() {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.sendEmptyMessage(CameraActions.STOP_FACE_DETECTION);
- }
- });
- }
-
- @Override
public void setErrorCallback(final Handler handler, final CameraErrorCallback cb) {
mDispatchThread.runJob(new Runnable() {
@Override
@@ -1013,8 +830,8 @@ class AndroidCameraAgentImpl implements CameraAgent {
mDispatchThread.runJob(new Runnable() {
@Override
public void run() {
- mCameraState.waitForStates(
- CameraStateHolder.CAMERA_IDLE | CameraStateHolder.CAMERA_UNLOCKED);
+ mCameraState.waitForStates(AndroidCameraStateHolder.CAMERA_IDLE |
+ AndroidCameraStateHolder.CAMERA_UNLOCKED);
mCameraHandler.obtainMessage(CameraActions.SET_PARAMETERS, flattenedParameters)
.sendToTarget();
}
@@ -1040,48 +857,9 @@ class AndroidCameraAgentImpl implements CameraAgent {
}
@Override
- public boolean applySettings(final CameraSettings settings) {
- if (settings == null) {
- Log.v(TAG, "null parameters in applySettings()");
- return false;
- }
- if (!mCapabilities.supports(settings)) {
- return false;
- }
-
- final CameraSettings copyOfSettings = new CameraSettings(settings);
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraState.waitForStates(
- CameraStateHolder.CAMERA_IDLE | CameraStateHolder.CAMERA_UNLOCKED);
- mCameraHandler.obtainMessage(CameraActions.APPLY_SETTINGS, copyOfSettings)
- .sendToTarget();
- }
- });
- return true;
- }
-
- @Override
- public void refreshSettings() {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler.sendEmptyMessage(CameraActions.REFRESH_PARAMETERS);
- }
- });
- }
-
- @Override
- public void enableShutterSound(final boolean enable) {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraHandler
- .obtainMessage(CameraActions.ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0)
- .sendToTarget();
- }
- });
+ public boolean applySettings(CameraSettings settings) {
+ return applySettingsHelper(settings, AndroidCameraStateHolder.CAMERA_IDLE |
+ AndroidCameraStateHolder.CAMERA_UNLOCKED);
}
@Override
@@ -1095,22 +873,52 @@ class AndroidCameraAgentImpl implements CameraAgent {
return dumpedSettings;
}
+
+ @Override
+ public Handler getCameraHandler() {
+ return AndroidCameraAgentImpl.this.getCameraHandler();
+ }
+
+ @Override
+ public DispatchThread getDispatchThread() {
+ return AndroidCameraAgentImpl.this.getDispatchThread();
+ }
+
+ @Override
+ public CameraStateHolder getCameraState() {
+ return mCameraState;
+ }
}
- private static class WaitDoneBundle {
- public Runnable mUnlockRunnable;
- private final Object mWaitLock;
+ private static class AndroidCameraStateHolder extends CameraStateHolder {
+ /* Camera states */
+ // These states are defined bitwise so we can easily to specify a set of
+ // states together.
+ public static final int CAMERA_UNOPENED = 1;
+ public static final int CAMERA_IDLE = 1 << 1;
+ public static final int CAMERA_UNLOCKED = 1 << 2;
+ public static final int CAMERA_CAPTURING = 1 << 3;
+ public static final int CAMERA_FOCUSING = 1 << 4;
- WaitDoneBundle() {
- mWaitLock = new Object();
- mUnlockRunnable = new Runnable() {
- @Override
- public void run() {
- synchronized (mWaitLock) {
- mWaitLock.notifyAll();
- }
- }
- };
+ private int mState;
+
+ public AndroidCameraStateHolder() {
+ this(CAMERA_UNOPENED);
+ }
+
+ public AndroidCameraStateHolder(int state) {
+ setState(state);
+ }
+
+ @Override
+ public synchronized void setState(int state) {
+ mState = state;
+ this.notifyAll();
+ }
+
+ @Override
+ public synchronized int getState() {
+ return mState;
}
}
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraCapabilities.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraCapabilities.java
index 28d1fd1..14fcaaa 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraCapabilities.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraCapabilities.java
@@ -29,13 +29,13 @@ import java.util.List;
*/
class AndroidCameraCapabilities extends CameraCapabilities {
- private static Log.Tag TAG = new Log.Tag("AndroidCameraCapabilities");
+ private static Log.Tag TAG = new Log.Tag("AndCamCapabs");
private FpsComparator mFpsComparator = new FpsComparator();
private SizeComparator mSizeComparator = new SizeComparator();
AndroidCameraCapabilities(Camera.Parameters p) {
- super(new AndroidCameraCapabilityStringifier());
+ super(new Stringifier());
mMaxExposureCompensation = p.getMaxExposureCompensation();
mMinExposureCompensation = p.getMinExposureCompensation();
mExposureCompensationStep = p.getExposureCompensationStep();
@@ -250,241 +250,4 @@ class AndroidCameraCapabilities extends CameraCapabilities {
size1.width() - size2.width());
}
}
-
- private static class AndroidCameraCapabilityStringifier implements Stringifier {
-
- @Override
- public String stringify(FocusMode focus) {
- if (focus == null) {
- return null;
- }
-
- switch (focus) {
- case AUTO:
- return Camera.Parameters.FOCUS_MODE_AUTO;
- case CONTINUOUS_PICTURE:
- return Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
- case CONTINUOUS_VIDEO:
- return Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
- case EXTENDED_DOF:
- return Camera.Parameters.FOCUS_MODE_EDOF;
- case FIXED:
- return Camera.Parameters.FOCUS_MODE_FIXED;
- case INFINITY:
- return Camera.Parameters.FOCUS_MODE_INFINITY;
- case MACRO:
- return Camera.Parameters.FOCUS_MODE_MACRO;
- }
- return null;
- }
-
- @Override
- public FocusMode focusModeFromString(String val) {
- if (val == null) {
- return null;
- }
-
- if (Camera.Parameters.FOCUS_MODE_AUTO.equals(val)) {
- return FocusMode.AUTO;
- } else if (Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE.equals(val)) {
- return FocusMode.CONTINUOUS_PICTURE;
- } else if (Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO.equals(val)) {
- return FocusMode.CONTINUOUS_VIDEO;
- } else if (Camera.Parameters.FOCUS_MODE_EDOF.equals(val)) {
- return FocusMode.EXTENDED_DOF;
- } else if (Camera.Parameters.FOCUS_MODE_FIXED.equals(val)) {
- return FocusMode.FIXED;
- } else if (Camera.Parameters.FOCUS_MODE_INFINITY.equals(val)) {
- return FocusMode.INFINITY;
- } else if (Camera.Parameters.FOCUS_MODE_MACRO.equals(val)) {
- return FocusMode.MACRO;
- } else {
- return null;
- }
- }
-
- @Override
- public String stringify(FlashMode flash) {
- if (flash == null) {
- return null;
- }
-
- switch (flash) {
- case NO_FLASH:
- return null;
- case AUTO:
- return Camera.Parameters.FLASH_MODE_AUTO;
- case OFF:
- return Camera.Parameters.FLASH_MODE_OFF;
- case ON:
- return Camera.Parameters.FLASH_MODE_ON;
- case TORCH:
- return Camera.Parameters.FLASH_MODE_TORCH;
- case RED_EYE:
- return Camera.Parameters.FLASH_MODE_RED_EYE;
- }
- return null;
- }
-
- @Override
- public FlashMode flashModeFromString(String val) {
- if (val == null) {
- return FlashMode.NO_FLASH;
- } else if (Camera.Parameters.FLASH_MODE_AUTO.equals(val)) {
- return FlashMode.AUTO;
- } else if (Camera.Parameters.FLASH_MODE_OFF.equals(val)) {
- return FlashMode.OFF;
- } else if (Camera.Parameters.FLASH_MODE_ON.equals(val)) {
- return FlashMode.ON;
- } else if (Camera.Parameters.FLASH_MODE_TORCH.equals(val)) {
- return FlashMode.TORCH;
- } else if (Camera.Parameters.FLASH_MODE_RED_EYE.equals(val)) {
- return FlashMode.RED_EYE;
- } else {
- return null;
- }
- }
-
- @Override
- public String stringify(SceneMode scene) {
- if (scene == null) {
- return null;
- }
-
- switch (scene) {
- case AUTO:
- return Camera.Parameters.SCENE_MODE_AUTO;
- case ACTION:
- return Camera.Parameters.SCENE_MODE_ACTION;
- case BARCODE:
- return Camera.Parameters.SCENE_MODE_BARCODE;
- case BEACH:
- return Camera.Parameters.SCENE_MODE_BEACH;
- case CANDLELIGHT:
- return Camera.Parameters.SCENE_MODE_CANDLELIGHT;
- case FIREWORKS:
- return Camera.Parameters.SCENE_MODE_FIREWORKS;
- case HDR:
- return Camera.Parameters.SCENE_MODE_HDR;
- case LANDSCAPE:
- return Camera.Parameters.SCENE_MODE_LANDSCAPE;
- case NIGHT:
- return Camera.Parameters.SCENE_MODE_NIGHT;
- case NIGHT_PORTRAIT:
- return Camera.Parameters.SCENE_MODE_NIGHT_PORTRAIT;
- case PARTY:
- return Camera.Parameters.SCENE_MODE_PARTY;
- case PORTRAIT:
- return Camera.Parameters.SCENE_MODE_PORTRAIT;
- case SNOW:
- return Camera.Parameters.SCENE_MODE_SNOW;
- case SPORTS:
- return Camera.Parameters.SCENE_MODE_SPORTS;
- case STEADYPHOTO:
- return Camera.Parameters.SCENE_MODE_STEADYPHOTO;
- case SUNSET:
- return Camera.Parameters.SCENE_MODE_SUNSET;
- case THEATRE:
- return Camera.Parameters.SCENE_MODE_THEATRE;
- }
- return null;
- }
-
- @Override
- public SceneMode sceneModeFromString(String val) {
- if (val == null) {
- return SceneMode.NO_SCENE_MODE;
- } else if (Camera.Parameters.SCENE_MODE_AUTO.equals(val)) {
- return SceneMode.AUTO;
- } else if (Camera.Parameters.SCENE_MODE_ACTION.equals(val)) {
- return SceneMode.ACTION;
- } else if (Camera.Parameters.SCENE_MODE_BARCODE.equals(val)) {
- return SceneMode.BARCODE;
- } else if (Camera.Parameters.SCENE_MODE_BEACH.equals(val)) {
- return SceneMode.BEACH;
- } else if (Camera.Parameters.SCENE_MODE_CANDLELIGHT.equals(val)) {
- return SceneMode.CANDLELIGHT;
- } else if (Camera.Parameters.SCENE_MODE_FIREWORKS.equals(val)) {
- return SceneMode.FIREWORKS;
- } else if (Camera.Parameters.SCENE_MODE_HDR.equals(val)) {
- return SceneMode.HDR;
- } else if (Camera.Parameters.SCENE_MODE_LANDSCAPE.equals(val)) {
- return SceneMode.LANDSCAPE;
- } else if (Camera.Parameters.SCENE_MODE_NIGHT.equals(val)) {
- return SceneMode.NIGHT;
- } else if (Camera.Parameters.SCENE_MODE_NIGHT_PORTRAIT.equals(val)) {
- return SceneMode.NIGHT_PORTRAIT;
- } else if (Camera.Parameters.SCENE_MODE_PARTY.equals(val)) {
- return SceneMode.PARTY;
- } else if (Camera.Parameters.SCENE_MODE_PORTRAIT.equals(val)) {
- return SceneMode.PORTRAIT;
- } else if (Camera.Parameters.SCENE_MODE_SNOW.equals(val)) {
- return SceneMode.SNOW;
- } else if (Camera.Parameters.SCENE_MODE_SPORTS.equals(val)) {
- return SceneMode.SPORTS;
- } else if (Camera.Parameters.SCENE_MODE_STEADYPHOTO.equals(val)) {
- return SceneMode.STEADYPHOTO;
- } else if (Camera.Parameters.SCENE_MODE_SUNSET.equals(val)) {
- return SceneMode.SUNSET;
- } else if (Camera.Parameters.SCENE_MODE_THEATRE.equals(val)) {
- return SceneMode.THEATRE;
- } else {
- return null;
- }
- }
-
- @Override
- public String stringify(WhiteBalance wb) {
- if (wb == null) {
- return null;
- }
-
- switch (wb) {
- case AUTO:
- return Camera.Parameters.WHITE_BALANCE_AUTO;
- case CLOUDY_DAYLIGHT:
- return Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT;
- case DAYLIGHT:
- return Camera.Parameters.WHITE_BALANCE_DAYLIGHT;
- case FLUORESCENT:
- return Camera.Parameters.WHITE_BALANCE_FLUORESCENT;
- case INCANDESCENT:
- return Camera.Parameters.WHITE_BALANCE_INCANDESCENT;
- case SHADE:
- return Camera.Parameters.WHITE_BALANCE_SHADE;
- case TWILIGHT:
- return Camera.Parameters.WHITE_BALANCE_TWILIGHT;
- case WARM_FLUORESCENT:
- return Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT;
- }
- return null;
- }
-
- @Override
- public WhiteBalance whiteBalanceFromString(String val) {
- if (val == null) {
- return null;
- }
-
- if (Camera.Parameters.WHITE_BALANCE_AUTO.equals(val)) {
- return WhiteBalance.AUTO;
- } else if (Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT.equals(val)) {
- return WhiteBalance.CLOUDY_DAYLIGHT;
- } else if (Camera.Parameters.WHITE_BALANCE_DAYLIGHT.equals(val)) {
- return WhiteBalance.DAYLIGHT;
- } else if (Camera.Parameters.WHITE_BALANCE_FLUORESCENT.equals(val)) {
- return WhiteBalance.FLUORESCENT;
- } else if (Camera.Parameters.WHITE_BALANCE_INCANDESCENT.equals(val)) {
- return WhiteBalance.INCANDESCENT;
- } else if (Camera.Parameters.WHITE_BALANCE_SHADE.equals(val)) {
- return WhiteBalance.SHADE;
- } else if (Camera.Parameters.WHITE_BALANCE_TWILIGHT.equals(val)) {
- return WhiteBalance.TWILIGHT;
- } else if (Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT.equals(val)) {
- return WhiteBalance.WARM_FLUORESCENT;
- } else {
- return null;
- }
- }
- }
}
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/CameraAgent.java b/camera2/portability/src/com/android/ex/camera2/portability/CameraAgent.java
index 9c3c400..d875cea 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/CameraAgent.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/CameraAgent.java
@@ -25,6 +25,8 @@ import android.os.Handler;
import android.os.Looper;
import android.view.SurfaceHolder;
+import com.android.ex.camera2.portability.debug.Log;
+
/**
* An interface which provides possible camera device operations.
*
@@ -39,9 +41,11 @@ import android.view.SurfaceHolder;
* {@code android.hardware.Camera.ErrorCallback},
* {@code android.hardware.Camera.OnZoomChangeListener}, and
*/
-public interface CameraAgent {
+public abstract class CameraAgent {
public static final long CAMERA_OPERATION_TIMEOUT_MS = 2500;
+ private static final Log.Tag TAG = new Log.Tag("CamAgnt");
+
public static class CameraStartPreviewCallbackForward
implements CameraStartPreviewCallback {
private final Handler mHandler;
@@ -67,8 +71,7 @@ public interface CameraAgent {
@Override
public void run() {
mCallback.onPreviewStarted();
- }
- });
+ }});
}
}
@@ -110,8 +113,7 @@ public interface CameraAgent {
@Override
public void run() {
mCallback.onCameraOpened(camera);
- }
- });
+ }});
}
@Override
@@ -120,8 +122,7 @@ public interface CameraAgent {
@Override
public void run() {
mCallback.onCameraDisabled(cameraId);
- }
- });
+ }});
}
@Override
@@ -130,8 +131,7 @@ public interface CameraAgent {
@Override
public void run() {
mCallback.onDeviceOpenFailure(cameraId, info);
- }
- });
+ }});
}
@Override
@@ -140,8 +140,7 @@ public interface CameraAgent {
@Override
public void run() {
mCallback.onDeviceOpenedAlready(cameraId, info);
- }
- });
+ }});
}
@Override
@@ -150,8 +149,7 @@ public interface CameraAgent {
@Override
public void run() {
mCallback.onReconnectionFailure(mgr, info);
- }
- });
+ }});
}
}
@@ -159,7 +157,7 @@ public interface CameraAgent {
* A handler for all camera api runtime exceptions.
* The default behavior is to throw the runtime exception.
*/
- public interface CameraExceptionCallback {
+ public static interface CameraExceptionCallback {
public void onCameraException(RuntimeException e);
}
@@ -167,7 +165,7 @@ public interface CameraAgent {
* An interface which wraps
* {@link android.hardware.Camera.ErrorCallback}
*/
- public interface CameraErrorCallback {
+ public static interface CameraErrorCallback {
public void onError(int error, CameraProxy camera);
}
@@ -175,7 +173,7 @@ public interface CameraAgent {
* An interface which wraps
* {@link android.hardware.Camera.AutoFocusCallback}.
*/
- public interface CameraAFCallback {
+ public static interface CameraAFCallback {
public void onAutoFocus(boolean focused, CameraProxy camera);
}
@@ -183,7 +181,7 @@ public interface CameraAgent {
* An interface which wraps
* {@link android.hardware.Camera.AutoFocusMoveCallback}.
*/
- public interface CameraAFMoveCallback {
+ public static interface CameraAFMoveCallback {
public void onAutoFocusMoving(boolean moving, CameraProxy camera);
}
@@ -191,7 +189,7 @@ public interface CameraAgent {
* An interface which wraps
* {@link android.hardware.Camera.ShutterCallback}.
*/
- public interface CameraShutterCallback {
+ public static interface CameraShutterCallback {
public void onShutter(CameraProxy camera);
}
@@ -199,7 +197,7 @@ public interface CameraAgent {
* An interface which wraps
* {@link android.hardware.Camera.PictureCallback}.
*/
- public interface CameraPictureCallback {
+ public static interface CameraPictureCallback {
public void onPictureTaken(byte[] data, CameraProxy camera);
}
@@ -207,7 +205,7 @@ public interface CameraAgent {
* An interface which wraps
* {@link android.hardware.Camera.PreviewCallback}.
*/
- public interface CameraPreviewDataCallback {
+ public static interface CameraPreviewDataCallback {
public void onPreviewFrame(byte[] data, CameraProxy camera);
}
@@ -215,7 +213,7 @@ public interface CameraAgent {
* An interface which wraps
* {@link android.hardware.Camera.FaceDetectionListener}.
*/
- public interface CameraFaceDetectionCallback {
+ public static interface CameraFaceDetectionCallback {
/**
* Callback for face detection.
*
@@ -228,7 +226,7 @@ public interface CameraAgent {
/**
* An interface to be called when the camera preview has started.
*/
- public interface CameraStartPreviewCallback {
+ public static interface CameraStartPreviewCallback {
/**
* Callback when the preview starts.
*/
@@ -241,7 +239,7 @@ public interface CameraAgent {
* in the framework, {@link android.hardware.Camera.ErrorCallback}, which
* is used after the camera is opened.
*/
- public interface CameraOpenCallback {
+ public static interface CameraOpenCallback {
/**
* Callback when camera open succeeds.
*/
@@ -292,7 +290,15 @@ public interface CameraAgent {
* @param callback The callback for the result.
* @param cameraId The camera ID to open.
*/
- public void openCamera(Handler handler, int cameraId, CameraOpenCallback callback);
+ public void openCamera(final Handler handler, final int cameraId,
+ final CameraOpenCallback callback) {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().obtainMessage(CameraActions.OPEN_CAMERA, cameraId, 0,
+ CameraOpenCallbackForward.getNewInstance(handler, callback)).sendToTarget();
+ }});
+ }
/**
* Closes the camera device.
@@ -300,32 +306,60 @@ public interface CameraAgent {
* @param camera The camera to close. {@code null} means all.
* @param synced Whether this call should be synchronous.
*/
- public void closeCamera(CameraProxy camera, boolean synced);
+ public void closeCamera(CameraProxy camera, boolean synced) {
+ if (synced) {
+ final WaitDoneBundle bundle = new WaitDoneBundle();
+
+ getDispatchThread().runJobSync(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().obtainMessage(CameraActions.RELEASE).sendToTarget();
+ getCameraHandler().post(bundle.mUnlockRunnable);
+ }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera release");
+ } else {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().removeCallbacksAndMessages(null);
+ getCameraHandler().obtainMessage(CameraActions.RELEASE).sendToTarget();
+ }});
+ }
+ }
/**
* Sets a callback for handling camera api runtime exceptions on
* a handler.
*/
- public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
+ public abstract void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
Handler handler);
/**
* Recycles the resources used by this instance. CameraAgent will be in
* an unusable state after calling this.
*/
- public void recycle();
+ public abstract void recycle();
/**
* @return The camera devices info.
*/
- public CameraDeviceInfo getCameraDeviceInfo();
+ public abstract CameraDeviceInfo getCameraDeviceInfo();
+
+ /**
+ * @return The handler to which camera tasks should be posted.
+ */
+ protected abstract Handler getCameraHandler();
+
+ /**
+ * @return The thread used on which client callbacks are served.
+ */
+ protected abstract DispatchThread getDispatchThread();
/**
* An interface that takes camera operation requests and post messages to the
* camera handler thread. All camera operations made through this interface is
* asynchronous by default except those mentioned specifically.
*/
- public interface CameraProxy {
+ public static abstract class CameraProxy {
/**
* Returns the underlying {@link android.hardware.Camera} object used
@@ -334,23 +368,23 @@ public interface CameraAgent {
* recording.
*/
@Deprecated
- public android.hardware.Camera getCamera();
+ public abstract android.hardware.Camera getCamera();
/**
* @return The camera ID associated to by this
* {@link CameraAgent.CameraProxy}.
*/
- public int getCameraId();
+ public abstract int getCameraId();
/**
* @return The camera characteristics.
*/
- public CameraDeviceInfo.Characteristics getCharacteristics();
+ public abstract CameraDeviceInfo.Characteristics getCharacteristics();
/**
* @return The camera capabilities.
*/
- public CameraCapabilities getCapabilities();
+ public abstract CameraCapabilities getCapabilities();
/**
* Reconnects to the camera device. On success, the camera device will
@@ -363,27 +397,56 @@ public interface CameraAgent {
* was handled.
* @param cb The callback when any error happens.
*/
- public void reconnect(Handler handler, CameraOpenCallback cb);
+ public void reconnect(final Handler handler, final CameraOpenCallback cb) {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().obtainMessage(CameraActions.RECONNECT, getCameraId(), 0,
+ CameraOpenCallbackForward.getNewInstance(handler, cb)).sendToTarget();
+ }});
+ }
/**
* Unlocks the camera device.
*
* @see android.hardware.Camera#unlock()
*/
- public void unlock();
+ public void unlock() {
+ final WaitDoneBundle bundle = new WaitDoneBundle();
+ getDispatchThread().runJobSync(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().sendEmptyMessage(CameraActions.UNLOCK);
+ getCameraHandler().post(bundle.mUnlockRunnable);
+ }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "camera unlock");
+ }
/**
* Locks the camera device.
* @see android.hardware.Camera#lock()
*/
- public void lock();
+ public void lock() {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().sendEmptyMessage(CameraActions.LOCK);
+ }});
+ }
/**
* Sets the {@link android.graphics.SurfaceTexture} for preview.
*
* @param surfaceTexture The {@link SurfaceTexture} for preview.
*/
- public void setPreviewTexture(final SurfaceTexture surfaceTexture);
+ public void setPreviewTexture(final SurfaceTexture surfaceTexture) {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler()
+ .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
+ .sendToTarget();
+ }});
+ }
/**
* Blocks until a {@link android.graphics.SurfaceTexture} has been set
@@ -391,32 +454,73 @@ public interface CameraAgent {
*
* @param surfaceTexture The {@link SurfaceTexture} for preview.
*/
- public void setPreviewTextureSync(final SurfaceTexture surfaceTexture);
+ public void setPreviewTextureSync(final SurfaceTexture surfaceTexture) {
+ final WaitDoneBundle bundle = new WaitDoneBundle();
+ getDispatchThread().runJobSync(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler()
+ .obtainMessage(CameraActions.SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture)
+ .sendToTarget();
+ getCameraHandler().post(bundle.mUnlockRunnable);
+ }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "set preview texture");
+ }
/**
* Sets the {@link android.view.SurfaceHolder} for preview.
*
* @param surfaceHolder The {@link SurfaceHolder} for preview.
*/
- public void setPreviewDisplay(final SurfaceHolder surfaceHolder);
+ public void setPreviewDisplay(final SurfaceHolder surfaceHolder) {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler()
+ .obtainMessage(CameraActions.SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder)
+ .sendToTarget();
+ }});
+ }
/**
* Starts the camera preview.
*/
- public void startPreview();
+ public void startPreview() {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler()
+ .obtainMessage(CameraActions.START_PREVIEW_ASYNC, null).sendToTarget();
+ }});
+ }
/**
* Starts the camera preview and executes a callback on a handler once
* the preview starts.
*/
- public void startPreviewWithCallback(Handler h, CameraStartPreviewCallback cb);
+ public void startPreviewWithCallback(final Handler h, final CameraStartPreviewCallback cb) {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().obtainMessage(CameraActions.START_PREVIEW_ASYNC,
+ CameraStartPreviewCallbackForward.getNewInstance(h, cb))
+ .sendToTarget();
+ }});
+ }
/**
* Stops the camera preview synchronously.
* {@code stopPreview()} must be synchronous to ensure that the caller can
* continues to release resources related to camera preview.
*/
- public void stopPreview();
+ public void stopPreview() {
+ final WaitDoneBundle bundle = new WaitDoneBundle();
+ getDispatchThread().runJobSync(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().sendEmptyMessage(CameraActions.STOP_PREVIEW);
+ getCameraHandler().post(bundle.mUnlockRunnable);
+ }}, bundle.mWaitLock, CAMERA_OPERATION_TIMEOUT_MS, "stop preview");
+ }
/**
* Sets the callback for preview data.
@@ -425,7 +529,7 @@ public interface CameraAgent {
* @param cb The callback to be invoked when the preview data is available.
* @see android.hardware.Camera#setPreviewCallback(android.hardware.Camera.PreviewCallback)
*/
- public void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb);
+ public abstract void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb);
/**
* Sets the one-time callback for preview data.
@@ -435,7 +539,8 @@ public interface CameraAgent {
* next frame is available.
* @see android.hardware.Camera#setPreviewCallback(android.hardware.Camera.PreviewCallback)
*/
- public void setOneShotPreviewCallback(Handler handler, CameraPreviewDataCallback cb);
+ public abstract void setOneShotPreviewCallback(Handler handler,
+ CameraPreviewDataCallback cb);
/**
* Sets the callback for preview data.
@@ -444,14 +549,24 @@ public interface CameraAgent {
* @param cb The callback to be invoked when the preview data is available.
* @see android.hardware.Camera#setPreviewCallbackWithBuffer(android.hardware.Camera.PreviewCallback)
*/
- public void setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb);
+ public abstract void setPreviewDataCallbackWithBuffer(Handler handler,
+ CameraPreviewDataCallback cb);
/**
* Adds buffer for the preview callback.
*
* @param callbackBuffer The buffer allocated for the preview data.
*/
- public void addCallbackBuffer(byte[] callbackBuffer);
+ public void addCallbackBuffer(final byte[] callbackBuffer) {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler()
+ .obtainMessage(CameraActions.ADD_CALLBACK_BUFFER, callbackBuffer)
+ .sendToTarget();
+ }
+ });
+ }
/**
* Starts the auto-focus process. The result will be returned through the callback.
@@ -459,12 +574,19 @@ public interface CameraAgent {
* @param handler The handler in which the callback will be invoked.
* @param cb The auto-focus callback.
*/
- public void autoFocus(Handler handler, CameraAFCallback cb);
+ public abstract void autoFocus(Handler handler, CameraAFCallback cb);
/**
* Cancels the auto-focus process.
*/
- public void cancelAutoFocus();
+ public void cancelAutoFocus() {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().removeMessages(CameraActions.AUTO_FOCUS);
+ getCameraHandler().sendEmptyMessage(CameraActions.CANCEL_AUTO_FOCUS);
+ }});
+ }
/**
* Sets the auto-focus callback
@@ -473,7 +595,7 @@ public interface CameraAgent {
* @param cb The callback to be invoked when the preview data is available.
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
- public void setAutoFocusMoveCallback(Handler handler, CameraAFMoveCallback cb);
+ public abstract void setAutoFocusMoveCallback(Handler handler, CameraAFMoveCallback cb);
/**
* Instrument the camera to take a picture.
@@ -488,7 +610,7 @@ public interface CameraAgent {
* android.hardware.Camera.PictureCallback,
* android.hardware.Camera.PictureCallback)
*/
- public void takePicture(
+ public abstract void takePicture(
Handler handler,
CameraShutterCallback shutter,
CameraPictureCallback raw,
@@ -500,14 +622,22 @@ public interface CameraAgent {
*
* @param degrees The rotation in degrees. Should be 0, 90, 180 or 270.
*/
- public void setDisplayOrientation(int degrees);
+ public void setDisplayOrientation(final int degrees) {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler()
+ .obtainMessage(CameraActions.SET_DISPLAY_ORIENTATION, degrees, 0)
+ .sendToTarget();
+ }});
+ }
/**
* Sets the listener for zoom change.
*
* @param listener The listener.
*/
- public void setZoomChangeListener(OnZoomChangeListener listener);
+ public abstract void setZoomChangeListener(OnZoomChangeListener listener);
/**
* Sets the face detection listener.
@@ -515,17 +645,30 @@ public interface CameraAgent {
* @param handler The handler in which the callback will be invoked.
* @param callback The callback for face detection results.
*/
- public void setFaceDetectionCallback(Handler handler, CameraFaceDetectionCallback callback);
+ public abstract void setFaceDetectionCallback(Handler handler,
+ CameraFaceDetectionCallback callback);
/**
* Starts the face detection.
*/
- public void startFaceDetection();
+ public void startFaceDetection() {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().sendEmptyMessage(CameraActions.START_FACE_DETECTION);
+ }});
+ }
/**
* Stops the face detection.
*/
- public void stopFaceDetection();
+ public void stopFaceDetection() {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().sendEmptyMessage(CameraActions.STOP_FACE_DETECTION);
+ }});
+ }
/**
* Registers an error callback.
@@ -534,7 +677,7 @@ public interface CameraAgent {
* @param cb The error callback.
* @see android.hardware.Camera#setErrorCallback(android.hardware.Camera.ErrorCallback)
*/
- public void setErrorCallback(Handler handler, CameraErrorCallback cb);
+ public abstract void setErrorCallback(Handler handler, CameraErrorCallback cb);
/**
* Sets the camera parameters.
@@ -542,7 +685,7 @@ public interface CameraAgent {
* @param params The camera parameters to use.
*/
@Deprecated
- public void setParameters(Camera.Parameters params);
+ public abstract void setParameters(Camera.Parameters params);
/**
* Gets the current camera parameters synchronously. This method is
@@ -551,7 +694,7 @@ public interface CameraAgent {
* immediately.
*/
@Deprecated
- public Camera.Parameters getParameters();
+ public abstract Camera.Parameters getParameters();
/**
* Gets the current camera settings synchronously.
@@ -559,7 +702,38 @@ public interface CameraAgent {
* camera to return the parameters. If the parameters are already
* cached, it returns immediately.</p>
*/
- public CameraSettings getSettings();
+ public abstract CameraSettings getSettings();
+
+ /**
+ * Default implementation of {@link #applySettings(CameraSettings)}
+ * that is only missing the set of states it needs to wait for
+ * before applying the settings.
+ *
+ * @param settings The settings to use on the device.
+ * @param statesToAwait Bitwise OR of the required camera states.
+ * @return Whether the settings can be applied.
+ */
+ protected boolean applySettingsHelper(final CameraSettings settings,
+ final int statesToAwait) {
+ if (settings == null) {
+ Log.v(TAG, "null parameters in applySettings()");
+ return false;
+ }
+ if (!getCapabilities().supports(settings)) {
+ return false;
+ }
+
+ final CameraSettings copyOfSettings = new CameraSettings(settings);
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraState().waitForStates(statesToAwait);
+ getCameraHandler().obtainMessage(CameraActions.APPLY_SETTINGS, copyOfSettings)
+ .sendToTarget();
+ }
+ });
+ return true;
+ }
/**
* Applies the settings to the camera device.
@@ -567,13 +741,19 @@ public interface CameraAgent {
* @param settings The settings to use on the device.
* @return Whether the settings can be applied.
*/
- public boolean applySettings(CameraSettings settings);
+ public abstract boolean applySettings(CameraSettings settings);
/**
* Forces {@code CameraProxy} to update the cached version of the camera
* settings regardless of the dirty bit.
*/
- public void refreshSettings();
+ public void refreshSettings() {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler().sendEmptyMessage(CameraActions.REFRESH_PARAMETERS);
+ }});
+ }
/**
* Enables/Disables the camera shutter sound.
@@ -581,7 +761,15 @@ public interface CameraAgent {
* @param enable {@code true} to enable the shutter sound,
* {@code false} to disable it.
*/
- public void enableShutterSound(boolean enable);
+ public void enableShutterSound(final boolean enable) {
+ getDispatchThread().runJob(new Runnable() {
+ @Override
+ public void run() {
+ getCameraHandler()
+ .obtainMessage(CameraActions.ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0)
+ .sendToTarget();
+ }});
+ }
/**
* Dumps the current settings of the camera device.
@@ -591,6 +779,37 @@ public interface CameraAgent {
*
* @return The content of the device settings represented by a string.
*/
- public String dumpDeviceSettings();
+ public abstract String dumpDeviceSettings();
+
+ /**
+ * @return The handler to which camera tasks should be posted.
+ */
+ public abstract Handler getCameraHandler();
+
+ /**
+ * @return The thread used on which client callbacks are served.
+ */
+ public abstract DispatchThread getDispatchThread();
+
+ /**
+ * @return The state machine tracking the camera API's current mode.
+ */
+ public abstract CameraStateHolder getCameraState();
+ }
+
+ public static class WaitDoneBundle {
+ public final Runnable mUnlockRunnable;
+ public final Object mWaitLock;
+
+ WaitDoneBundle() {
+ mWaitLock = new Object();
+ mUnlockRunnable = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mWaitLock) {
+ mWaitLock.notifyAll();
+ }
+ }};
+ }
}
}
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/CameraAgentFactory.java b/camera2/portability/src/com/android/ex/camera2/portability/CameraAgentFactory.java
index ce8379d..00dc280 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/CameraAgentFactory.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/CameraAgentFactory.java
@@ -16,12 +16,14 @@
package com.android.ex.camera2.portability;
+import android.content.Context;
+
/**
* A factory class for {@link CameraAgent}.
*/
public class CameraAgentFactory {
- private static AndroidCameraAgentImpl sAndroidCameraAgent;
+ private static CameraAgent sAndroidCameraAgent;
private static int sAndroidCameraAgentClientCount;
/**
@@ -29,9 +31,13 @@ public class CameraAgentFactory {
*
* @return The {@link CameraAgent} to control the camera device.
*/
- public static synchronized CameraAgent getAndroidCameraAgent() {
+ public static synchronized CameraAgent getAndroidCameraAgent(Context context) {
if (sAndroidCameraAgent == null) {
- sAndroidCameraAgent = new AndroidCameraAgentImpl();
+ if (false) {
+ sAndroidCameraAgent = new AndroidCamera2AgentImpl(context);
+ } else {
+ sAndroidCameraAgent = new AndroidCameraAgentImpl();
+ }
sAndroidCameraAgentClientCount = 1;
} else {
++sAndroidCameraAgentClientCount;
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/CameraCapabilities.java b/camera2/portability/src/com/android/ex/camera2/portability/CameraCapabilities.java
index f08301c..9b7ca6e 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/CameraCapabilities.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/CameraCapabilities.java
@@ -34,7 +34,7 @@ import java.util.TreeSet;
*/
public class CameraCapabilities {
- private static Log.Tag TAG = new Log.Tag("CamCapabilities");
+ private static Log.Tag TAG = new Log.Tag("CamCapabs");
/* All internal states are declared final and should be thread-safe. */
@@ -311,61 +311,116 @@ public class CameraCapabilities {
* A interface stringifier to convert abstract representations to API
* related string representation.
*/
- public interface Stringifier {
+ public static class Stringifier {
+ /**
+ * Converts the string to hyphen-delimited lowercase for compatibility with multiple APIs.
+ *
+ * @param enumCase The name of an enum constant.
+ * @return The converted string.
+ */
+ private static String toApiCase(String enumCase) {
+ return enumCase.toLowerCase().replaceAll("_", "-");
+ }
+
+ /**
+ * Conerts the string to underscore-delimited uppercase to match the enum constant names.
+ *
+ * @param apiCase An API-related string representation.
+ * @return The converted string.
+ */
+ private static String toEnumCase(String apiCase) {
+ return apiCase.toUpperCase().replaceAll("-", "_");
+ }
+
/**
* Converts the focus mode to API-related string representation.
*
* @param focus The focus mode to convert.
* @return The string used by the camera framework API to represent the
- * focus mode.
+ * focus mode.
*/
- String stringify(FocusMode focus);
+ public String stringify(FocusMode focus) {
+ return toApiCase(focus.name());
+ }
/**
* Converts the API-related string representation of the focus mode to the
* abstract representation.
*
* @param val The string representation.
- * @return The focus mode represented by the input string.
+ * @return The focus mode represented by the input string, or the focus
+ * mode with the lowest ordinal if it cannot be converted.
*/
- FocusMode focusModeFromString(String val);
+ public FocusMode focusModeFromString(String val) {
+ if (val == null) {
+ return FocusMode.values()[0];
+ }
+ try {
+ return FocusMode.valueOf(toEnumCase(val));
+ } catch (IllegalArgumentException ex) {
+ return FocusMode.values()[0];
+ }
+ }
/**
* Converts the flash mode to API-related string representation.
*
* @param flash The focus mode to convert.
* @return The string used by the camera framework API to represent the
- * flash mode.
+ * flash mode.
*/
- String stringify(FlashMode flash);
+ public String stringify(FlashMode flash) {
+ return toApiCase(flash.name());
+ }
/**
* Converts the API-related string representation of the flash mode to the
* abstract representation.
*
* @param val The string representation.
- * @return The flash mode represented by the input string. Can be
- * {@code null}.
+ * @return The flash mode represented by the input string, or the flash
+ * mode with the lowest ordinal if it cannot be converted.
*/
- FlashMode flashModeFromString(String val);
+ public FlashMode flashModeFromString(String val) {
+ if (val == null) {
+ return FlashMode.values()[0];
+ }
+ try {
+ return FlashMode.valueOf(toEnumCase(val));
+ } catch (IllegalArgumentException ex) {
+ return FlashMode.values()[0];
+ }
+ }
/**
* Converts the scene mode to API-related string representation.
*
* @param scene The focus mode to convert.
* @return The string used by the camera framework API to represent the
- * scene mode.
+ * scene mode.
*/
- String stringify(SceneMode scene);
+ public String stringify(SceneMode scene) {
+ return toApiCase(scene.name());
+ }
/**
* Converts the API-related string representation of the scene mode to the
* abstract representation.
*
* @param val The string representation.
- * @return The scene mode represented by the input string.
+ * @return The scene mode represented by the input string, or the scene
+ * mode with the lowest ordinal if it cannot be converted.
*/
- SceneMode sceneModeFromString(String val);
+ public SceneMode sceneModeFromString(String val) {
+ if (val == null) {
+ return SceneMode.values()[0];
+ }
+ try {
+ return SceneMode.valueOf(toEnumCase(val));
+ } catch (IllegalArgumentException ex) {
+ return SceneMode.values()[0];
+ }
+ }
/**
* Converts the white balance to API-related string representation.
@@ -374,16 +429,29 @@ public class CameraCapabilities {
* @return The string used by the camera framework API to represent the
* white balance.
*/
- String stringify(WhiteBalance wb);
+ public String stringify(WhiteBalance wb) {
+ return toApiCase(wb.name());
+ }
/**
* Converts the API-related string representation of the white balance to
* the abstract representation.
*
* @param val The string representation.
- * @return The white balance represented by the input string.
+ * @return The white balance represented by the input string, or the
+ * white balance with the lowest ordinal if it cannot be
+ * converted.
*/
- WhiteBalance whiteBalanceFromString(String val);
+ public WhiteBalance whiteBalanceFromString(String val) {
+ if (val == null) {
+ return WhiteBalance.values()[0];
+ }
+ try {
+ return WhiteBalance.valueOf(toEnumCase(val));
+ } catch (IllegalArgumentException ex) {
+ return WhiteBalance.values()[0];
+ }
+ }
}
/**
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/CameraCapabilitiesFactory.java b/camera2/portability/src/com/android/ex/camera2/portability/CameraCapabilitiesFactory.java
index 80765d3..6c2bc54 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/CameraCapabilitiesFactory.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/CameraCapabilitiesFactory.java
@@ -22,7 +22,7 @@ import com.android.ex.camera2.portability.debug.Log;
public class CameraCapabilitiesFactory {
- private static Log.Tag TAG = new Log.Tag("CapabilitiesFactory");
+ private static Log.Tag TAG = new Log.Tag("CamCapabsFact");
public static CameraCapabilities createFrom(Camera.Parameters p) {
if (p == null) {
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/CameraSettings.java b/camera2/portability/src/com/android/ex/camera2/portability/CameraSettings.java
index 33ceb5c..3948b2e 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/CameraSettings.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/CameraSettings.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2014 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.ex.camera2.portability;
import android.hardware.Camera;
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/CameraStateHolder.java b/camera2/portability/src/com/android/ex/camera2/portability/CameraStateHolder.java
index 02d6c48..5df541a 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/CameraStateHolder.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/CameraStateHolder.java
@@ -20,8 +20,8 @@ import android.os.SystemClock;
import com.android.ex.camera2.portability.debug.Log;
-class CameraStateHolder {
- private static final Log.Tag TAG = new Log.Tag("CameraStateHolder");
+public abstract class CameraStateHolder {
+ private static final Log.Tag TAG = new Log.Tag("CamStateHolder");
/** Camera states **/
// These states are defined bitwise so we can easily to specify a set of
@@ -51,7 +51,7 @@ class CameraStateHolder {
return mState;
}
- private interface ConditionChecker {
+ private static interface ConditionChecker {
/**
* @return Whether the condition holds.
*/
@@ -99,7 +99,7 @@ class CameraStateHolder {
return waitForCondition(new ConditionChecker() {
@Override
public boolean success() {
- return (states | mState) == states;
+ return (states | getState()) == states;
}
}, CameraAgent.CAMERA_OPERATION_TIMEOUT_MS);
}
@@ -116,7 +116,7 @@ class CameraStateHolder {
return waitForCondition(new ConditionChecker() {
@Override
public boolean success() {
- return (states & mState) == 0;
+ return (states & getState()) == 0;
}
}, CameraAgent.CAMERA_OPERATION_TIMEOUT_MS);
}
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/DispatchThread.java b/camera2/portability/src/com/android/ex/camera2/portability/DispatchThread.java
index 67713c9..bc77259 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/DispatchThread.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/DispatchThread.java
@@ -25,7 +25,7 @@ import com.android.ex.camera2.portability.debug.Log;
import java.util.LinkedList;
import java.util.Queue;
-class DispatchThread extends Thread {
+public class DispatchThread extends Thread {
private static final Log.Tag TAG = new Log.Tag("DispatchThread");
private static final long MAX_MESSAGE_QUEUE_LENGTH = 256;
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/Size.java b/camera2/portability/src/com/android/ex/camera2/portability/Size.java
index 9ae21aa..042c443 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/Size.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/Size.java
@@ -45,6 +45,20 @@ public class Size {
}
/**
+ * A helper method to build a list of this class from a list of {@link android.util.Size}.
+ *
+ * @param cameraSizes Source.
+ * @return The built list.
+ */
+ public static List<Size> buildListFromAndroidSizes(List<android.util.Size> androidSizes) {
+ ArrayList<Size> list = new ArrayList<Size>(androidSizes.size());
+ for (android.util.Size androidSize : androidSizes) {
+ list.add(new Size(androidSize));
+ }
+ return list;
+ }
+
+ /**
* Encode List of this class as comma-separated list of integers.
*
* @param sizes List of this class to encode.
@@ -110,6 +124,19 @@ public class Size {
}
/**
+ * Constructor from a source {@link android.util.Size}.
+ *
+ * @param other The source size.
+ */
+ public Size(android.util.Size other) {
+ if (other == null) {
+ val = new Point(0, 0);
+ } else {
+ val = new Point(other.getWidth(), other.getHeight());
+ }
+ }
+
+ /**
* Constructor from a source {@link android.graphics.Point}.
*
* @param p The source size.