summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAngus Kong <shkong@google.com>2013-03-27 21:58:31 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2013-03-27 21:58:31 +0000
commit2a23c46ca52e9af02aac7c454a89d2b9c4f2e539 (patch)
tree15246116a8604d9393073e609f03057af773f6ae
parentc6af786bdc2488c2c7a69846b81261f31ffdccb3 (diff)
parentdcb0ef1d6eacdd7d18a6881ae75f67c9851a858c (diff)
downloadandroid_packages_apps_Snap-2a23c46ca52e9af02aac7c454a89d2b9c4f2e539.tar.gz
android_packages_apps_Snap-2a23c46ca52e9af02aac7c454a89d2b9c4f2e539.tar.bz2
android_packages_apps_Snap-2a23c46ca52e9af02aac7c454a89d2b9c4f2e539.zip
Merge "Make camera calls asynchronous" into gb-ub-photos-bryce
-rw-r--r--src/com/android/camera/CameraManager.java188
-rw-r--r--src/com/android/camera/PhotoModule.java29
-rw-r--r--src/com/android/camera/VideoModule.java2
3 files changed, 112 insertions, 107 deletions
diff --git a/src/com/android/camera/CameraManager.java b/src/com/android/camera/CameraManager.java
index 854e1058f..0306e295c 100644
--- a/src/com/android/camera/CameraManager.java
+++ b/src/com/android/camera/CameraManager.java
@@ -34,22 +34,24 @@ 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 android.view.SurfaceHolder;
import com.android.gallery3d.common.ApiHelper;
import java.io.IOException;
+import java.util.concurrent.SynchronousQueue;
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 boolean mParametersIsDirty;
+ private SynchronousQueue<Parameters> mParametersQueue =
+ new SynchronousQueue<Parameters>();
+ private SynchronousQueue<IOExceptionHolder> mReconnectExceptionQueue =
+ new SynchronousQueue<IOExceptionHolder>();
private static final int RELEASE = 1;
private static final int RECONNECT = 2;
@@ -72,15 +74,21 @@ public class CameraManager {
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 static final int SET_PREVIEW_DISPLAY_ASYNC = 22;
+ private static final int SET_PREVIEW_CALLBACK = 23;
+ private static final int ENABLE_SHUTTER_SOUND = 24;
private Handler mCameraHandler;
private CameraProxy mCameraProxy;
private android.hardware.Camera mCamera;
+ // 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;
+ }
+
public static CameraManager instance() {
return sCameraManager;
}
@@ -115,7 +123,7 @@ public class CameraManager {
private void setPreviewTexture(Object surfaceTexture) {
try {
mCamera.setPreviewTexture((SurfaceTexture) surfaceTexture);
- } catch(IOException e) {
+ } catch (IOException e) {
throw new RuntimeException(e);
}
}
@@ -137,114 +145,119 @@ public class CameraManager {
mCamera.release();
mCamera = null;
mCameraProxy = null;
- break;
+ return;
case RECONNECT:
- mReconnectException = null;
+ IOExceptionHolder holder = new IOExceptionHolder();
+ holder.ex = null;
try {
mCamera.reconnect();
} catch (IOException ex) {
- mReconnectException = ex;
+ holder.ex = ex;
}
- break;
+ try {
+ mReconnectExceptionQueue.put(holder);
+ } catch (InterruptedException ex) {
+ }
+ return;
case UNLOCK:
mCamera.unlock();
- break;
+ return;
case LOCK:
mCamera.lock();
- break;
+ return;
case SET_PREVIEW_TEXTURE_ASYNC:
setPreviewTexture(msg.obj);
- return; // no need to call mSig.open()
+ return;
case SET_PREVIEW_DISPLAY_ASYNC:
try {
mCamera.setPreviewDisplay((SurfaceHolder) msg.obj);
- } catch(IOException e) {
+ } catch (IOException e) {
throw new RuntimeException(e);
}
- return; // no need to call mSig.open()
+ return;
case START_PREVIEW_ASYNC:
mCamera.startPreview();
- return; // no need to call mSig.open()
+ return;
case STOP_PREVIEW:
mCamera.stopPreview();
- break;
+ return;
case SET_PREVIEW_CALLBACK_WITH_BUFFER:
mCamera.setPreviewCallbackWithBuffer(
(PreviewCallback) msg.obj);
- break;
+ return;
case ADD_CALLBACK_BUFFER:
mCamera.addCallbackBuffer((byte[]) msg.obj);
- break;
+ return;
case AUTO_FOCUS:
mCamera.autoFocus((AutoFocusCallback) msg.obj);
- break;
+ return;
case CANCEL_AUTO_FOCUS:
mCamera.cancelAutoFocus();
- break;
+ return;
case SET_AUTO_FOCUS_MOVE_CALLBACK:
setAutoFocusMoveCallback(mCamera, msg.obj);
- break;
+ return;
case SET_DISPLAY_ORIENTATION:
mCamera.setDisplayOrientation(msg.arg1);
- break;
+ return;
case SET_ZOOM_CHANGE_LISTENER:
mCamera.setZoomChangeListener(
(OnZoomChangeListener) msg.obj);
- break;
+ return;
case SET_FACE_DETECTION_LISTENER:
setFaceDetectionListener((FaceDetectionListener) msg.obj);
- break;
+ return;
case START_FACE_DETECTION:
startFaceDetection();
- break;
+ return;
case STOP_FACE_DETECTION:
stopFaceDetection();
- break;
+ return;
case SET_ERROR_CALLBACK:
mCamera.setErrorCallback((ErrorCallback) msg.obj);
- break;
+ return;
case SET_PARAMETERS:
mCamera.setParameters((Parameters) msg.obj);
- break;
+ return;
case GET_PARAMETERS:
- mParameters = mCamera.getParameters();
- break;
+ try {
+ mParametersQueue.put(mCamera.getParameters());
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ return;
case SET_PARAMETERS_ASYNC:
mCamera.setParameters((Parameters) msg.obj);
- return; // no need to call mSig.open()
+ return;
case SET_PREVIEW_CALLBACK:
mCamera.setPreviewCallback((PreviewCallback) msg.obj);
- break;
+ return;
case ENABLE_SHUTTER_SOUND:
enableShutterSound((msg.arg1 == 1) ? true : false);
- break;
-
- case WAIT_FOR_IDLE:
- // do nothing
- break;
+ return;
default:
throw new RuntimeException("Invalid CameraProxy message=" + msg.what);
@@ -261,7 +274,6 @@ public class CameraManager {
}
throw e;
}
- mSig.open();
}
}
@@ -283,6 +295,7 @@ public class CameraManager {
mCamera = android.hardware.Camera.open(cameraId);
if (mCamera != null) {
mCameraProxy = new CameraProxy();
+ mParametersIsDirty = true;
return mCameraProxy;
} else {
return null;
@@ -290,6 +303,15 @@ public class CameraManager {
}
public class CameraProxy {
+ private ConditionVariable mWaitDoneLock = new ConditionVariable();
+ private Runnable mUnlockRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mWaitDoneLock.open();
+ }
+ };
+
+
private CameraProxy() {
Assert(mCamera != null);
}
@@ -299,30 +321,27 @@ public class CameraManager {
}
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;
+ IOExceptionHolder holder = null;
+ try {
+ holder = mReconnectExceptionQueue.take();
+ } catch (InterruptedException ex) {
+ }
+ if (holder == null || holder.ex != null) {
+ throw holder.ex;
}
}
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)
@@ -339,66 +358,49 @@ public class CameraManager {
}
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.removeMessages(AUTO_FOCUS);
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
@@ -410,81 +412,69 @@ public class CameraManager {
+ ", 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();
+ // TODO: check if this synchronous version is necessary
+ mParametersIsDirty = true;
mCameraHandler.obtainMessage(SET_PARAMETERS, params).sendToTarget();
- mSig.block();
}
public void setParametersAsync(Parameters params) {
+ mParametersIsDirty = true;
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;
+ if (mParametersIsDirty || mParameters == null) {
+ mCameraHandler.sendEmptyMessage(GET_PARAMETERS);
+ try {
+ mParameters = mParametersQueue.take();
+ mParametersIsDirty = false;
+ } catch (InterruptedException ex) {
+ }
+ }
+ return mParameters;
}
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();
+ public void waitDone() {
+ mWaitDoneLock.close();
+ mCameraHandler.post(mUnlockRunnable);
+ mWaitDoneLock.block();
}
}
}
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index a9d5cc6a6..f4bd4ce1d 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -173,6 +173,13 @@ public class PhotoModule
}
};
+ private Runnable mFlashRunnable = new Runnable() {
+ @Override
+ public void run() {
+ animateFlash();
+ }
+ };
+
private final StringBuilder mBuilder = new StringBuilder();
private final Formatter mFormatter = new Formatter(mBuilder);
private final Object[] mFormatterArgs = new Object[1];
@@ -205,7 +212,6 @@ public class PhotoModule
private LocationManager mLocationManager;
- private final ShutterCallback mShutterCallback = new ShutterCallback();
private final PostViewPictureCallback mPostViewPictureCallback =
new PostViewPictureCallback();
private final RawPictureCallback mRawPictureCallback =
@@ -721,11 +727,21 @@ public class PhotoModule
private final class ShutterCallback
implements android.hardware.Camera.ShutterCallback {
+
+ private boolean mAnimateFlash;
+
+ public ShutterCallback(boolean animateFlash) {
+ mAnimateFlash = animateFlash;
+ }
+
@Override
public void onShutter() {
mShutterCallbackTime = System.currentTimeMillis();
mShutterLag = mShutterCallbackTime - mCaptureStartTime;
Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
+ if (mAnimateFlash) {
+ mActivity.runOnUiThread(mFlashRunnable);
+ }
}
}
@@ -988,13 +1004,10 @@ public class PhotoModule
Util.setGpsParameters(mParameters, loc);
mCameraDevice.setParameters(mParameters);
- mCameraDevice.takePicture2(mShutterCallback, mRawPictureCallback,
- mPostViewPictureCallback, new JpegPictureCallback(loc),
- mCameraState, mFocusManager.getFocusState());
-
- if (!animateBefore) {
- animateFlash();
- }
+ mCameraDevice.takePicture2(new ShutterCallback(!animateBefore),
+ mRawPictureCallback, mPostViewPictureCallback,
+ new JpegPictureCallback(loc), mCameraState,
+ mFocusManager.getFocusState());
mNamedImages.nameNewImage(mContentResolver, mCaptureStartTime);
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index 94c862502..ea50033fc 100644
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -1123,6 +1123,7 @@ public class VideoModule implements CameraModule,
setupMediaRecorderPreviewDisplay();
// Unlock the camera object before passing it to media recorder.
mActivity.mCameraDevice.unlock();
+ mActivity.mCameraDevice.waitDone();
mMediaRecorder.setCamera(mActivity.mCameraDevice.getCamera());
if (!mCaptureTimeLapse) {
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
@@ -1647,6 +1648,7 @@ public class VideoModule implements CameraModule,
releaseMediaRecorder();
if (!mPaused) {
mActivity.mCameraDevice.lock();
+ mActivity.mCameraDevice.waitDone();
if (ApiHelper.HAS_SURFACE_TEXTURE &&
!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) {
stopPreview();