OSDN Git Service

Merge "add Grad filter" into gb-ub-photos-carlsbad
authorJohn Hoford <hoford@google.com>
Tue, 30 Jul 2013 00:27:30 +0000 (00:27 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Tue, 30 Jul 2013 00:27:32 +0000 (00:27 +0000)
14 files changed:
res/drawable-xhdpi/ic_switch_refocus.png [new file with mode: 0644]
res/values/strings.xml
src/com/android/camera/AndroidCameraManagerImpl.java [new file with mode: 0644]
src/com/android/camera/CameraActivity.java
src/com/android/camera/CameraHolder.java
src/com/android/camera/CameraManager.java
src/com/android/camera/CameraManagerFactory.java [new file with mode: 0644]
src/com/android/camera/EffectsRecorder.java
src/com/android/camera/PhotoModule.java
src/com/android/camera/Util.java
src/com/android/camera/VideoModule.java
src/com/android/camera/ui/CameraSwitcher.java
src/com/android/gallery3d/filtershow/FilterShowActivity.java
src_pd/com/android/gallery3d/util/RefocusHelper.java [new file with mode: 0644]

diff --git a/res/drawable-xhdpi/ic_switch_refocus.png b/res/drawable-xhdpi/ic_switch_refocus.png
new file mode 100644 (file)
index 0000000..3175f35
Binary files /dev/null and b/res/drawable-xhdpi/ic_switch_refocus.png differ
index c110e79..f2d69c8 100644 (file)
     <string name="accessibility_switch_to_panorama">Switch to panorama</string>
     <!-- The button to switch to new Panorama mode. [CHAR LIMIT = NONE] -->
     <string name="accessibility_switch_to_new_panorama">Switch to new panorama</string>
+    <!-- The button to switch to the Re-Focus mode. [CHAR LIMIT = NONE] -->
+    <string name="accessibility_switch_to_refocus">Switch to Refocus</string>
     <!-- The button in review mode indicating that the photo taking, video recording, and panorama saving session should be canceled [CHAR LIMIT = NONE] -->
     <string name="accessibility_review_cancel">Review cancel</string>
     <!-- The button in review mode indicating that the taken photo/video is OK to be attached/uploaded [CHAR LIMIT = NONE] -->
diff --git a/src/com/android/camera/AndroidCameraManagerImpl.java b/src/com/android/camera/AndroidCameraManagerImpl.java
new file mode 100644 (file)
index 0000000..8ffdb42
--- /dev/null
@@ -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);
+                }
+            });
+        }
+    }
+}
index d875670..7013036 100644 (file)
@@ -50,6 +50,7 @@ import com.android.camera.ui.FilmStripView;
 import com.android.gallery3d.R;
 import com.android.gallery3d.common.ApiHelper;
 import com.android.gallery3d.util.LightCycleHelper;
+import com.android.gallery3d.util.RefocusHelper;
 
 public class CameraActivity extends Activity
     implements CameraSwitchListener {
@@ -477,6 +478,9 @@ public class CameraActivity extends Activity
             case CameraSwitcher.LIGHTCYCLE_MODULE_INDEX:
                 mCurrentModule = LightCycleHelper.createPanoramaModule();
                 break;
+            case CameraSwitcher.REFOCUS_MODULE_INDEX:
+                mCurrentModule = RefocusHelper.createRefocusModule();
+                break;
            default:
                break;
         }
index 5b7bbfd..d913df7 100644 (file)
@@ -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();
index c7005cf..e4a0667 100644 (file)
 
 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 (file)
index 0000000..914ebb2
--- /dev/null
@@ -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;
+    }
+}
index 2db44c7..4bf8d41 100644 (file)
@@ -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
index 361f111..6140848 100644 (file)
@@ -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);
         }
     }
 
index 3a0b619..ccc2d90 100644 (file)
@@ -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);
 
index bba2363..e3efa22 100644 (file)
@@ -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);
index 90d88d2..6e43215 100644 (file)
@@ -49,10 +49,12 @@ public class CameraSwitcher extends RotateImageView
     public static final int PHOTO_MODULE_INDEX = 0;
     public static final int VIDEO_MODULE_INDEX = 1;
     public static final int LIGHTCYCLE_MODULE_INDEX = 2;
+    public static final int REFOCUS_MODULE_INDEX = 3;
     private static final int[] DRAW_IDS = {
             R.drawable.ic_switch_camera,
             R.drawable.ic_switch_video,
-            R.drawable.ic_switch_photosphere
+            R.drawable.ic_switch_photosphere,
+            R.drawable.ic_switch_refocus
     };
     public interface CameraSwitchListener {
         public void onCameraSelected(int i);
@@ -186,6 +188,10 @@ public class CameraSwitcher extends RotateImageView
                     item.setContentDescription(getContext().getResources().getString(
                             R.string.accessibility_switch_to_new_panorama));
                     break;
+                case R.drawable.ic_switch_refocus:
+                    item.setContentDescription(getContext().getResources().getString(
+                            R.string.accessibility_switch_to_refocus));
+                    break;
                 default:
                     break;
             }
index d822553..8bbdd0c 100644 (file)
@@ -899,6 +899,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
         super.onConfigurationChanged(newConfig);
         setDefaultValues();
         loadXML();
+        fillCategories();
         loadMainPanel();
 
         // mLoadBitmapTask==null implies you have looked at the intent
diff --git a/src_pd/com/android/gallery3d/util/RefocusHelper.java b/src_pd/com/android/gallery3d/util/RefocusHelper.java
new file mode 100644 (file)
index 0000000..39ded47
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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.gallery3d.util;
+
+import com.android.camera.CameraModule;
+
+public class RefocusHelper {
+    public static CameraModule createRefocusModule() {
+        return null;
+    }
+}