summaryrefslogtreecommitdiffstats
path: root/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java')
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java344
1 files changed, 223 insertions, 121 deletions
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
index 2a30063..2fc4ad3 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
@@ -65,6 +65,7 @@ class AndroidCamera2AgentImpl extends CameraAgent {
private final DispatchThread mDispatchThread;
private final CameraManager mCameraManager;
private final MediaActionSound mNoisemaker;
+ private CameraExceptionHandler mExceptionHandler;
/**
* Number of camera devices. The length of {@code mCameraDevices} does not reveal this
@@ -86,6 +87,7 @@ class AndroidCamera2AgentImpl extends CameraAgent {
mCameraHandlerThread = new HandlerThread("Camera2 Handler Thread");
mCameraHandlerThread.start();
mCameraHandler = new Camera2Handler(mCameraHandlerThread.getLooper());
+ mExceptionHandler = new CameraExceptionHandler(mCameraHandler);
mCameraState = new AndroidCamera2StateHolder();
mDispatchThread = new DispatchThread(mCameraHandler, mCameraHandlerThread);
mDispatchThread.start();
@@ -134,11 +136,6 @@ class AndroidCamera2AgentImpl extends CameraAgent {
// TODO: Implement
@Override
- public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
- Handler handler) {}
-
- // TODO: Implement
- @Override
public void recycle() {}
// TODO: Some indices may now be invalid; ensure everyone can handle that and update the docs
@@ -159,8 +156,23 @@ class AndroidCamera2AgentImpl extends CameraAgent {
return mDispatchThread;
}
+ @Override
+ protected CameraStateHolder getCameraState() {
+ return mCameraState;
+ }
+
+ @Override
+ protected CameraExceptionHandler getCameraExceptionHandler() {
+ return mExceptionHandler;
+ }
+
+ @Override
+ public void setCameraExceptionHandler(CameraExceptionHandler exceptionHandler) {
+ mExceptionHandler = exceptionHandler;
+ }
+
private static abstract class CaptureAvailableListener
- extends CameraCaptureSession.CaptureListener
+ extends CameraCaptureSession.CaptureCallback
implements ImageReader.OnImageAvailableListener {};
private class Camera2Handler extends HistoryHandler {
@@ -168,6 +180,7 @@ class AndroidCamera2AgentImpl extends CameraAgent {
private CameraOpenCallback mOpenCallback;
private int mCameraIndex;
private String mCameraId;
+ private int mCancelAfPending = 0;
// Available in CAMERA_UNCONFIGURED state and above:
private CameraDevice mCamera;
@@ -208,14 +221,16 @@ class AndroidCamera2AgentImpl extends CameraAgent {
@Override
public void handleMessage(final Message msg) {
super.handleMessage(msg);
+ Log.v(TAG, "handleMessage - action = '" + CameraActions.stringify(msg.what) + "'");
+ int cameraAction = msg.what;
try {
- switch(msg.what) {
+ switch (cameraAction) {
case CameraActions.OPEN_CAMERA:
case CameraActions.RECONNECT: {
CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj;
int cameraIndex = msg.arg1;
- if (mCameraState.getState() != AndroidCamera2StateHolder.CAMERA_UNOPENED) {
+ if (mCameraState.getState() > AndroidCamera2StateHolder.CAMERA_UNOPENED) {
openCallback.onDeviceOpenedAlready(cameraIndex,
generateHistoryString(cameraIndex));
break;
@@ -231,7 +246,7 @@ class AndroidCamera2AgentImpl extends CameraAgent {
mOpenCallback.onCameraDisabled(msg.arg1);
break;
}
- mCameraManager.openCamera(mCameraId, mCameraDeviceStateListener, this);
+ mCameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, this);
break;
}
@@ -297,7 +312,7 @@ class AndroidCamera2AgentImpl extends CameraAgent {
mSession.setRepeatingRequest(
mPersistentSettings.createRequest(mCamera,
CameraDevice.TEMPLATE_PREVIEW, mPreviewSurface),
- /*listener*/mCameraResultStateListener, /*handler*/this);
+ /*listener*/mCameraResultStateCallback, /*handler*/this);
} catch(CameraAccessException ex) {
Log.w(TAG, "Unable to start preview", ex);
changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
@@ -305,6 +320,10 @@ class AndroidCamera2AgentImpl extends CameraAgent {
break;
}
+ // FIXME: We need to tear down the CameraCaptureSession here
+ // (and unlock the CameraSettings object from our
+ // CameraProxy) so that the preview/photo sizes can be
+ // changed again while no preview is running.
case CameraActions.STOP_PREVIEW: {
if (mCameraState.getState() <
AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
@@ -356,6 +375,11 @@ class AndroidCamera2AgentImpl extends CameraAgent {
}
case CameraActions.AUTO_FOCUS: {
+ if (mCancelAfPending > 0) {
+ Log.v(TAG, "handleMessage - Ignored AUTO_FOCUS because there was "
+ + mCancelAfPending + " pending CANCEL_AUTO_FOCUS messages");
+ break; // ignore AF because a CANCEL_AF is queued after this
+ }
// We only support locking the focus while a preview is being displayed.
// However, it can be requested multiple times in succession; the effect of
// the subsequent invocations is determined by the focus mode defined in the
@@ -375,8 +399,8 @@ class AndroidCamera2AgentImpl extends CameraAgent {
// However, it will probably take longer than that, so once that happens,
// just start checking the repeating preview requests as they complete.
final CameraAFCallback callback = (CameraAFCallback) msg.obj;
- CameraCaptureSession.CaptureListener deferredCallbackSetter =
- new CameraCaptureSession.CaptureListener() {
+ CameraCaptureSession.CaptureCallback deferredCallbackSetter =
+ new CameraCaptureSession.CaptureCallback() {
private boolean mAlreadyDispatched = false;
@Override
@@ -396,13 +420,13 @@ class AndroidCamera2AgentImpl extends CameraAgent {
private void checkAfState(CaptureResult result) {
if (result.get(CaptureResult.CONTROL_AF_STATE) != null &&
!mAlreadyDispatched) {
- // Now our mCameraResultStateListener will invoke the callback
+ // Now our mCameraResultStateCallback will invoke the callback
// the first time it finds the focus motor to be locked.
mAlreadyDispatched = true;
mOneshotAfCallback = callback;
// This is an optimization: check the AF state of this frame
// instead of simply waiting for the next.
- mCameraResultStateListener.monitorControlStates(result);
+ mCameraResultStateCallback.monitorControlStates(result);
}
}
@@ -433,6 +457,9 @@ class AndroidCamera2AgentImpl extends CameraAgent {
}
case CameraActions.CANCEL_AUTO_FOCUS: {
+ // Ignore all AFs that were already queued until we see
+ // a CANCEL_AUTO_FOCUS_FINISH
+ mCancelAfPending++;
// Why would you want to unlock the lens if it isn't already locked?
if (mCameraState.getState() <
AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
@@ -458,6 +485,13 @@ class AndroidCamera2AgentImpl extends CameraAgent {
break;
}
+ case CameraActions.CANCEL_AUTO_FOCUS_FINISH: {
+ // Stop ignoring AUTO_FOCUS messages unless there are additional
+ // CANCEL_AUTO_FOCUSes that were added
+ mCancelAfPending--;
+ break;
+ }
+
case CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK: {
mPassiveAfCallback = (CameraAFMoveCallback) msg.obj;
break;
@@ -489,12 +523,18 @@ class AndroidCamera2AgentImpl extends CameraAgent {
case CameraActions.SET_DISPLAY_ORIENTATION: {
// Only set the JPEG capture orientation if requested to do so; otherwise,
- // capture in the sensor's physical orientation
+ // capture in the sensor's physical orientation. (e.g., JPEG rotation is
+ // necessary in auto-rotate mode.
mPersistentSettings.set(CaptureRequest.JPEG_ORIENTATION, msg.arg2 > 0 ?
mCameraProxy.getCharacteristics().getJpegOrientation(msg.arg1) : 0);
break;
}
+ case CameraActions.SET_JPEG_ORIENTATION: {
+ mPersistentSettings.set(CaptureRequest.JPEG_ORIENTATION, msg.arg1);
+ break;
+ }
+
case CameraActions.CAPTURE_PHOTO: {
if (mCameraState.getState() <
AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
@@ -538,8 +578,8 @@ class AndroidCamera2AgentImpl extends CameraAgent {
// trigger capture has made it into the pipeline, we'll start checking
// for the completion of that convergence, capturing when that happens.
Log.i(TAG, "Forcing pre-capture autoexposure convergence");
- CameraCaptureSession.CaptureListener deferredCallbackSetter =
- new CameraCaptureSession.CaptureListener() {
+ CameraCaptureSession.CaptureCallback deferredCallbackSetter =
+ new CameraCaptureSession.CaptureCallback() {
private boolean mAlreadyDispatched = false;
@Override
@@ -559,13 +599,13 @@ class AndroidCamera2AgentImpl extends CameraAgent {
private void checkAeState(CaptureResult result) {
if (result.get(CaptureResult.CONTROL_AE_STATE) != null &&
!mAlreadyDispatched) {
- // Now our mCameraResultStateListener will invoke the
+ // Now our mCameraResultStateCallback will invoke the
// callback once the autoexposure routine has converged.
mAlreadyDispatched = true;
mOneshotCaptureCallback = listener;
// This is an optimization: check the AE state of this frame
// instead of simply waiting for the next.
- mCameraResultStateListener.monitorControlStates(result);
+ mCameraResultStateCallback.monitorControlStates(result);
}
}
@@ -601,12 +641,12 @@ class AndroidCamera2AgentImpl extends CameraAgent {
}
}
} catch (final Exception ex) {
- if (msg.what != CameraActions.RELEASE && mCamera != null) {
+ if (cameraAction != CameraActions.RELEASE && mCamera != null) {
// TODO: Handle this better
mCamera.close();
mCamera = null;
} else if (mCamera == null) {
- if (msg.what == CameraActions.OPEN_CAMERA) {
+ if (cameraAction == CameraActions.OPEN_CAMERA) {
if (mOpenCallback != null) {
mOpenCallback.onDeviceOpenFailure(mCameraIndex,
generateHistoryString(mCameraIndex));
@@ -618,12 +658,12 @@ class AndroidCamera2AgentImpl extends CameraAgent {
}
if (ex instanceof RuntimeException) {
- post(new Runnable() {
- @Override
- public void run() {
- sCameraExceptionCallback.onCameraException((RuntimeException) ex);
- }});
+ String commandHistory = generateHistoryString(Integer.parseInt(mCameraId));
+ mExceptionHandler.onCameraException((RuntimeException) ex, commandHistory,
+ cameraAction, mCameraState.getState());
}
+ } finally {
+ WaitDoneBundle.unblockSyncWaiters(msg);
}
}
@@ -659,7 +699,7 @@ class AndroidCamera2AgentImpl extends CameraAgent {
mSession.setRepeatingRequest(
mPersistentSettings.createRequest(mCamera,
CameraDevice.TEMPLATE_PREVIEW, mPreviewSurface),
- /*listener*/mCameraResultStateListener, /*handler*/this);
+ /*listener*/mCameraResultStateCallback, /*handler*/this);
} catch (CameraAccessException ex) {
Log.e(TAG, "Failed to apply updated request settings", ex);
}
@@ -706,7 +746,7 @@ class AndroidCamera2AgentImpl extends CameraAgent {
try {
mCamera.createCaptureSession(
Arrays.asList(mPreviewSurface, mCaptureReader.getSurface()),
- mCameraPreviewStateListener, this);
+ mCameraPreviewStateCallback, this);
} catch (CameraAccessException ex) {
Log.e(TAG, "Failed to create camera capture session", ex);
}
@@ -727,14 +767,14 @@ class AndroidCamera2AgentImpl extends CameraAgent {
mCameraState.setState(newState);
if (newState < AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
mCurrentAeState = CaptureResult.CONTROL_AE_STATE_INACTIVE;
- mCameraResultStateListener.resetState();
+ mCameraResultStateCallback.resetState();
}
}
}
- // This listener monitors our connection to and disconnection from camera devices.
- private CameraDevice.StateListener mCameraDeviceStateListener =
- new CameraDevice.StateListener() {
+ // This callback monitors our connection to and disconnection from camera devices.
+ private CameraDevice.StateCallback mCameraDeviceStateCallback =
+ new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
mCamera = camera;
@@ -742,8 +782,10 @@ class AndroidCamera2AgentImpl extends CameraAgent {
try {
CameraCharacteristics props =
mCameraManager.getCameraCharacteristics(mCameraId);
- mCameraProxy = new AndroidCamera2ProxyImpl(mCameraIndex, mCamera,
- getCameraDeviceInfo().getCharacteristics(mCameraIndex), props);
+ CameraDeviceInfo.Characteristics characteristics =
+ getCameraDeviceInfo().getCharacteristics(mCameraIndex);
+ mCameraProxy = new AndroidCamera2ProxyImpl(AndroidCamera2AgentImpl.this,
+ mCameraIndex, mCamera, characteristics, props);
mPersistentSettings = new Camera2RequestSettingsSet();
mActiveArray =
props.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
@@ -774,9 +816,9 @@ class AndroidCamera2AgentImpl extends CameraAgent {
}
}};
- // This listener monitors our camera session (i.e. our transition into and out of preview).
- private CameraCaptureSession.StateListener mCameraPreviewStateListener =
- new CameraCaptureSession.StateListener() {
+ // This callback monitors our camera session (i.e. our transition into and out of preview).
+ private CameraCaptureSession.StateCallback mCameraPreviewStateCallback =
+ new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
mSession = session;
@@ -798,16 +840,16 @@ class AndroidCamera2AgentImpl extends CameraAgent {
}
}};
- private abstract class CameraResultStateListener
- extends CameraCaptureSession.CaptureListener {
+ private abstract class CameraResultStateCallback
+ extends CameraCaptureSession.CaptureCallback {
public abstract void monitorControlStates(CaptureResult result);
public abstract void resetState();
}
- // This listener monitors requested captures and notifies any relevant callbacks.
- private CameraResultStateListener mCameraResultStateListener =
- new CameraResultStateListener() {
+ // This callback monitors requested captures and notifies any relevant callbacks.
+ private CameraResultStateCallback mCameraResultStateCallback =
+ new CameraResultStateCallback() {
private int mLastAfState = -1;
private long mLastAfFrameNumber = -1;
private long mLastAeFrameNumber = -1;
@@ -854,6 +896,9 @@ class AndroidCamera2AgentImpl extends CameraAgent {
case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: {
+ // This check must be made regardless of whether the focus state has
+ // changed recently to avoid infinite waiting during autoFocus()
+ // when the algorithm has already either converged or failed to.
if (mOneshotAfCallback != null) {
// A call to autoFocus() was just made to request a focus lock.
// Notify the caller that the lens is now indefinitely fixed,
@@ -876,8 +921,7 @@ class AndroidCamera2AgentImpl extends CameraAgent {
// might get the final callbacks for an earlier frame after receiving one or
// more that correspond to the next one. To prevent our data from oscillating,
// we never consider AE states that are older than the last one we've seen.
- if (aeState != mCurrentAeState &&
- result.getFrameNumber() > mLastAeFrameNumber) {
+ if (result.getFrameNumber() > mLastAeFrameNumber) {
mCurrentAeState = aeStateMaybe;
mLastAeFrameNumber = result.getFrameNumber();
@@ -885,6 +929,9 @@ class AndroidCamera2AgentImpl extends CameraAgent {
case CaptureResult.CONTROL_AE_STATE_CONVERGED:
case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED:
case CaptureResult.CONTROL_AE_STATE_LOCKED: {
+ // This check must be made regardless of whether the exposure state
+ // has changed recently to avoid infinite waiting during
+ // takePicture() when the algorithm has already converged.
if (mOneshotCaptureCallback != null) {
// A call to takePicture() was just made, and autoexposure
// converged so it's time to initiate the capture!
@@ -896,7 +943,7 @@ class AndroidCamera2AgentImpl extends CameraAgent {
mPersistentSettings.createRequest(mCamera,
CameraDevice.TEMPLATE_STILL_CAPTURE,
mCaptureReader.getSurface()),
- /*listener*/mOneshotCaptureCallback,
+ /*callback*/mOneshotCaptureCallback,
/*handler*/Camera2Handler.this);
} catch (CameraAccessException ex) {
Log.e(TAG, "Unable to initiate capture", ex);
@@ -926,18 +973,27 @@ class AndroidCamera2AgentImpl extends CameraAgent {
}
private class AndroidCamera2ProxyImpl extends CameraAgent.CameraProxy {
+ private final AndroidCamera2AgentImpl mCameraAgent;
private final int mCameraIndex;
private final CameraDevice mCamera;
private final CameraDeviceInfo.Characteristics mCharacteristics;
private final AndroidCamera2Capabilities mCapabilities;
+ private CameraSettings mLastSettings;
+ private boolean mShutterSoundEnabled;
- public AndroidCamera2ProxyImpl(int cameraIndex, CameraDevice camera,
+ public AndroidCamera2ProxyImpl(
+ AndroidCamera2AgentImpl agent,
+ int cameraIndex,
+ CameraDevice camera,
CameraDeviceInfo.Characteristics characteristics,
CameraCharacteristics properties) {
+ mCameraAgent = agent;
mCameraIndex = cameraIndex;
mCamera = camera;
mCharacteristics = characteristics;
mCapabilities = new AndroidCamera2Capabilities(properties);
+ mLastSettings = null;
+ mShutterSoundEnabled = true;
}
// TODO: Implement
@@ -959,10 +1015,34 @@ class AndroidCamera2AgentImpl extends CameraAgent {
return mCapabilities;
}
+ public CameraAgent getAgent() {
+ return mCameraAgent;
+ }
+
private AndroidCamera2Capabilities getSpecializedCapabilities() {
return mCapabilities;
}
+ // FIXME: Unlock the sizes in stopPreview(), as per the corresponding
+ // explanation on the STOP_PREVIEW case in the handler.
+ @Override
+ public void setPreviewTexture(SurfaceTexture surfaceTexture) {
+ // Once the Surface has been selected, we configure the session and
+ // are no longer able to change the sizes.
+ getSettings().setSizesLocked(true);
+ super.setPreviewTexture(surfaceTexture);
+ }
+
+ // FIXME: Unlock the sizes in stopPreview(), as per the corresponding
+ // explanation on the STOP_PREVIEW case in the handler.
+ @Override
+ public void setPreviewTextureSync(SurfaceTexture surfaceTexture) {
+ // Once the Surface has been selected, we configure the session and
+ // are no longer able to change the sizes.
+ getSettings().setSizesLocked(true);
+ super.setPreviewTexture(surfaceTexture);
+ }
+
// TODO: Implement
@Override
public void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb) {}
@@ -981,53 +1061,67 @@ class AndroidCamera2AgentImpl extends CameraAgent {
@Override
public void autoFocus(final Handler handler, final CameraAFCallback cb) {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- CameraAFCallback cbForward = null;
- if (cb != null) {
- cbForward = new CameraAFCallback() {
- @Override
- public void onAutoFocus(final boolean focused,
- final CameraProxy camera) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- cb.onAutoFocus(focused, camera);
- }});
- }};
- }
+ try {
+ mDispatchThread.runJob(new Runnable() {
+ @Override
+ public void run() {
+ CameraAFCallback cbForward = null;
+ if (cb != null) {
+ cbForward = new CameraAFCallback() {
+ @Override
+ public void onAutoFocus(final boolean focused,
+ final CameraProxy camera) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ cb.onAutoFocus(focused, camera);
+ }
+ });
+ }
+ };
+ }
- mCameraState.waitForStates(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE |
- AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
- mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, cbForward)
- .sendToTarget();
- }});
+ mCameraState.waitForStates(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE |
+ AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
+ mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, cbForward)
+ .sendToTarget();
+ }
+ });
+ } catch (RuntimeException ex) {
+ mCameraAgent.getCameraExceptionHandler().onDispatchThreadException(ex);
+ }
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void setAutoFocusMoveCallback(final Handler handler, final CameraAFMoveCallback cb) {
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- CameraAFMoveCallback cbForward = null;
- if (cb != null) {
- cbForward = new CameraAFMoveCallback() {
- @Override
- public void onAutoFocusMoving(final boolean moving,
- final CameraProxy camera) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- cb.onAutoFocusMoving(moving, camera);
- }});
- }};
- }
+ try {
+ mDispatchThread.runJob(new Runnable() {
+ @Override
+ public void run() {
+ CameraAFMoveCallback cbForward = null;
+ if (cb != null) {
+ cbForward = new CameraAFMoveCallback() {
+ @Override
+ public void onAutoFocusMoving(final boolean moving,
+ final CameraProxy camera) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ cb.onAutoFocusMoving(moving, camera);
+ }
+ });
+ }
+ };
+ }
- mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK,
- cbForward).sendToTarget();
- }});
+ mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK,
+ cbForward).sendToTarget();
+ }
+ });
+ } catch (RuntimeException ex) {
+ mCameraAgent.getCameraExceptionHandler().onDispatchThreadException(ex);
+ }
}
@Override
@@ -1041,12 +1135,14 @@ class AndroidCamera2AgentImpl extends CameraAgent {
new CaptureAvailableListener() {
@Override
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
- long timestamp) {
+ long timestamp, long frameNumber) {
if (shutter != null) {
handler.post(new Runnable() {
@Override
public void run() {
- mNoisemaker.play(MediaActionSound.SHUTTER_CLICK);
+ if (mShutterSoundEnabled) {
+ mNoisemaker.play(MediaActionSound.SHUTTER_CLICK);
+ }
shutter.onShutter(AndroidCamera2ProxyImpl.this);
}});
}
@@ -1067,14 +1163,20 @@ class AndroidCamera2AgentImpl extends CameraAgent {
}
}
}};
- mDispatchThread.runJob(new Runnable() {
- @Override
- public void run() {
- mCameraState.waitForStates(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE |
- AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
- mCameraHandler.obtainMessage(CameraActions.CAPTURE_PHOTO, picListener)
- .sendToTarget();
- }});
+ try {
+ mDispatchThread.runJob(new Runnable() {
+ @Override
+ public void run() {
+ // Wait until PREVIEW_ACTIVE or better
+ mCameraState.waitForStates(
+ ~(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE - 1));
+ mCameraHandler.obtainMessage(CameraActions.CAPTURE_PHOTO, picListener)
+ .sendToTarget();
+ }
+ });
+ } catch (RuntimeException ex) {
+ mCameraAgent.getCameraExceptionHandler().onDispatchThreadException(ex);
+ }
}
// TODO: Implement
@@ -1096,10 +1198,6 @@ class AndroidCamera2AgentImpl extends CameraAgent {
// TODO: Implement
@Override
- public void setErrorCallback(Handler handler, CameraErrorCallback cb) {}
-
- // TODO: Implement
- @Override
public void setParameters(android.hardware.Camera.Parameters params) {}
// TODO: Implement
@@ -1108,7 +1206,10 @@ class AndroidCamera2AgentImpl extends CameraAgent {
@Override
public CameraSettings getSettings() {
- return mCameraHandler.buildSettings(mCapabilities);
+ if (mLastSettings == null) {
+ mLastSettings = mCameraHandler.buildSettings(mCapabilities);
+ }
+ return mLastSettings;
}
@Override
@@ -1122,9 +1223,17 @@ class AndroidCamera2AgentImpl extends CameraAgent {
return false;
}
- return applySettingsHelper(settings, AndroidCamera2StateHolder.CAMERA_UNCONFIGURED |
- AndroidCamera2StateHolder.CAMERA_CONFIGURED |
- AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
+ // Wait for any state that isn't OPENED
+ if (applySettingsHelper(settings, ~AndroidCamera2StateHolder.CAMERA_UNOPENED)) {
+ mLastSettings = settings;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void enableShutterSound(boolean enable) {
+ mShutterSoundEnabled = enable;
}
// TODO: Implement
@@ -1151,19 +1260,22 @@ class AndroidCamera2AgentImpl extends CameraAgent {
private static class AndroidCamera2StateHolder extends CameraStateHolder {
// Usage flow: openCamera() -> applySettings() -> setPreviewTexture() -> startPreview() ->
// autoFocus() -> takePicture()
+ // States are mutually exclusive, but must be separate bits so that they can be used with
+ // the StateHolder#waitForStates() and StateHolder#waitToAvoidStates() methods.
+ // Do not set the state to be a combination of these values!
/* Camera states */
/** No camera device is opened. */
- public static final int CAMERA_UNOPENED = 1;
+ public static final int CAMERA_UNOPENED = 1 << 0;
/** A camera is opened, but no settings have been provided. */
- public static final int CAMERA_UNCONFIGURED = 2;
+ public static final int CAMERA_UNCONFIGURED = 1 << 1;
/** The open camera has been configured by providing it with settings. */
- public static final int CAMERA_CONFIGURED = 3;
+ public static final int CAMERA_CONFIGURED = 1 << 2;
/** A capture session is ready to stream a preview, but still has no repeating request. */
- public static final int CAMERA_PREVIEW_READY = 4;
+ public static final int CAMERA_PREVIEW_READY = 1 << 3;
/** A preview is currently being streamed. */
- public static final int CAMERA_PREVIEW_ACTIVE = 5;
+ public static final int CAMERA_PREVIEW_ACTIVE = 1 << 4;
/** The lens is locked on a particular region. */
- public static final int CAMERA_FOCUS_LOCKED = 6;
+ public static final int CAMERA_FOCUS_LOCKED = 1 << 5;
public AndroidCamera2StateHolder() {
this(CAMERA_UNOPENED);
@@ -1284,9 +1396,7 @@ class AndroidCamera2AgentImpl extends CameraAgent {
@Override
public boolean canDisableShutterSound() {
- // The new API doesn't support this operation, so don't encourage people to try it.
- // TODO: What kind of assumptions have callers made about this result's meaning?
- return false;
+ return true;
}
private static float[] convertRectToPoly(RectF rf) {
@@ -1307,12 +1417,4 @@ class AndroidCamera2AgentImpl extends CameraAgent {
}
}
}
-
- private static final CameraExceptionCallback sCameraExceptionCallback =
- new CameraExceptionCallback() {
- @Override
- public synchronized void onCameraException(RuntimeException e) {
- throw e;
- }
- };
}