diff options
author | Michael Kolb <kolby@google.com> | 2013-01-29 10:33:22 -0800 |
---|---|---|
committer | Michael Kolb <kolby@google.com> | 2013-01-29 10:51:20 -0800 |
commit | 8872c23e739de38d74f04a8c852ebb5199c905f6 (patch) | |
tree | 63e6ca8d492217f647ae87527e0039e5a0da2c97 /src/com/android/camera/CameraManager.java | |
parent | c58d88b469fd345df9bdbff0c147d91caa9959b5 (diff) | |
download | android_packages_apps_Snap-8872c23e739de38d74f04a8c852ebb5199c905f6.tar.gz android_packages_apps_Snap-8872c23e739de38d74f04a8c852ebb5199c905f6.tar.bz2 android_packages_apps_Snap-8872c23e739de38d74f04a8c852ebb5199c905f6.zip |
Move Camera Java/Native source into Gallery2
Change-Id: I968efe4d656e88a7760d3c0044f65b4adac2ddd1
Diffstat (limited to 'src/com/android/camera/CameraManager.java')
-rw-r--r-- | src/com/android/camera/CameraManager.java | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/src/com/android/camera/CameraManager.java b/src/com/android/camera/CameraManager.java new file mode 100644 index 000000000..854e1058f --- /dev/null +++ b/src/com/android/camera/CameraManager.java @@ -0,0 +1,490 @@ +/* + * Copyright (C) 2012 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.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.ConditionVariable; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.view.SurfaceHolder; +import android.util.Log; + +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(); + + // Thread progress signals + private ConditionVariable mSig = new ConditionVariable(); + + private Parameters mParameters; + private IOException mReconnectException; + + 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_PARAMETERS_ASYNC = 21; + private static final int WAIT_FOR_IDLE = 22; + private static final int SET_PREVIEW_DISPLAY_ASYNC = 23; + private static final int SET_PREVIEW_CALLBACK = 24; + private static final int ENABLE_SHUTTER_SOUND = 25; + + private Handler mCameraHandler; + private CameraProxy mCameraProxy; + private android.hardware.Camera mCamera; + + public static CameraManager instance() { + return sCameraManager; + } + + private CameraManager() { + 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); + } + + /* + * This method does not deal with the build version check. Everyone should + * check first before sending message to this handler. + */ + @Override + public void handleMessage(final Message msg) { + try { + switch (msg.what) { + case RELEASE: + mCamera.release(); + mCamera = null; + mCameraProxy = null; + break; + + case RECONNECT: + mReconnectException = null; + try { + mCamera.reconnect(); + } catch (IOException ex) { + mReconnectException = ex; + } + break; + + case UNLOCK: + mCamera.unlock(); + break; + + case LOCK: + mCamera.lock(); + break; + + case SET_PREVIEW_TEXTURE_ASYNC: + setPreviewTexture(msg.obj); + return; // no need to call mSig.open() + + case SET_PREVIEW_DISPLAY_ASYNC: + try { + mCamera.setPreviewDisplay((SurfaceHolder) msg.obj); + } catch(IOException e) { + throw new RuntimeException(e); + } + return; // no need to call mSig.open() + + case START_PREVIEW_ASYNC: + mCamera.startPreview(); + return; // no need to call mSig.open() + + case STOP_PREVIEW: + mCamera.stopPreview(); + break; + + case SET_PREVIEW_CALLBACK_WITH_BUFFER: + mCamera.setPreviewCallbackWithBuffer( + (PreviewCallback) msg.obj); + break; + + case ADD_CALLBACK_BUFFER: + mCamera.addCallbackBuffer((byte[]) msg.obj); + break; + + case AUTO_FOCUS: + mCamera.autoFocus((AutoFocusCallback) msg.obj); + break; + + case CANCEL_AUTO_FOCUS: + mCamera.cancelAutoFocus(); + break; + + case SET_AUTO_FOCUS_MOVE_CALLBACK: + setAutoFocusMoveCallback(mCamera, msg.obj); + break; + + case SET_DISPLAY_ORIENTATION: + mCamera.setDisplayOrientation(msg.arg1); + break; + + case SET_ZOOM_CHANGE_LISTENER: + mCamera.setZoomChangeListener( + (OnZoomChangeListener) msg.obj); + break; + + case SET_FACE_DETECTION_LISTENER: + setFaceDetectionListener((FaceDetectionListener) msg.obj); + break; + + case START_FACE_DETECTION: + startFaceDetection(); + break; + + case STOP_FACE_DETECTION: + stopFaceDetection(); + break; + + case SET_ERROR_CALLBACK: + mCamera.setErrorCallback((ErrorCallback) msg.obj); + break; + + case SET_PARAMETERS: + mCamera.setParameters((Parameters) msg.obj); + break; + + case GET_PARAMETERS: + mParameters = mCamera.getParameters(); + break; + + case SET_PARAMETERS_ASYNC: + mCamera.setParameters((Parameters) msg.obj); + return; // no need to call mSig.open() + + case SET_PREVIEW_CALLBACK: + mCamera.setPreviewCallback((PreviewCallback) msg.obj); + break; + + case ENABLE_SHUTTER_SOUND: + enableShutterSound((msg.arg1 == 1) ? true : false); + break; + + case WAIT_FOR_IDLE: + // do nothing + break; + + 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; + mCameraProxy = null; + } + throw e; + } + mSig.open(); + } + } + + @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) + private void setAutoFocusMoveCallback(android.hardware.Camera camera, + Object cb) { + camera.setAutoFocusMoveCallback((AutoFocusMoveCallback) cb); + } + + // 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) { + mCameraProxy = new CameraProxy(); + return mCameraProxy; + } else { + return null; + } + } + + public class CameraProxy { + private CameraProxy() { + Assert(mCamera != null); + } + + public android.hardware.Camera getCamera() { + return mCamera; + } + + public void release() { + mSig.close(); + mCameraHandler.sendEmptyMessage(RELEASE); + mSig.block(); + } + + public void reconnect() throws IOException { + mSig.close(); + mCameraHandler.sendEmptyMessage(RECONNECT); + mSig.block(); + if (mReconnectException != null) { + throw mReconnectException; + } + } + + public void unlock() { + mSig.close(); + mCameraHandler.sendEmptyMessage(UNLOCK); + mSig.block(); + } + + public void lock() { + mSig.close(); + mCameraHandler.sendEmptyMessage(LOCK); + mSig.block(); + } + + @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); + } + + public void stopPreview() { + mSig.close(); + mCameraHandler.sendEmptyMessage(STOP_PREVIEW); + mSig.block(); + } + + public void setPreviewCallback(final PreviewCallback cb) { + mSig.close(); + mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK, cb).sendToTarget(); + mSig.block(); + } + + public void setPreviewCallbackWithBuffer(final PreviewCallback cb) { + mSig.close(); + mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK_WITH_BUFFER, cb).sendToTarget(); + mSig.block(); + } + + public void addCallbackBuffer(byte[] callbackBuffer) { + mSig.close(); + mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer).sendToTarget(); + mSig.block(); + } + + public void autoFocus(AutoFocusCallback cb) { + mSig.close(); + mCameraHandler.obtainMessage(AUTO_FOCUS, cb).sendToTarget(); + mSig.block(); + } + + public void cancelAutoFocus() { + mSig.close(); + mCameraHandler.sendEmptyMessage(CANCEL_AUTO_FOCUS); + mSig.block(); + } + + @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) + public void setAutoFocusMoveCallback(AutoFocusMoveCallback cb) { + mSig.close(); + mCameraHandler.obtainMessage(SET_AUTO_FOCUS_MOVE_CALLBACK, cb).sendToTarget(); + mSig.block(); + } + + public void takePicture(final ShutterCallback shutter, final PictureCallback raw, + final PictureCallback postview, final PictureCallback jpeg) { + mSig.close(); + // Too many parameters, so use post for simplicity + mCameraHandler.post(new Runnable() { + @Override + public void run() { + mCamera.takePicture(shutter, raw, postview, jpeg); + mSig.open(); + } + }); + mSig.block(); + } + + public void takePicture2(final ShutterCallback shutter, final PictureCallback raw, + final PictureCallback postview, final PictureCallback jpeg, + final int cameraState, final int focusState) { + mSig.close(); + // 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; + } + mSig.open(); + } + }); + mSig.block(); + } + + public void setDisplayOrientation(int degrees) { + mSig.close(); + mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0) + .sendToTarget(); + mSig.block(); + } + + public void setZoomChangeListener(OnZoomChangeListener listener) { + mSig.close(); + mCameraHandler.obtainMessage(SET_ZOOM_CHANGE_LISTENER, listener).sendToTarget(); + mSig.block(); + } + + @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) + public void setFaceDetectionListener(FaceDetectionListener listener) { + mSig.close(); + mCameraHandler.obtainMessage(SET_FACE_DETECTION_LISTENER, listener).sendToTarget(); + mSig.block(); + } + + public void startFaceDetection() { + mSig.close(); + mCameraHandler.sendEmptyMessage(START_FACE_DETECTION); + mSig.block(); + } + + public void stopFaceDetection() { + mSig.close(); + mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION); + mSig.block(); + } + + public void setErrorCallback(ErrorCallback cb) { + mSig.close(); + mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, cb).sendToTarget(); + mSig.block(); + } + + public void setParameters(Parameters params) { + mSig.close(); + mCameraHandler.obtainMessage(SET_PARAMETERS, params).sendToTarget(); + mSig.block(); + } + + public void setParametersAsync(Parameters params) { + mCameraHandler.removeMessages(SET_PARAMETERS_ASYNC); + mCameraHandler.obtainMessage(SET_PARAMETERS_ASYNC, params).sendToTarget(); + } + + public Parameters getParameters() { + mSig.close(); + mCameraHandler.sendEmptyMessage(GET_PARAMETERS); + mSig.block(); + Parameters parameters = mParameters; + mParameters = null; + return parameters; + } + + public void enableShutterSound(boolean enable) { + mSig.close(); + mCameraHandler.obtainMessage( + ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0).sendToTarget(); + mSig.block(); + } + + public void waitForIdle() { + mSig.close(); + mCameraHandler.sendEmptyMessage(WAIT_FOR_IDLE); + mSig.block(); + } + } +} |