summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/camera/AndroidCameraManagerImpl.java737
-rw-r--r--src/com/android/camera/CameraHolder.java3
-rw-r--r--src/com/android/camera/CameraManager.java670
-rw-r--r--src/com/android/camera/CameraManagerFactory.java37
-rw-r--r--src/com/android/camera/EffectsRecorder.java9
-rw-r--r--src/com/android/camera/PhotoModule.java56
-rw-r--r--src/com/android/camera/Util.java4
-rw-r--r--src/com/android/camera/VideoModule.java31
8 files changed, 1071 insertions, 476 deletions
diff --git a/src/com/android/camera/AndroidCameraManagerImpl.java b/src/com/android/camera/AndroidCameraManagerImpl.java
new file mode 100644
index 000000000..8ffdb42b8
--- /dev/null
+++ b/src/com/android/camera/AndroidCameraManagerImpl.java
@@ -0,0 +1,737 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera;
+
+import static com.android.camera.Util.Assert;
+
+import android.annotation.TargetApi;
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.hardware.Camera.AutoFocusCallback;
+import android.hardware.Camera.AutoFocusMoveCallback;
+import android.hardware.Camera.ErrorCallback;
+import android.hardware.Camera.FaceDetectionListener;
+import android.hardware.Camera.OnZoomChangeListener;
+import android.hardware.Camera.Parameters;
+import android.hardware.Camera.PictureCallback;
+import android.hardware.Camera.PreviewCallback;
+import android.hardware.Camera.ShutterCallback;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+import com.android.gallery3d.common.ApiHelper;
+
+import java.io.IOException;
+
+/**
+ * A class to implement {@link CameraManager} of the Android camera framework.
+ */
+class AndroidCameraManagerImpl implements CameraManager {
+ private static final String TAG = "CAM_" +
+ AndroidCameraManagerImpl.class.getSimpleName();
+
+ private Parameters mParameters;
+ private boolean mParametersIsDirty;
+ private IOException mReconnectIOException;
+
+ /* Messages used in CameraHandler. */
+ // Camera initialization/finalization
+ private static final int OPEN_CAMERA = 1;
+ private static final int RELEASE = 2;
+ private static final int RECONNECT = 3;
+ private static final int UNLOCK = 4;
+ private static final int LOCK = 5;
+ // Preview
+ private static final int SET_PREVIEW_TEXTURE_ASYNC = 101;
+ private static final int START_PREVIEW_ASYNC = 102;
+ private static final int STOP_PREVIEW = 103;
+ private static final int SET_PREVIEW_CALLBACK_WITH_BUFFER = 104;
+ private static final int ADD_CALLBACK_BUFFER = 105;
+ private static final int SET_PREVIEW_DISPLAY_ASYNC = 106;
+ private static final int SET_PREVIEW_CALLBACK = 107;
+ // Parameters
+ private static final int SET_PARAMETERS = 201;
+ private static final int GET_PARAMETERS = 202;
+ private static final int REFRESH_PARAMETERS = 203;
+ // Focus, Zoom
+ private static final int AUTO_FOCUS = 301;
+ private static final int CANCEL_AUTO_FOCUS = 302;
+ private static final int SET_AUTO_FOCUS_MOVE_CALLBACK = 303;
+ private static final int SET_ZOOM_CHANGE_LISTENER = 304;
+ // Face detection
+ private static final int SET_FACE_DETECTION_LISTENER = 461;
+ private static final int START_FACE_DETECTION = 462;
+ private static final int STOP_FACE_DETECTION = 463;
+ private static final int SET_ERROR_CALLBACK = 464;
+ // Presentation
+ private static final int ENABLE_SHUTTER_SOUND = 501;
+ private static final int SET_DISPLAY_ORIENTATION = 502;
+
+ private CameraHandler mCameraHandler;
+ private android.hardware.Camera mCamera;
+
+ // Used to retain a copy of Parameters for setting parameters.
+ private Parameters mParamsToSet;
+
+ AndroidCameraManagerImpl() {
+ HandlerThread ht = new HandlerThread("Camera Handler Thread");
+ ht.start();
+ mCameraHandler = new CameraHandler(ht.getLooper());
+ }
+
+ private class CameraHandler extends Handler {
+ CameraHandler(Looper looper) {
+ super(looper);
+ }
+
+ @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
+ private void startFaceDetection() {
+ mCamera.startFaceDetection();
+ }
+
+ @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
+ private void stopFaceDetection() {
+ mCamera.stopFaceDetection();
+ }
+
+ @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
+ private void setFaceDetectionListener(FaceDetectionListener listener) {
+ mCamera.setFaceDetectionListener(listener);
+ }
+
+ @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
+ private void setPreviewTexture(Object surfaceTexture) {
+ try {
+ mCamera.setPreviewTexture((SurfaceTexture) surfaceTexture);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN_MR1)
+ private void enableShutterSound(boolean enable) {
+ mCamera.enableShutterSound(enable);
+ }
+
+ @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
+ private void setAutoFocusMoveCallback(
+ android.hardware.Camera camera, Object cb) {
+ camera.setAutoFocusMoveCallback((AutoFocusMoveCallback) cb);
+ }
+
+ public void requestTakePicture(
+ final ShutterCallback shutter,
+ final PictureCallback raw,
+ final PictureCallback postView,
+ final PictureCallback jpeg) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mCamera.takePicture(shutter, raw, postView, jpeg);
+ } catch (RuntimeException e) {
+ // TODO: output camera state and focus state for debugging.
+ Log.e(TAG, "take picture failed.");
+ throw e;
+ }
+ }
+ });
+ }
+
+ /**
+ * Waits for all the {@code Message} and {@code Runnable} currently in the queue
+ * are processed.
+ *
+ * @return {@code false} if the wait was interrupted, {@code true} otherwise.
+ */
+ public boolean waitDone() {
+ final Object waitDoneLock = new Object();
+ final Runnable unlockRunnable = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (waitDoneLock) {
+ waitDoneLock.notifyAll();
+ }
+ }
+ };
+
+ synchronized (waitDoneLock) {
+ mCameraHandler.post(unlockRunnable);
+ try {
+ waitDoneLock.wait();
+ } catch (InterruptedException ex) {
+ Log.v(TAG, "waitDone interrupted");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * This method does not deal with the API level check. Everyone should
+ * check first for supported operations before sending message to this handler.
+ */
+ @Override
+ public void handleMessage(final Message msg) {
+ try {
+ switch (msg.what) {
+ case OPEN_CAMERA:
+ mCamera = android.hardware.Camera.open();
+ if (mCamera != null) {
+ mParametersIsDirty = true;
+
+ // Get a instance of Camera.Parameters for later use.
+ if (mParamsToSet == null) {
+ mParamsToSet = mCamera.getParameters();
+ }
+ }
+ return;
+
+ case RELEASE:
+ mCamera.release();
+ mCamera = null;
+ return;
+
+ case RECONNECT:
+ mReconnectIOException = null;
+ try {
+ mCamera.reconnect();
+ } catch (IOException ex) {
+ mReconnectIOException = ex;
+ }
+ return;
+
+ case UNLOCK:
+ mCamera.unlock();
+ return;
+
+ case LOCK:
+ mCamera.lock();
+ return;
+
+ case SET_PREVIEW_TEXTURE_ASYNC:
+ setPreviewTexture(msg.obj);
+ return;
+
+ case SET_PREVIEW_DISPLAY_ASYNC:
+ try {
+ mCamera.setPreviewDisplay((SurfaceHolder) msg.obj);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return;
+
+ case START_PREVIEW_ASYNC:
+ mCamera.startPreview();
+ return;
+
+ case STOP_PREVIEW:
+ mCamera.stopPreview();
+ return;
+
+ case SET_PREVIEW_CALLBACK_WITH_BUFFER:
+ mCamera.setPreviewCallbackWithBuffer(
+ (PreviewCallback) msg.obj);
+ return;
+
+ case ADD_CALLBACK_BUFFER:
+ mCamera.addCallbackBuffer((byte[]) msg.obj);
+ return;
+
+ case AUTO_FOCUS:
+ mCamera.autoFocus((AutoFocusCallback) msg.obj);
+ return;
+
+ case CANCEL_AUTO_FOCUS:
+ mCamera.cancelAutoFocus();
+ return;
+
+ case SET_AUTO_FOCUS_MOVE_CALLBACK:
+ setAutoFocusMoveCallback(mCamera, msg.obj);
+ return;
+
+ case SET_DISPLAY_ORIENTATION:
+ mCamera.setDisplayOrientation(msg.arg1);
+ return;
+
+ case SET_ZOOM_CHANGE_LISTENER:
+ mCamera.setZoomChangeListener(
+ (OnZoomChangeListener) msg.obj);
+ return;
+
+ case SET_FACE_DETECTION_LISTENER:
+ setFaceDetectionListener((FaceDetectionListener) msg.obj);
+ return;
+
+ case START_FACE_DETECTION:
+ startFaceDetection();
+ return;
+
+ case STOP_FACE_DETECTION:
+ stopFaceDetection();
+ return;
+
+ case SET_ERROR_CALLBACK:
+ mCamera.setErrorCallback((ErrorCallback) msg.obj);
+ return;
+
+ case SET_PARAMETERS:
+ mParametersIsDirty = true;
+ mParamsToSet.unflatten((String) msg.obj);
+ mCamera.setParameters(mParamsToSet);
+ return;
+
+ case GET_PARAMETERS:
+ if (mParametersIsDirty) {
+ mParameters = mCamera.getParameters();
+ mParametersIsDirty = false;
+ }
+ return;
+
+ case SET_PREVIEW_CALLBACK:
+ mCamera.setPreviewCallback((PreviewCallback) msg.obj);
+ return;
+
+ case ENABLE_SHUTTER_SOUND:
+ enableShutterSound((msg.arg1 == 1) ? true : false);
+ return;
+
+ case REFRESH_PARAMETERS:
+ mParametersIsDirty = true;
+ return;
+
+ default:
+ throw new RuntimeException("Invalid CameraProxy message=" + msg.what);
+ }
+ } catch (RuntimeException e) {
+ if (msg.what != RELEASE && mCamera != null) {
+ try {
+ mCamera.release();
+ } catch (Exception ex) {
+ Log.e(TAG, "Fail to release the camera.");
+ }
+ mCamera = null;
+ }
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ public CameraManager.CameraProxy cameraOpen(int cameraId) {
+ mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0).sendToTarget();
+ mCameraHandler.waitDone();
+ if (mCamera != null) {
+ return new AndroidCameraProxyImpl();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * A class which implements {@link CameraManager.CameraProxy} and
+ * camera handler thread.
+ */
+ public class AndroidCameraProxyImpl implements CameraManager.CameraProxy {
+
+ private AndroidCameraProxyImpl() {
+ Assert(mCamera != null);
+ }
+
+ @Override
+ public android.hardware.Camera getCamera() {
+ return mCamera;
+ }
+
+ @Override
+ public void release() {
+ // release() must be synchronous so we know exactly when the camera
+ // is released and can continue on.
+ mCameraHandler.sendEmptyMessage(RELEASE);
+ mCameraHandler.waitDone();
+ }
+
+ @Override
+ public void reconnect() throws IOException {
+ mCameraHandler.sendEmptyMessage(RECONNECT);
+ mCameraHandler.waitDone();
+ if (mReconnectIOException != null) {
+ throw mReconnectIOException;
+ }
+ }
+
+ @Override
+ public void unlock() {
+ mCameraHandler.sendEmptyMessage(UNLOCK);
+ mCameraHandler.waitDone();
+ }
+
+ @Override
+ public void lock() {
+ mCameraHandler.sendEmptyMessage(LOCK);
+ }
+
+ @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
+ @Override
+ public void setPreviewTexture(final SurfaceTexture surfaceTexture) {
+ mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture).sendToTarget();
+ }
+
+ @Override
+ public void setPreviewDisplay(final SurfaceHolder surfaceHolder) {
+ mCameraHandler.obtainMessage(SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder).sendToTarget();
+ }
+
+ @Override
+ public void startPreview() {
+ mCameraHandler.sendEmptyMessage(START_PREVIEW_ASYNC);
+ }
+
+ @Override
+ public void stopPreview() {
+ mCameraHandler.sendEmptyMessage(STOP_PREVIEW);
+ mCameraHandler.waitDone();
+ }
+
+ @Override
+ public void setPreviewDataCallback(
+ Handler handler, final CameraPreviewDataCallback cb) {
+ mCameraHandler.obtainMessage(
+ SET_PREVIEW_CALLBACK,
+ PreviewCallbackForward.instance(handler, this, cb)).sendToTarget();
+ }
+
+ @Override
+ public void setPreviewDataCallbackWithBuffer(
+ Handler handler, final CameraPreviewDataCallback cb) {
+ mCameraHandler.obtainMessage(
+ SET_PREVIEW_CALLBACK_WITH_BUFFER,
+ PreviewCallbackForward.instance(handler, this, cb)).sendToTarget();
+ }
+
+ @Override
+ public void addCallbackBuffer(byte[] callbackBuffer) {
+ mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer).sendToTarget();
+ }
+
+ @Override
+ public void autoFocus(Handler handler, CameraAFCallback cb) {
+ mCameraHandler.obtainMessage(
+ AUTO_FOCUS,
+ AFCallbackForward.instance(handler, this, cb)).sendToTarget();
+ }
+
+ @Override
+ public void cancelAutoFocus() {
+ mCameraHandler.removeMessages(AUTO_FOCUS);
+ mCameraHandler.sendEmptyMessage(CANCEL_AUTO_FOCUS);
+ }
+
+ @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
+ @Override
+ public void setAutoFocusMoveCallback(
+ Handler handler, final CameraAFMoveCallback cb) {
+ mCameraHandler.obtainMessage(
+ SET_AUTO_FOCUS_MOVE_CALLBACK,
+ AFMoveCallbackForward.instance(handler, this, cb)).sendToTarget();
+ }
+
+ @Override
+ public void takePicture(
+ final Handler handler,
+ final CameraShutterCallback shutter,
+ final CameraPictureCallback raw,
+ final CameraPictureCallback post,
+ final CameraPictureCallback jpeg) {
+ mCameraHandler.requestTakePicture(
+ ShutterCallbackForward.instance(handler, this, shutter),
+ PictureCallbackForward.instance(handler, this, raw),
+ PictureCallbackForward.instance(handler, this, post),
+ PictureCallbackForward.instance(handler, this, jpeg));
+ }
+
+ @Override
+ public void setDisplayOrientation(int degrees) {
+ mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0)
+ .sendToTarget();
+ }
+
+ @Override
+ public void setZoomChangeListener(OnZoomChangeListener listener) {
+ mCameraHandler.obtainMessage(SET_ZOOM_CHANGE_LISTENER, listener).sendToTarget();
+ }
+
+ @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
+ public void setFaceDetectionListener(FaceDetectionListener listener) {
+ mCameraHandler.obtainMessage(SET_FACE_DETECTION_LISTENER, listener).sendToTarget();
+ }
+
+ @Override
+ public void startFaceDetection() {
+ mCameraHandler.sendEmptyMessage(START_FACE_DETECTION);
+ }
+
+ @Override
+ public void stopFaceDetection() {
+ mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION);
+ }
+
+ @Override
+ public void setErrorCallback(ErrorCallback cb) {
+ mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, cb).sendToTarget();
+ }
+
+ @Override
+ public void setParameters(Parameters params) {
+ if (params == null) {
+ Log.v(TAG, "null parameters in setParameters()");
+ return;
+ }
+ mCameraHandler.obtainMessage(SET_PARAMETERS, params.flatten())
+ .sendToTarget();
+ }
+
+ @Override
+ public Parameters getParameters() {
+ mCameraHandler.sendEmptyMessage(GET_PARAMETERS);
+ mCameraHandler.waitDone();
+ return mParameters;
+ }
+
+ @Override
+ public void refreshParameters() {
+ mCameraHandler.sendEmptyMessage(REFRESH_PARAMETERS);
+ }
+
+ @Override
+ public void enableShutterSound(boolean enable) {
+ mCameraHandler.obtainMessage(
+ ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0).sendToTarget();
+ }
+ }
+
+ /**
+ * A helper class to forward AutoFocusCallback to another thread.
+ */
+ private static class AFCallbackForward implements AutoFocusCallback {
+ private final Handler mHandler;
+ private final CameraProxy mCamera;
+ private final CameraAFCallback mCallback;
+
+ /**
+ * Returns an instance of {@link AFCallbackForward}.
+ *
+ * @param handler The handler in which the callback will be invoked in.
+ * @param camera The {@link CameraProxy} which the callback is from.
+ * @param cb The callback to be invoked.
+ * @return The instance of the {@link AFCallbackForward},
+ * or null if any one of other parameters is null.
+ */
+ public static AFCallbackForward instance(
+ Handler handler, CameraProxy camera, CameraAFCallback cb) {
+ if (handler == null || camera == null || cb == null) return null;
+ return new AFCallbackForward(handler, camera, cb);
+ }
+
+ private AFCallbackForward(
+ Handler h, CameraProxy camera, CameraAFCallback cb) {
+ mHandler = h;
+ mCamera = camera;
+ mCallback = cb;
+ }
+
+ @Override
+ public void onAutoFocus(final boolean b, Camera camera) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onAutoFocus(b, mCamera);
+ }
+ });
+ }
+ }
+
+ /** A helper class to forward AutoFocusMoveCallback to another thread. */
+ @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
+ private static class AFMoveCallbackForward implements AutoFocusMoveCallback {
+ private final Handler mHandler;
+ private final CameraAFMoveCallback mCallback;
+ private final CameraProxy mCamera;
+
+ /**
+ * Returns an instance of {@link AFMoveCallbackForward}.
+ *
+ * @param handler The handler in which the callback will be invoked in.
+ * @param camera The {@link CameraProxy} which the callback is from.
+ * @param cb The callback to be invoked.
+ * @return The instance of the {@link AFMoveCallbackForward},
+ * or null if any one of other parameters is null.
+ */
+ public static AFMoveCallbackForward instance(
+ Handler handler, CameraProxy camera, CameraAFMoveCallback cb) {
+ if (handler == null || camera == null || cb == null) return null;
+ return new AFMoveCallbackForward(handler, camera, cb);
+ }
+
+ private AFMoveCallbackForward(
+ Handler h, CameraProxy camera, CameraAFMoveCallback cb) {
+ mHandler = h;
+ mCamera = camera;
+ mCallback = cb;
+ }
+
+ @Override
+ public void onAutoFocusMoving(
+ final boolean moving, android.hardware.Camera camera) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onAutoFocusMoving(moving, mCamera);
+ }
+ });
+ }
+ }
+
+ /**
+ * A helper class to forward ShutterCallback to to another thread.
+ */
+ private static class ShutterCallbackForward implements ShutterCallback {
+ private final Handler mHandler;
+ private final CameraShutterCallback mCallback;
+ private final CameraProxy mCamera;
+
+ /**
+ * Returns an instance of {@link ShutterCallbackForward}.
+ *
+ * @param handler The handler in which the callback will be invoked in.
+ * @param camera The {@link CameraProxy} which the callback is from.
+ * @param cb The callback to be invoked.
+ * @return The instance of the {@link ShutterCallbackForward},
+ * or null if any one of other parameters is null.
+ */
+ public static ShutterCallbackForward instance(
+ Handler handler, CameraProxy camera, CameraShutterCallback cb) {
+ if (handler == null || camera == null || cb == null) return null;
+ return new ShutterCallbackForward(handler, camera, cb);
+ }
+
+ private ShutterCallbackForward(
+ Handler h, CameraProxy camera, CameraShutterCallback cb) {
+ mHandler = h;
+ mCamera = camera;
+ mCallback = cb;
+ }
+
+ @Override
+ public void onShutter() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onShutter(mCamera);
+ }
+ });
+ }
+ }
+
+ /**
+ * A helper class to forward PictureCallback to another thread.
+ */
+ private static class PictureCallbackForward implements PictureCallback {
+ private final Handler mHandler;
+ private final CameraPictureCallback mCallback;
+ private final CameraProxy mCamera;
+
+ /**
+ * Returns an instance of {@link PictureCallbackForward}.
+ *
+ * @param handler The handler in which the callback will be invoked in.
+ * @param camera The {@link CameraProxy} which the callback is from.
+ * @param cb The callback to be invoked.
+ * @return The instance of the {@link PictureCallbackForward},
+ * or null if any one of other parameters is null.
+ */
+ public static PictureCallbackForward instance(
+ Handler handler, CameraProxy camera, CameraPictureCallback cb) {
+ if (handler == null || camera == null || cb == null) return null;
+ return new PictureCallbackForward(handler, camera, cb);
+ }
+
+ private PictureCallbackForward(
+ Handler h, CameraProxy camera, CameraPictureCallback cb) {
+ mHandler = h;
+ mCamera = camera;
+ mCallback = cb;
+ }
+
+ @Override
+ public void onPictureTaken(
+ final byte[] data, android.hardware.Camera camera) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onPictureTaken(data, mCamera);
+ }
+ });
+ }
+ }
+
+ /**
+ * A helper class to forward PreviewCallback to another thread.
+ */
+ private static class PreviewCallbackForward implements PreviewCallback {
+ private final Handler mHandler;
+ private final CameraPreviewDataCallback mCallback;
+ private final CameraProxy mCamera;
+
+ /**
+ * Returns an instance of {@link PreviewCallbackForward}.
+ *
+ * @param handler The handler in which the callback will be invoked in.
+ * @param camera The {@link CameraProxy} which the callback is from.
+ * @param cb The callback to be invoked.
+ * @return The instance of the {@link PictureCallbackForward},
+ * or null if any one of other parameters is null.
+ */
+ public static PreviewCallbackForward instance(
+ Handler handler, CameraProxy camera, CameraPreviewDataCallback cb) {
+ if (handler == null || camera == null || cb == null) return null;
+ return new PreviewCallbackForward(handler, camera, cb);
+ }
+
+ private PreviewCallbackForward(
+ Handler h, CameraProxy camera, CameraPreviewDataCallback cb) {
+ mHandler = h;
+ mCamera = camera;
+ mCallback = cb;
+ }
+
+ @Override
+ public void onPreviewFrame(
+ final byte[] data, android.hardware.Camera camera) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onPreviewFrame(data, mCamera);
+ }
+ });
+ }
+ }
+}
diff --git a/src/com/android/camera/CameraHolder.java b/src/com/android/camera/CameraHolder.java
index 5b7bbfda3..d913df709 100644
--- a/src/com/android/camera/CameraHolder.java
+++ b/src/com/android/camera/CameraHolder.java
@@ -207,7 +207,8 @@ public class CameraHolder {
try {
Log.v(TAG, "open camera " + cameraId);
if (mMockCameraInfo == null) {
- mCameraDevice = CameraManager.instance().cameraOpen(cameraId);
+ mCameraDevice = CameraManagerFactory
+ .getAndroidCameraManager().cameraOpen(cameraId);
} else {
if (mMockCamera == null)
throw new RuntimeException();
diff --git a/src/com/android/camera/CameraManager.java b/src/com/android/camera/CameraManager.java
index c7005cf54..e4a066701 100644
--- a/src/com/android/camera/CameraManager.java
+++ b/src/com/android/camera/CameraManager.java
@@ -16,466 +16,288 @@
package com.android.camera;
-import static com.android.camera.Util.Assert;
-
import android.annotation.TargetApi;
import android.graphics.SurfaceTexture;
-import android.hardware.Camera.AutoFocusCallback;
-import android.hardware.Camera.AutoFocusMoveCallback;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.FaceDetectionListener;
import android.hardware.Camera.OnZoomChangeListener;
import android.hardware.Camera.Parameters;
-import android.hardware.Camera.PictureCallback;
-import android.hardware.Camera.PreviewCallback;
-import android.hardware.Camera.ShutterCallback;
import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
import android.view.SurfaceHolder;
import com.android.gallery3d.common.ApiHelper;
import java.io.IOException;
-public class CameraManager {
- private static final String TAG = "CameraManager";
- private static CameraManager sCameraManager = new CameraManager();
-
- private Parameters mParameters;
- private boolean mParametersIsDirty;
- private IOException mReconnectIOException;
-
- private static final int RELEASE = 1;
- private static final int RECONNECT = 2;
- private static final int UNLOCK = 3;
- private static final int LOCK = 4;
- private static final int SET_PREVIEW_TEXTURE_ASYNC = 5;
- private static final int START_PREVIEW_ASYNC = 6;
- private static final int STOP_PREVIEW = 7;
- private static final int SET_PREVIEW_CALLBACK_WITH_BUFFER = 8;
- private static final int ADD_CALLBACK_BUFFER = 9;
- private static final int AUTO_FOCUS = 10;
- private static final int CANCEL_AUTO_FOCUS = 11;
- private static final int SET_AUTO_FOCUS_MOVE_CALLBACK = 12;
- private static final int SET_DISPLAY_ORIENTATION = 13;
- private static final int SET_ZOOM_CHANGE_LISTENER = 14;
- private static final int SET_FACE_DETECTION_LISTENER = 15;
- private static final int START_FACE_DETECTION = 16;
- private static final int STOP_FACE_DETECTION = 17;
- private static final int SET_ERROR_CALLBACK = 18;
- private static final int SET_PARAMETERS = 19;
- private static final int GET_PARAMETERS = 20;
- private static final int SET_PREVIEW_DISPLAY_ASYNC = 21;
- private static final int SET_PREVIEW_CALLBACK = 22;
- private static final int ENABLE_SHUTTER_SOUND = 23;
- private static final int REFRESH_PARAMETERS = 24;
-
- private Handler mCameraHandler;
- private android.hardware.Camera mCamera;
-
- // Used to retain a copy of Parameters for setting parameters.
- private Parameters mParamsToSet;
-
-
- // This holder is used when we need to pass the exception
- // back to the calling thread. SynchornousQueue doesn't
- // allow we to pass a null object thus a holder is needed.
- private class IOExceptionHolder {
- public IOException ex;
+/**
+ * An interface which provides possible camera device operations.
+ *
+ * The client should call {@code CameraManager.cameraOpen} to get an instance
+ * of {@link CameraManager.CameraProxy} to control the camera. Classes
+ * implementing this interface should have its own one unique {@code Thread}
+ * other than the main thread for camera operations. Camera device callbacks
+ * are wrapped since the client should not deal with
+ * {@code android.hardware.Camera} directly.
+ *
+ * TODO: provide callback interfaces for:
+ * {@code android.hardware.Camera.ErrorCallback},
+ * {@code android.hardware.Camera.FaceDetectionListener},
+ * {@code android.hardware.Camera.OnZoomChangeListener}, and
+ * {@code android.hardware.Camera.Parameters}.
+ */
+public interface CameraManager {
+
+ /**
+ * An interface which wraps
+ * {@link android.hardware.Camera.AutoFocusCallback}.
+ */
+ public interface CameraAFCallback {
+ public void onAutoFocus(boolean focused, CameraProxy camera);
}
- public static CameraManager instance() {
- return sCameraManager;
+ /**
+ * An interface which wraps
+ * {@link android.hardware.Camera.AutoFocusMoveCallback}.
+ */
+ public interface CameraAFMoveCallback {
+ public void onAutoFocusMoving(boolean moving, CameraProxy camera);
}
- private CameraManager() {
- HandlerThread ht = new HandlerThread("Camera Handler Thread");
- ht.start();
- mCameraHandler = new CameraHandler(ht.getLooper());
+ /**
+ * An interface which wraps
+ * {@link android.hardware.Camera.ShutterCallback}.
+ */
+ public interface CameraShutterCallback {
+ public void onShutter(CameraProxy camera);
}
- private class CameraHandler extends Handler {
- CameraHandler(Looper looper) {
- super(looper);
- }
-
- @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
- private void startFaceDetection() {
- mCamera.startFaceDetection();
- }
+ /**
+ * An interface which wraps
+ * {@link android.hardware.Camera.PictureCallback}.
+ */
+ public interface CameraPictureCallback {
+ public void onPictureTaken(byte[] data, CameraProxy camera);
+ }
- @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
- private void stopFaceDetection() {
- mCamera.stopFaceDetection();
- }
+ /**
+ * An interface which wraps
+ * {@link android.hardware.Camera.PreviewCallback}.
+ */
+ public interface CameraPreviewDataCallback {
+ public void onPreviewFrame(byte[] data, CameraProxy camera);
+ }
- @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
- private void setFaceDetectionListener(FaceDetectionListener listener) {
- mCamera.setFaceDetectionListener(listener);
- }
+ /**
+ * Opens the camera of the specified ID synchronously.
+ *
+ * @param cameraId The camera ID to open.
+ * @return An instance of {@link CameraProxy} on success. null on failure.
+ */
+ public CameraProxy cameraOpen(int cameraId);
+
+ /**
+ * 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 {
+
+ /**
+ * Returns the underlying {@link android.hardware.Camera} object used
+ * by this proxy. This method should only be used when handing the
+ * camera device over to {@link android.media.MediaRecorder} for
+ * recording.
+ */
+ public android.hardware.Camera getCamera();
- @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
- private void setPreviewTexture(Object surfaceTexture) {
- try {
- mCamera.setPreviewTexture((SurfaceTexture) surfaceTexture);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN_MR1)
- private void enableShutterSound(boolean enable) {
- mCamera.enableShutterSound(enable);
- }
-
- /*
- * This method does not deal with the build version check. Everyone should
- * check first before sending message to this handler.
+ /**
+ * Releases the camera device synchronously.
+ * This function must be synchronous so the caller knows exactly when the camera
+ * is released and can continue on.
*/
- @Override
- public void handleMessage(final Message msg) {
- try {
- switch (msg.what) {
- case RELEASE:
- mCamera.release();
- mCamera = null;
- return;
-
- case RECONNECT:
- mReconnectIOException = null;
- try {
- mCamera.reconnect();
- } catch (IOException ex) {
- mReconnectIOException = ex;
- }
- return;
-
- case UNLOCK:
- mCamera.unlock();
- return;
-
- case LOCK:
- mCamera.lock();
- return;
-
- case SET_PREVIEW_TEXTURE_ASYNC:
- setPreviewTexture(msg.obj);
- return;
-
- case SET_PREVIEW_DISPLAY_ASYNC:
- try {
- mCamera.setPreviewDisplay((SurfaceHolder) msg.obj);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- return;
-
- case START_PREVIEW_ASYNC:
- mCamera.startPreview();
- return;
-
- case STOP_PREVIEW:
- mCamera.stopPreview();
- return;
-
- case SET_PREVIEW_CALLBACK_WITH_BUFFER:
- mCamera.setPreviewCallbackWithBuffer(
- (PreviewCallback) msg.obj);
- return;
-
- case ADD_CALLBACK_BUFFER:
- mCamera.addCallbackBuffer((byte[]) msg.obj);
- return;
-
- case AUTO_FOCUS:
- mCamera.autoFocus((AutoFocusCallback) msg.obj);
- return;
-
- case CANCEL_AUTO_FOCUS:
- mCamera.cancelAutoFocus();
- return;
-
- case SET_AUTO_FOCUS_MOVE_CALLBACK:
- setAutoFocusMoveCallback(mCamera, msg.obj);
- return;
-
- case SET_DISPLAY_ORIENTATION:
- mCamera.setDisplayOrientation(msg.arg1);
- return;
-
- case SET_ZOOM_CHANGE_LISTENER:
- mCamera.setZoomChangeListener(
- (OnZoomChangeListener) msg.obj);
- return;
-
- case SET_FACE_DETECTION_LISTENER:
- setFaceDetectionListener((FaceDetectionListener) msg.obj);
- return;
-
- case START_FACE_DETECTION:
- startFaceDetection();
- return;
-
- case STOP_FACE_DETECTION:
- stopFaceDetection();
- return;
-
- case SET_ERROR_CALLBACK:
- mCamera.setErrorCallback((ErrorCallback) msg.obj);
- return;
-
- case SET_PARAMETERS:
- mParametersIsDirty = true;
- mParamsToSet.unflatten((String) msg.obj);
- mCamera.setParameters(mParamsToSet);
- return;
-
- case GET_PARAMETERS:
- if (mParametersIsDirty) {
- mParameters = mCamera.getParameters();
- mParametersIsDirty = false;
- }
- return;
-
- case SET_PREVIEW_CALLBACK:
- mCamera.setPreviewCallback((PreviewCallback) msg.obj);
- return;
-
- case ENABLE_SHUTTER_SOUND:
- enableShutterSound((msg.arg1 == 1) ? true : false);
- return;
-
- case REFRESH_PARAMETERS:
- mParametersIsDirty = true;
- return;
-
- default:
- throw new RuntimeException("Invalid CameraProxy message=" + msg.what);
- }
- } catch (RuntimeException e) {
- if (msg.what != RELEASE && mCamera != null) {
- try {
- mCamera.release();
- } catch (Exception ex) {
- Log.e(TAG, "Fail to release the camera.");
- }
- mCamera = null;
- }
- throw e;
- }
- }
- }
+ public void release();
- @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
- private void setAutoFocusMoveCallback(android.hardware.Camera camera,
- Object cb) {
- camera.setAutoFocusMoveCallback((AutoFocusMoveCallback) cb);
- }
+ /**
+ * Reconnects to the camera device.
+ *
+ * @see android.hardware.Camera#reconnect()
+ */
+ public void reconnect() throws IOException;
- // Open camera synchronously. This method is invoked in the context of a
- // background thread.
- CameraProxy cameraOpen(int cameraId) {
- // Cannot open camera in mCameraHandler, otherwise all camera events
- // will be routed to mCameraHandler looper, which in turn will call
- // event handler like Camera.onFaceDetection, which in turn will modify
- // UI and cause exception like this:
- // CalledFromWrongThreadException: Only the original thread that created
- // a view hierarchy can touch its views.
- mCamera = android.hardware.Camera.open(cameraId);
- if (mCamera != null) {
- mParametersIsDirty = true;
- if (mParamsToSet == null) {
- mParamsToSet = mCamera.getParameters();
- }
- return new CameraProxy();
- } else {
- return null;
- }
- }
+ /**
+ * Unlocks the camera device.
+ *
+ * @see android.hardware.Camera#unlock()
+ */
+ public void unlock();
- public class CameraProxy {
+ /**
+ * Locks the camera device.
+ * @see android.hardware.Camera#lock()
+ */
+ public void lock();
- private CameraProxy() {
- Assert(mCamera != null);
- }
+ /**
+ * Sets the {@link android.graphics.SurfaceTexture} for preview.
+ *
+ * @param surfaceTexture The {@link SurfaceTexture} for preview.
+ */
+ @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
+ public void setPreviewTexture(final SurfaceTexture surfaceTexture);
- public android.hardware.Camera getCamera() {
- return mCamera;
- }
+ /**
+ * Sets the {@link android.view.SurfaceHolder} for preview.
+ *
+ * @param surfaceHolder The {@link SurfaceHolder} for preview.
+ */
+ public void setPreviewDisplay(final SurfaceHolder surfaceHolder);
- public void release() {
- // release() must be synchronous so we know exactly when the camera
- // is released and can continue on.
- mCameraHandler.sendEmptyMessage(RELEASE);
- waitDone();
- }
+ /**
+ * Starts the camera preview.
+ */
+ public void startPreview();
- public void reconnect() throws IOException {
- mCameraHandler.sendEmptyMessage(RECONNECT);
- waitDone();
- if (mReconnectIOException != null) {
- throw mReconnectIOException;
- }
- }
+ /**
+ * 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();
+
+ /**
+ * Sets the callback for preview data.
+ *
+ * @param handler handler in which the callback was handled.
+ * @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);
+
+ /**
+ * Sets the callback for preview data.
+ *
+ * @param handler The handler in which the callback will be invoked.
+ * @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 void unlock() {
- mCameraHandler.sendEmptyMessage(UNLOCK);
- }
+ /**
+ * Adds buffer for the preview callback.
+ *
+ * @param callbackBuffer The buffer allocated for the preview data.
+ */
+ public void addCallbackBuffer(byte[] callbackBuffer);
- public void lock() {
- mCameraHandler.sendEmptyMessage(LOCK);
- }
+ /**
+ * Starts the auto-focus process. The result will be returned through the callback.
+ *
+ * @param handler The handler in which the callback will be invoked.
+ * @param cb The auto-focus callback.
+ */
+ public void autoFocus(Handler handler, CameraAFCallback cb);
- @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
- public void setPreviewTextureAsync(final SurfaceTexture surfaceTexture) {
- mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture).sendToTarget();
- }
-
- public void setPreviewDisplayAsync(final SurfaceHolder surfaceHolder) {
- mCameraHandler.obtainMessage(SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder).sendToTarget();
- }
-
- public void startPreviewAsync() {
- mCameraHandler.sendEmptyMessage(START_PREVIEW_ASYNC);
- }
-
- // stopPreview() is synchronous because many resources should be released after
- // the preview is stopped.
- public void stopPreview() {
- mCameraHandler.sendEmptyMessage(STOP_PREVIEW);
- waitDone();
- }
-
- public void setPreviewCallback(final PreviewCallback cb) {
- mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK, cb).sendToTarget();
- }
-
- public void setPreviewCallbackWithBuffer(final PreviewCallback cb) {
- mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK_WITH_BUFFER, cb).sendToTarget();
- }
-
- public void addCallbackBuffer(byte[] callbackBuffer) {
- mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer).sendToTarget();
- }
-
- public void autoFocus(AutoFocusCallback cb) {
- mCameraHandler.obtainMessage(AUTO_FOCUS, cb).sendToTarget();
- }
-
- public void cancelAutoFocus() {
- mCameraHandler.removeMessages(AUTO_FOCUS);
- mCameraHandler.sendEmptyMessage(CANCEL_AUTO_FOCUS);
- }
+ /**
+ * Cancels the auto-focus process.
+ */
+ public void cancelAutoFocus();
+ /**
+ * Sets the auto-focus callback
+ *
+ * @param handler The handler in which the callback will be invoked.
+ * @param cb The callback to be invoked when the preview data is available.
+ */
@TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
- public void setAutoFocusMoveCallback(AutoFocusMoveCallback cb) {
- mCameraHandler.obtainMessage(SET_AUTO_FOCUS_MOVE_CALLBACK, cb).sendToTarget();
- }
-
- public void takePicture(final ShutterCallback shutter, final PictureCallback raw,
- final PictureCallback postview, final PictureCallback jpeg) {
- // Too many parameters, so use post for simplicity
- mCameraHandler.post(new Runnable() {
- @Override
- public void run() {
- mCamera.takePicture(shutter, raw, postview, jpeg);
- }
- });
- }
-
- public void takePicture2(final ShutterCallback shutter, final PictureCallback raw,
- final PictureCallback postview, final PictureCallback jpeg,
- final int cameraState, final int focusState) {
- // Too many parameters, so use post for simplicity
- mCameraHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- mCamera.takePicture(shutter, raw, postview, jpeg);
- } catch (RuntimeException e) {
- Log.w(TAG, "take picture failed; cameraState:" + cameraState
- + ", focusState:" + focusState);
- throw e;
- }
- }
- });
- }
-
- public void setDisplayOrientation(int degrees) {
- mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0)
- .sendToTarget();
- }
-
- public void setZoomChangeListener(OnZoomChangeListener listener) {
- mCameraHandler.obtainMessage(SET_ZOOM_CHANGE_LISTENER, listener).sendToTarget();
- }
+ public void setAutoFocusMoveCallback(Handler handler, CameraAFMoveCallback cb);
+
+ /**
+ * Instrument the camera to take a picture.
+ *
+ * @param handler The handler in which the callback will be invoked.
+ * @param shutter The callback for shutter action, may be null.
+ * @param raw The callback for uncompressed data, may be null.
+ * @param postview The callback for postview image data, may be null.
+ * @param jpeg The callback for jpeg image data, may be null.
+ * @see android.hardware.Camera#takePicture(
+ * android.hardware.Camera.ShutterCallback,
+ * android.hardware.Camera.PictureCallback,
+ * android.hardware.Camera.PictureCallback)
+ */
+ public void takePicture(
+ Handler handler,
+ CameraShutterCallback shutter,
+ CameraPictureCallback raw,
+ CameraPictureCallback postview,
+ CameraPictureCallback jpeg);
+
+ /**
+ * Sets the display orientation for camera to adjust the preview orientation.
+ *
+ * @param degrees The rotation in degrees. Should be 0, 90, 180 or 270.
+ */
+ public void setDisplayOrientation(int degrees);
+
+ /**
+ * Sets the listener for zoom change.
+ *
+ * @param listener The listener.
+ */
+ public void setZoomChangeListener(OnZoomChangeListener listener);
+ /**
+ * Sets the face detection listener.
+ *
+ * @param listener The listener for face detection results.
+ */
@TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
- public void setFaceDetectionListener(FaceDetectionListener listener) {
- mCameraHandler.obtainMessage(SET_FACE_DETECTION_LISTENER, listener).sendToTarget();
- }
-
- public void startFaceDetection() {
- mCameraHandler.sendEmptyMessage(START_FACE_DETECTION);
- }
-
- public void stopFaceDetection() {
- mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION);
- }
-
- public void setErrorCallback(ErrorCallback cb) {
- mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, cb).sendToTarget();
- }
-
- public void setParameters(Parameters params) {
- if (params == null) {
- Log.v(TAG, "null parameters in setParameters()");
- return;
- }
- mCameraHandler.obtainMessage(SET_PARAMETERS, params.flatten())
- .sendToTarget();
- }
-
- public Parameters getParameters() {
- mCameraHandler.sendEmptyMessage(GET_PARAMETERS);
- waitDone();
- return mParameters;
- }
-
- public void refreshParameters() {
- mCameraHandler.sendEmptyMessage(REFRESH_PARAMETERS);
- }
-
- public void enableShutterSound(boolean enable) {
- mCameraHandler.obtainMessage(
- ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0).sendToTarget();
- }
-
- // return false if cancelled.
- public boolean waitDone() {
- final Object waitDoneLock = new Object();
- final Runnable unlockRunnable = new Runnable() {
- @Override
- public void run() {
- synchronized (waitDoneLock) {
- waitDoneLock.notifyAll();
- }
- }
- };
-
- synchronized (waitDoneLock) {
- mCameraHandler.post(unlockRunnable);
- try {
- waitDoneLock.wait();
- } catch (InterruptedException ex) {
- Log.v(TAG, "waitDone interrupted");
- return false;
- }
- }
- return true;
- }
+ public void setFaceDetectionListener(FaceDetectionListener listener);
+
+ /**
+ * Starts the face detection.
+ */
+ public void startFaceDetection();
+
+ /**
+ * Stops the face detection.
+ */
+ public void stopFaceDetection();
+
+ /**
+ * Registers an error callback.
+ *
+ * @param cb The error callback.
+ * @see android.hardware.Camera#setErrorCallback(android.hardware.Camera.ErrorCallback)
+ */
+ public void setErrorCallback(ErrorCallback cb);
+
+ /**
+ * Sets the camera parameters.
+ *
+ * @param params The camera parameters to use.
+ */
+ public void setParameters(Parameters params);
+
+ /**
+ * Gets the current camera parameters synchronously. This method is
+ * synchronous since the caller has to wait for the camera to return
+ * the parameters. If the parameters are already cached, it returns
+ * immediately.
+ */
+ public Parameters getParameters();
+
+ /**
+ * Forces {@code CameraProxy} to update the cached version of the camera
+ * parameters regardless of the dirty bit.
+ */
+ public void refreshParameters();
+
+ /**
+ * Enables/Disables the camera shutter sound.
+ *
+ * @param enable {@code true} to enable the shutter sound,
+ * {@code false} to disable it.
+ */
+ public void enableShutterSound(boolean enable);
}
}
diff --git a/src/com/android/camera/CameraManagerFactory.java b/src/com/android/camera/CameraManagerFactory.java
new file mode 100644
index 000000000..914ebb265
--- /dev/null
+++ b/src/com/android/camera/CameraManagerFactory.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.camera;
+
+/**
+ * A factory class for {@link CameraManager}.
+ */
+public class CameraManagerFactory {
+
+ private static AndroidCameraManagerImpl sAndroidCameraManager;
+
+ /**
+ * Returns the android camera implementation of {@link CameraManager}.
+ *
+ * @return The {@link CameraManager} to control the camera device.
+ */
+ public static synchronized CameraManager getAndroidCameraManager() {
+ if (sAndroidCameraManager == null) {
+ sAndroidCameraManager = new AndroidCameraManagerImpl();
+ }
+ return sAndroidCameraManager;
+ }
+}
diff --git a/src/com/android/camera/EffectsRecorder.java b/src/com/android/camera/EffectsRecorder.java
index 2db44c76f..4bf8d411e 100644
--- a/src/com/android/camera/EffectsRecorder.java
+++ b/src/com/android/camera/EffectsRecorder.java
@@ -30,7 +30,6 @@ import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
@@ -650,7 +649,7 @@ public class EffectsRecorder {
// Switching effects while running. Stop existing runner.
// The stop callback will take care of starting new runner.
mCameraDevice.stopPreview();
- mCameraDevice.setPreviewTextureAsync(null);
+ mCameraDevice.setPreviewTexture(null);
invoke(mOldRunner, sGraphRunnerStop);
}
}
@@ -862,9 +861,9 @@ public class EffectsRecorder {
mCameraDevice.stopPreview();
if (mLogVerbose) Log.v(TAG, "Runner active, connecting effects preview");
- mCameraDevice.setPreviewTextureAsync(mTextureSource);
+ mCameraDevice.setPreviewTexture(mTextureSource);
- mCameraDevice.startPreviewAsync();
+ mCameraDevice.startPreview();
// Unlock AE/AWB after preview started
tryEnable3ALocks(false);
@@ -995,7 +994,7 @@ public class EffectsRecorder {
return;
}
mCameraDevice.stopPreview();
- mCameraDevice.setPreviewTextureAsync(null);
+ mCameraDevice.setPreviewTexture(null);
}
// Stop and release effect resources
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 361f111ea..6140848ec 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -28,7 +28,6 @@ import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
-import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
@@ -52,7 +51,11 @@ import android.view.SurfaceHolder;
import android.view.View;
import android.view.WindowManager;
+import com.android.camera.CameraManager.CameraAFCallback;
+import com.android.camera.CameraManager.CameraAFMoveCallback;
+import com.android.camera.CameraManager.CameraPictureCallback;
import com.android.camera.CameraManager.CameraProxy;
+import com.android.camera.CameraManager.CameraShutterCallback;
import com.android.camera.ui.CountDownView.OnCountDownFinishedListener;
import com.android.camera.ui.PopupManager;
import com.android.camera.ui.RotateTextToast;
@@ -623,7 +626,7 @@ public class PhotoModule
if (mCameraDevice == null || mCameraStartUpThread != null)
return;
- mCameraDevice.setPreviewDisplayAsync(holder);
+ mCameraDevice.setPreviewDisplay(holder);
// This happens when onConfigurationChanged arrives, surface has been
// destroyed, and there is no onFullScreenChanged.
if (mCameraState == PREVIEW_STOPPED) {
@@ -680,7 +683,7 @@ public class PhotoModule
}
private final class ShutterCallback
- implements android.hardware.Camera.ShutterCallback {
+ implements CameraShutterCallback {
private boolean mAnimateFlash;
@@ -689,7 +692,7 @@ public class PhotoModule
}
@Override
- public void onShutter() {
+ public void onShutter(CameraProxy camera) {
mShutterCallbackTime = System.currentTimeMillis();
mShutterLag = mShutterCallbackTime - mCaptureStartTime;
Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
@@ -699,10 +702,10 @@ public class PhotoModule
}
}
- private final class PostViewPictureCallback implements PictureCallback {
+ private final class PostViewPictureCallback
+ implements CameraPictureCallback {
@Override
- public void onPictureTaken(
- byte [] data, android.hardware.Camera camera) {
+ public void onPictureTaken(byte [] data, CameraProxy camera) {
mPostViewPictureCallbackTime = System.currentTimeMillis();
Log.v(TAG, "mShutterToPostViewCallbackTime = "
+ (mPostViewPictureCallbackTime - mShutterCallbackTime)
@@ -710,17 +713,18 @@ public class PhotoModule
}
}
- private final class RawPictureCallback implements PictureCallback {
+ private final class RawPictureCallback
+ implements CameraPictureCallback {
@Override
- public void onPictureTaken(
- byte [] rawData, android.hardware.Camera camera) {
+ public void onPictureTaken(byte [] rawData, CameraProxy camera) {
mRawPictureCallbackTime = System.currentTimeMillis();
Log.v(TAG, "mShutterToRawCallbackTime = "
+ (mRawPictureCallbackTime - mShutterCallbackTime) + "ms");
}
}
- private final class JpegPictureCallback implements PictureCallback {
+ private final class JpegPictureCallback
+ implements CameraPictureCallback {
Location mLocation;
public JpegPictureCallback(Location loc) {
@@ -728,8 +732,7 @@ public class PhotoModule
}
@Override
- public void onPictureTaken(
- final byte [] jpegData, final android.hardware.Camera camera) {
+ public void onPictureTaken(final byte [] jpegData, CameraProxy camera) {
if (mPaused) {
return;
}
@@ -841,11 +844,10 @@ public class PhotoModule
}
}
- private final class AutoFocusCallback
- implements android.hardware.Camera.AutoFocusCallback {
+ private final class AutoFocusCallback implements CameraAFCallback {
@Override
public void onAutoFocus(
- boolean focused, android.hardware.Camera camera) {
+ boolean focused, CameraProxy camera) {
if (mPaused) return;
mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
@@ -857,10 +859,10 @@ public class PhotoModule
@TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
private final class AutoFocusMoveCallback
- implements android.hardware.Camera.AutoFocusMoveCallback {
+ implements CameraAFMoveCallback {
@Override
public void onAutoFocusMoving(
- boolean moving, android.hardware.Camera camera) {
+ boolean moving, CameraProxy camera) {
mFocusManager.onAutoFocusMoving(moving);
}
}
@@ -965,10 +967,10 @@ public class PhotoModule
Util.setGpsParameters(mParameters, loc);
mCameraDevice.setParameters(mParameters);
- mCameraDevice.takePicture2(new ShutterCallback(!animateBefore),
+ mCameraDevice.takePicture(mHandler,
+ new ShutterCallback(!animateBefore),
mRawPictureCallback, mPostViewPictureCallback,
- new JpegPictureCallback(loc), mCameraState,
- mFocusManager.getFocusState());
+ new JpegPictureCallback(loc));
mNamedImages.nameNewImage(mContentResolver, mCaptureStartTime);
@@ -1408,7 +1410,7 @@ public class PhotoModule
@Override
public void autoFocus() {
mFocusStartTime = System.currentTimeMillis();
- mCameraDevice.autoFocus(mAutoFocusCallback);
+ mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
setCameraState(FOCUSING);
}
@@ -1558,11 +1560,11 @@ public class PhotoModule
mUI.setPreviewSize(mParameters.getPreviewSize());
Object st = mUI.getSurfaceTexture();
if (st != null) {
- mCameraDevice.setPreviewTextureAsync((SurfaceTexture) st);
+ mCameraDevice.setPreviewTexture((SurfaceTexture) st);
}
Log.v(TAG, "startPreview");
- mCameraDevice.startPreviewAsync();
+ mCameraDevice.startPreview();
mFocusManager.onPreviewStarted();
if (mSnapshotOnIdle) {
@@ -1769,10 +1771,10 @@ public class PhotoModule
@TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
private void updateAutoFocusMoveCallback() {
if (mParameters.getFocusMode().equals(Util.FOCUS_MODE_CONTINUOUS_PICTURE)) {
- mCameraDevice.setAutoFocusMoveCallback(
- (AutoFocusMoveCallback) mAutoFocusMoveCallback);
+ mCameraDevice.setAutoFocusMoveCallback(mHandler,
+ (CameraManager.CameraAFMoveCallback) mAutoFocusMoveCallback);
} else {
- mCameraDevice.setAutoFocusMoveCallback(null);
+ mCameraDevice.setAutoFocusMoveCallback(null, null);
}
}
diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java
index 3a0b61967..ccc2d9079 100644
--- a/src/com/android/camera/Util.java
+++ b/src/com/android/camera/Util.java
@@ -38,6 +38,7 @@ import android.hardware.Camera.Size;
import android.location.Location;
import android.net.Uri;
import android.os.Build;
+import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
@@ -310,7 +311,8 @@ public class Util {
}
}
- public static CameraManager.CameraProxy openCamera(Activity activity, int cameraId)
+ public static CameraManager.CameraProxy openCamera(
+ Activity activity, int cameraId)
throws CameraHardwareException, CameraDisabledException {
throwIfCameraDisabled(activity);
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index bba2363b9..e3efa22b6 100644
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -31,7 +31,6 @@ import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
-import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.location.Location;
import android.media.CamcorderProfile;
@@ -55,6 +54,7 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
+import com.android.camera.CameraManager.CameraPictureCallback;
import com.android.camera.CameraManager.CameraProxy;
import com.android.camera.ui.PopupManager;
import com.android.camera.ui.RotateTextToast;
@@ -114,7 +114,6 @@ public class VideoModule implements CameraModule,
private int mCameraId;
private Parameters mParameters;
- private boolean mCameraOpened = false;
private boolean mIsInReviewMode;
private boolean mSnapshotInProgress = false;
@@ -228,9 +227,8 @@ public class VideoModule implements CameraModule,
private void openCamera() {
try {
- if (!mCameraOpened) {
+ if (mCameraDevice == null) {
mCameraDevice = Util.openCamera(mActivity, mCameraId);
- mCameraOpened = true;
}
mParameters = mCameraDevice.getParameters();
} catch (CameraHardwareException e) {
@@ -449,7 +447,8 @@ public class VideoModule implements CameraModule,
mCameraDevice.setParameters(mParameters);
Log.v(TAG, "Video snapshot start");
- mCameraDevice.takePicture(null, null, null, new JpegPictureCallback(loc));
+ mCameraDevice.takePicture(mHandler,
+ null, null, null, new JpegPictureCallback(loc));
showVideoSnapshotUI(true);
mSnapshotInProgress = true;
UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
@@ -832,8 +831,8 @@ public class VideoModule implements CameraModule,
try {
if (!effectsActive()) {
- mCameraDevice.setPreviewTextureAsync(surfaceTexture);
- mCameraDevice.startPreviewAsync();
+ mCameraDevice.setPreviewTexture(surfaceTexture);
+ mCameraDevice.startPreview();
mPreviewing = true;
onPreviewStarted();
} else {
@@ -911,10 +910,7 @@ public class VideoModule implements CameraModule,
if (closeEffectsAlso) closeEffects();
mCameraDevice.setZoomChangeListener(null);
mCameraDevice.setErrorCallback(null);
- if (mCameraOpened) {
- CameraHolder.instance().release();
- }
- mCameraOpened = false;
+ CameraHolder.instance().release();
mCameraDevice = null;
mPreviewing = false;
mSnapshotInProgress = false;
@@ -1070,7 +1066,7 @@ public class VideoModule implements CameraModule,
// We stop the preview here before unlocking the device because we
// need to change the SurfaceTexture to SurfaceView for preview.
stopPreview();
- mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder());
+ mCameraDevice.setPreviewDisplay(mUI.getSurfaceHolder());
// The orientation for SurfaceTexture is different from that for
// SurfaceView. For SurfaceTexture we don't need to consider the
// display rotation. Just consider the sensor's orientation and we
@@ -1080,7 +1076,7 @@ public class VideoModule implements CameraModule,
// display rotation is considered.
mCameraDevice.setDisplayOrientation(
Util.getDisplayOrientation(mDisplayRotation, mCameraId));
- mCameraDevice.startPreviewAsync();
+ mCameraDevice.startPreview();
mPreviewing = true;
mMediaRecorder.setPreviewDisplay(mUI.getSurfaceHolder().getSurface());
}
@@ -1124,7 +1120,6 @@ public class VideoModule implements CameraModule,
setupMediaRecorderPreviewDisplay();
// Unlock the camera object before passing it to media recorder.
mCameraDevice.unlock();
- mCameraDevice.waitDone();
mMediaRecorder.setCamera(mCameraDevice.getCamera());
if (!mCaptureTimeLapse) {
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
@@ -1446,7 +1441,8 @@ public class VideoModule implements CameraModule,
return;
}
- if (!mCameraDevice.waitDone()) return;
+ //??
+ //if (!mCameraDevice.waitDone()) return;
mCurrentVideoUri = null;
if (effectsActive()) {
initializeEffectsRecording();
@@ -1613,7 +1609,6 @@ public class VideoModule implements CameraModule,
releaseMediaRecorder();
if (!mPaused) {
mCameraDevice.lock();
- mCameraDevice.waitDone();
if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) {
stopPreview();
mUI.hideSurfaceView();
@@ -2129,7 +2124,7 @@ public class VideoModule implements CameraModule,
mUI.onSwitchMode(toCamera);
}
- private final class JpegPictureCallback implements PictureCallback {
+ private final class JpegPictureCallback implements CameraPictureCallback {
Location mLocation;
public JpegPictureCallback(Location loc) {
@@ -2137,7 +2132,7 @@ public class VideoModule implements CameraModule,
}
@Override
- public void onPictureTaken(byte [] jpegData, android.hardware.Camera camera) {
+ public void onPictureTaken(byte [] jpegData, CameraProxy camera) {
Log.v(TAG, "onPictureTaken");
mSnapshotInProgress = false;
showVideoSnapshotUI(false);