summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/AndroidCameraManagerImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/AndroidCameraManagerImpl.java')
-rw-r--r--src/com/android/camera/AndroidCameraManagerImpl.java779
1 files changed, 779 insertions, 0 deletions
diff --git a/src/com/android/camera/AndroidCameraManagerImpl.java b/src/com/android/camera/AndroidCameraManagerImpl.java
new file mode 100644
index 000000000..897aa9252
--- /dev/null
+++ b/src/com/android/camera/AndroidCameraManagerImpl.java
@@ -0,0 +1,779 @@
+/*
+ * 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(msg.arg1);
+ 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(SurfaceTexture surfaceTexture) {
+ mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture).sendToTarget();
+ }
+
+ @Override
+ public void setPreviewDisplay(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, CameraPreviewDataCallback cb) {
+ mCameraHandler.obtainMessage(
+ SET_PREVIEW_CALLBACK,
+ PreviewCallbackForward.getNewInstance(handler, this, cb)).sendToTarget();
+ }
+
+ @Override
+ public void setPreviewDataCallbackWithBuffer(
+ Handler handler, CameraPreviewDataCallback cb) {
+ mCameraHandler.obtainMessage(
+ SET_PREVIEW_CALLBACK_WITH_BUFFER,
+ PreviewCallbackForward.getNewInstance(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.getNewInstance(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, CameraAFMoveCallback cb) {
+ mCameraHandler.obtainMessage(
+ SET_AUTO_FOCUS_MOVE_CALLBACK,
+ AFMoveCallbackForward.getNewInstance(handler, this, cb)).sendToTarget();
+ }
+
+ @Override
+ public void takePicture(
+ Handler handler,
+ CameraShutterCallback shutter,
+ CameraPictureCallback raw,
+ CameraPictureCallback post,
+ CameraPictureCallback jpeg) {
+ mCameraHandler.requestTakePicture(
+ ShutterCallbackForward.getNewInstance(handler, this, shutter),
+ PictureCallbackForward.getNewInstance(handler, this, raw),
+ PictureCallbackForward.getNewInstance(handler, this, post),
+ PictureCallbackForward.getNewInstance(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 setFaceDetectionCallback(
+ Handler handler, CameraFaceDetectionCallback cb) {
+ mCameraHandler.obtainMessage(
+ SET_FACE_DETECTION_LISTENER,
+ FaceDetectionCallbackForward.getNewInstance(handler, this, cb)).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 a new 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 parameter is null.
+ */
+ public static AFCallbackForward getNewInstance(
+ 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 a new 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 parameter is null.
+ */
+ public static AFMoveCallbackForward getNewInstance(
+ 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 a new 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 parameter is null.
+ */
+ public static ShutterCallbackForward getNewInstance(
+ 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 a new 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 parameters is null.
+ */
+ public static PictureCallbackForward getNewInstance(
+ 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 a new 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 PreviewCallbackForward},
+ * or null if any parameters is null.
+ */
+ public static PreviewCallbackForward getNewInstance(
+ 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);
+ }
+ });
+ }
+ }
+
+ private static class FaceDetectionCallbackForward implements FaceDetectionListener {
+ private final Handler mHandler;
+ private final CameraFaceDetectionCallback mCallback;
+ private final CameraProxy mCamera;
+
+ /**
+ * Returns a new instance of {@link FaceDetectionCallbackForward}.
+ *
+ * @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 FaceDetectionCallbackForward},
+ * or null if any parameter is null.
+ */
+ public static FaceDetectionCallbackForward getNewInstance(
+ Handler handler, CameraProxy camera, CameraFaceDetectionCallback cb) {
+ if (handler == null || camera == null || cb == null) return null;
+ return new FaceDetectionCallbackForward(handler, camera, cb);
+ }
+
+ private FaceDetectionCallbackForward(
+ Handler h, CameraProxy camera, CameraFaceDetectionCallback cb) {
+ mHandler = h;
+ mCamera = camera;
+ mCallback = cb;
+ }
+
+ @Override
+ public void onFaceDetection(
+ final Camera.Face[] faces, Camera camera) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onFaceDetection(faces, mCamera);
+ }
+ });
+ }
+ }
+}