summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/CameraManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/CameraManager.java')
-rw-r--r--src/com/android/camera/CameraManager.java670
1 files changed, 246 insertions, 424 deletions
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);
}
}