diff options
-rw-r--r-- | src/com/android/camera/AndroidCameraManagerImpl.java | 737 | ||||
-rw-r--r-- | src/com/android/camera/CameraHolder.java | 3 | ||||
-rw-r--r-- | src/com/android/camera/CameraManager.java | 670 | ||||
-rw-r--r-- | src/com/android/camera/CameraManagerFactory.java | 37 | ||||
-rw-r--r-- | src/com/android/camera/EffectsRecorder.java | 9 | ||||
-rw-r--r-- | src/com/android/camera/PhotoModule.java | 56 | ||||
-rw-r--r-- | src/com/android/camera/Util.java | 4 | ||||
-rw-r--r-- | src/com/android/camera/VideoModule.java | 31 |
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); |