From 3b7da912d573f358fd217f6d9b569cca648efe02 Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Wed, 3 Sep 2014 17:09:29 -0700 Subject: ex: Avoid exception if HDR_SCENE_MODE name changes. Bug: 17353543 Change-Id: I31448687a69afc66e93f4360e8a3186ff8ad6235 --- .../com/android/ex/camera2/portability/LegacyVendorTags.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/camera2/portability/src/com/android/ex/camera2/portability/LegacyVendorTags.java b/camera2/portability/src/com/android/ex/camera2/portability/LegacyVendorTags.java index e55748d..7eb5c33 100644 --- a/camera2/portability/src/com/android/ex/camera2/portability/LegacyVendorTags.java +++ b/camera2/portability/src/com/android/ex/camera2/portability/LegacyVendorTags.java @@ -17,6 +17,7 @@ package com.android.ex.camera2.portability; import android.hardware.camera2.CameraCharacteristics; +import android.util.Log; import java.lang.ExceptionInInitializerError; import java.lang.reflect.Field; @@ -27,19 +28,24 @@ import java.lang.reflect.Method; */ public class LegacyVendorTags { + private static final String TAG = "LegacyVendorTags"; + /** * Hidden enum for scene modes supported only by the Camera1 API. */ public static final int CONTROL_SCENE_MODE_HDR; static { + int tempSceneMode = -1; try { - CONTROL_SCENE_MODE_HDR = + tempSceneMode = Class.forName("android.hardware.camera2.CameraCharacteristics"). getField("CONTROL_SCENE_MODE_HDR").getInt(null); } catch (Exception e) { - throw new ExceptionInInitializerError( - "Error while reflecting on LegacyVendorTags: " + e); + Log.e(TAG, "Error while reflecting on SCENE_MODE_HDR enum, HDR will not be available: " + + e); + } finally { + CONTROL_SCENE_MODE_HDR = tempSceneMode; } } -- cgit v1.2.3 From dc05ed7a8443af7c1a7b1bb39519d09d79284e42 Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Fri, 5 Sep 2014 11:40:40 -0700 Subject: portability: Fix incorrect comparison between int and Integer Bug: 17405119 Change-Id: Ic4828b5ddee2b11fa9886506e48c640a4c5ad3ef --- .../src/com/android/ex/camera2/portability/AndroidCamera2Settings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java index 7f6cffe..a286fb8 100644 --- a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java +++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2Settings.java @@ -192,7 +192,7 @@ public class AndroidCamera2Settings extends CameraSettings { } else if (setting == CONTROL_AF_REGIONS) { return mFocusAreas.size() == 0; } else if (setting == CONTROL_AE_TARGET_FPS_RANGE) { - Range defaultFpsRange = mTemplateSettings.get(CONTROL_AE_TARGET_FPS_RANGE); + Range defaultFpsRange = mTemplateSettings.get(CONTROL_AE_TARGET_FPS_RANGE); return (mPreviewFpsRangeMin == 0 && mPreviewFpsRangeMax == 0) || (defaultFpsRange != null && mPreviewFpsRangeMin == defaultFpsRange.getLower() && mPreviewFpsRangeMax == defaultFpsRange.getUpper()); -- cgit v1.2.3 From bb013aa3e197e881756be5ad13e6ad30bfb4aeff Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Thu, 4 Sep 2014 13:02:46 -0700 Subject: Camera2: Renames for API consistency - Listener -> Callback - add/remove callbacks -> register/unregister Bug: 17389922 Change-Id: I6e162ae18447b5a4fcabc17d17b1341f341fc47d --- camera2/Android.mk | 1 + .../portability/AndroidCamera2AgentImpl.java | 52 ++--- .../ex/camera2/blocking/BlockingCameraManager.java | 18 +- .../camera2/blocking/BlockingCaptureCallback.java | 164 +++++++++++++++ .../camera2/blocking/BlockingCaptureListener.java | 164 --------------- .../camera2/blocking/BlockingSessionCallback.java | 228 +++++++++++++++++++++ .../camera2/blocking/BlockingSessionListener.java | 228 --------------------- .../ex/camera2/blocking/BlockingStateCallback.java | 227 ++++++++++++++++++++ .../ex/camera2/blocking/BlockingStateListener.java | 227 -------------------- .../ex/camera2/pos/AutoFocusStateMachine.java | 2 +- .../utils/Camera2CaptureCallbackForwarder.java | 99 +++++++++ .../utils/Camera2CaptureCallbackSplitter.java | 95 +++++++++ .../utils/Camera2CaptureListenerForwarder.java | 99 --------- .../utils/Camera2CaptureListenerSplitter.java | 95 --------- .../ex/camera2/utils/Camera2DeviceTester.java | 2 +- .../android/ex/camera2/utils/Camera2UtilsTest.java | 34 +-- 16 files changed, 868 insertions(+), 867 deletions(-) create mode 100644 camera2/public/src/com/android/ex/camera2/blocking/BlockingCaptureCallback.java delete mode 100644 camera2/public/src/com/android/ex/camera2/blocking/BlockingCaptureListener.java create mode 100644 camera2/public/src/com/android/ex/camera2/blocking/BlockingSessionCallback.java delete mode 100644 camera2/public/src/com/android/ex/camera2/blocking/BlockingSessionListener.java create mode 100644 camera2/public/src/com/android/ex/camera2/blocking/BlockingStateCallback.java delete mode 100644 camera2/public/src/com/android/ex/camera2/blocking/BlockingStateListener.java create mode 100644 camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureCallbackForwarder.java create mode 100644 camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureCallbackSplitter.java delete mode 100644 camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerForwarder.java delete mode 100644 camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerSplitter.java diff --git a/camera2/Android.mk b/camera2/Android.mk index 9ac4a8a..3719578 100644 --- a/camera2/Android.mk +++ b/camera2/Android.mk @@ -12,4 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Build all subprojects include $(call all-subdir-makefiles) 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 913a575..62cb700 100644 --- a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java +++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java @@ -160,7 +160,7 @@ class AndroidCamera2AgentImpl extends CameraAgent { } private static abstract class CaptureAvailableListener - extends CameraCaptureSession.CaptureListener + extends CameraCaptureSession.CaptureCallback implements ImageReader.OnImageAvailableListener {}; private class Camera2Handler extends HistoryHandler { @@ -231,7 +231,7 @@ class AndroidCamera2AgentImpl extends CameraAgent { mOpenCallback.onCameraDisabled(msg.arg1); break; } - mCameraManager.openCamera(mCameraId, mCameraDeviceStateListener, this); + mCameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, this); break; } @@ -297,7 +297,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); @@ -379,8 +379,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 @@ -400,13 +400,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); } } @@ -542,8 +542,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 @@ -563,13 +563,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); } } @@ -663,7 +663,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); } @@ -710,7 +710,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); } @@ -731,14 +731,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; @@ -778,9 +778,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; @@ -802,16 +802,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; @@ -905,7 +905,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); diff --git a/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java index 02dbbba..407a08a 100644 --- a/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java +++ b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java @@ -66,7 +66,7 @@ public class BlockingCameraManager { /** * Returns the error code {@link ERROR_DISCONNECTED} if disconnected, or one of - * {@code CameraDevice.StateListener#ERROR_*} if there was another error. + * {@code CameraDevice.StateCallback#ERROR_*} if there was another error. * * @return int Disconnect/error code */ @@ -81,7 +81,7 @@ public class BlockingCameraManager { * @param errorCode * @param message * - * @see {@link CameraDevice.StateListener#ERROR_CAMERA_DEVICE} + * @see {@link CameraDevice.StateCallback#ERROR_CAMERA_DEVICE} */ public BlockingOpenException(int errorCode, String message) { super(message); @@ -117,8 +117,8 @@ public class BlockingCameraManager { * does.

* *

Throws {@link BlockingOpenException} when the open fails asynchronously (due to - * {@link CameraDevice.StateListener#onDisconnected(CameraDevice)} or - * ({@link CameraDevice.StateListener#onError(CameraDevice)}.

+ * {@link CameraDevice.StateCallback#onDisconnected(CameraDevice)} or + * ({@link CameraDevice.StateCallback#onError(CameraDevice)}.

* *

Throws {@link TimeoutRuntimeException} if opening times out. This is usually * highly unrecoverable, and all future calls to opening that camera will fail since the @@ -142,7 +142,7 @@ public class BlockingCameraManager { * @throws TimeoutRuntimeException * If opening times out. Typically unrecoverable. */ - public CameraDevice openCamera(String cameraId, CameraDevice.StateListener listener, + public CameraDevice openCamera(String cameraId, CameraDevice.StateCallback listener, Handler handler) throws CameraAccessException, BlockingOpenException { if (handler == null) { @@ -163,17 +163,17 @@ public class BlockingCameraManager { /** * Block until CameraManager#openCamera finishes with onOpened/onError/onDisconnected * - *

Pass-through all StateListener changes to the proxy.

+ *

Pass-through all StateCallback changes to the proxy.

* *

Time out after {@link #OPEN_TIME_OUT} and unblock. Clean up camera if it arrives * later.

*/ - private class OpenListener extends CameraDevice.StateListener { + private class OpenListener extends CameraDevice.StateCallback { private static final int ERROR_UNINITIALIZED = -1; private final String mCameraId; - private final CameraDevice.StateListener mProxy; + private final CameraDevice.StateCallback mProxy; private final Object mLock = new Object(); private final ConditionVariable mDeviceReady = new ConditionVariable(); @@ -187,7 +187,7 @@ public class BlockingCameraManager { private boolean mTimedOut = false; OpenListener(CameraManager manager, String cameraId, - CameraDevice.StateListener listener, Handler handler) + CameraDevice.StateCallback listener, Handler handler) throws CameraAccessException { mCameraId = cameraId; mProxy = listener; diff --git a/camera2/public/src/com/android/ex/camera2/blocking/BlockingCaptureCallback.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCaptureCallback.java new file mode 100644 index 0000000..4fb2c43 --- /dev/null +++ b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCaptureCallback.java @@ -0,0 +1,164 @@ +/* + * Copyright 2014 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.ex.camera2.blocking; + +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CaptureFailure; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; +import android.util.Log; + +import com.android.ex.camera2.utils.StateChangeListener; +import com.android.ex.camera2.utils.StateWaiter; + +/** + * A camera capture listener that implements blocking operations on state changes for a + * particular capture request. + * + *

Provides a waiter that can be used to block until the next unobserved state of the + * requested type arrives.

+ * + *

Pass-through all StateListener changes to the proxy.

+ * + * @see #getStateWaiter + */ +public class BlockingCaptureCallback extends CameraCaptureSession.CaptureCallback { + + /** + * {@link #onCaptureStarted} has been called. + */ + public static final int CAPTURE_STARTED = 0; + + /** + * {@link #onCaptureProgressed} has been + * called. + */ + public static final int CAPTURE_PROGRESSED = 1; + + /** + * {@link #onCaptureCompleted} has + * been called. + */ + public static final int CAPTURE_COMPLETED = 2; + + /** + * {@link #onCaptureFailed} has been + * called. + */ + public static final int CAPTURE_FAILED = 3; + + /** + * {@link #onCaptureSequenceCompleted} has been called. + */ + public static final int CAPTURE_SEQUENCE_COMPLETED = 4; + + /** + * {@link #onCaptureSequenceAborted} has been called. + */ + public static final int CAPTURE_SEQUENCE_ABORTED = 5; + + private static final String[] sStateNames = { + "CAPTURE_STARTED", + "CAPTURE_PROGRESSED", + "CAPTURE_COMPLETED", + "CAPTURE_FAILED", + "CAPTURE_SEQUENCE_COMPLETED", + "CAPTURE_SEQUENCE_ABORTED" + }; + + private static final String TAG = "BlockingCaptureCallback"; + private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + + private final CameraCaptureSession.CaptureCallback mProxy; + + private final StateWaiter mStateWaiter = new StateWaiter(sStateNames); + private final StateChangeListener mStateChangeListener = mStateWaiter.getListener(); + + /** + * Create a blocking capture listener without forwarding the capture listener invocations + * to another capture listener. + */ + public BlockingCaptureCallback() { + mProxy = null; + } + + /** + * Create a blocking capture listener; forward original listener invocations + * into {@code listener}. + * + * @param listener a non-{@code null} listener to forward invocations into + * + * @throws NullPointerException if {@code listener} was {@code null} + */ + public BlockingCaptureCallback(CameraCaptureSession.CaptureCallback listener) { + if (listener == null) { + throw new NullPointerException("listener must not be null"); + } + mProxy = listener; + } + + /** + * Acquire the state waiter; can be used to block until a set of state transitions have + * been reached. + * + *

Only one thread should wait at a time.

+ */ + public StateWaiter getStateWaiter() { + return mStateWaiter; + } + + @Override + public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, + long timestamp) { + if (mProxy != null) mProxy.onCaptureStarted(session, request, timestamp); + mStateChangeListener.onStateChanged(CAPTURE_STARTED); + } + + @Override + public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, + CaptureResult partialResult) { + if (mProxy != null) mProxy.onCaptureProgressed(session, request, partialResult); + mStateChangeListener.onStateChanged(CAPTURE_PROGRESSED); + } + + @Override + public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, + TotalCaptureResult result) { + if (mProxy != null) mProxy.onCaptureCompleted(session, request, result); + mStateChangeListener.onStateChanged(CAPTURE_COMPLETED); + } + + @Override + public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, + CaptureFailure failure) { + if (mProxy != null) mProxy.onCaptureFailed(session, request, failure); + mStateChangeListener.onStateChanged(CAPTURE_FAILED); + } + + @Override + public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, + long frameNumber) { + if (mProxy != null) mProxy.onCaptureSequenceCompleted(session, sequenceId, frameNumber); + mStateChangeListener.onStateChanged(CAPTURE_SEQUENCE_COMPLETED); + } + + @Override + public void onCaptureSequenceAborted(CameraCaptureSession session, int sequenceId) { + if (mProxy != null) mProxy.onCaptureSequenceAborted(session, sequenceId); + mStateChangeListener.onStateChanged(CAPTURE_SEQUENCE_ABORTED); + } +} diff --git a/camera2/public/src/com/android/ex/camera2/blocking/BlockingCaptureListener.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCaptureListener.java deleted file mode 100644 index eae85d1..0000000 --- a/camera2/public/src/com/android/ex/camera2/blocking/BlockingCaptureListener.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2014 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.ex.camera2.blocking; - -import android.hardware.camera2.CameraCaptureSession; -import android.hardware.camera2.CaptureFailure; -import android.hardware.camera2.CaptureRequest; -import android.hardware.camera2.CaptureResult; -import android.hardware.camera2.TotalCaptureResult; -import android.util.Log; - -import com.android.ex.camera2.utils.StateChangeListener; -import com.android.ex.camera2.utils.StateWaiter; - -/** - * A camera capture listener that implements blocking operations on state changes for a - * particular capture request. - * - *

Provides a waiter that can be used to block until the next unobserved state of the - * requested type arrives.

- * - *

Pass-through all StateListener changes to the proxy.

- * - * @see #getStateWaiter - */ -public class BlockingCaptureListener extends CameraCaptureSession.CaptureListener { - - /** - * {@link #onCaptureStarted} has been called. - */ - public static final int CAPTURE_STARTED = 0; - - /** - * {@link #onCaptureProgressed} has been - * called. - */ - public static final int CAPTURE_PROGRESSED = 1; - - /** - * {@link #onCaptureCompleted} has - * been called. - */ - public static final int CAPTURE_COMPLETED = 2; - - /** - * {@link #onCaptureFailed} has been - * called. - */ - public static final int CAPTURE_FAILED = 3; - - /** - * {@link #onCaptureSequenceCompleted} has been called. - */ - public static final int CAPTURE_SEQUENCE_COMPLETED = 4; - - /** - * {@link #onCaptureSequenceAborted} has been called. - */ - public static final int CAPTURE_SEQUENCE_ABORTED = 5; - - private static final String[] sStateNames = { - "CAPTURE_STARTED", - "CAPTURE_PROGRESSED", - "CAPTURE_COMPLETED", - "CAPTURE_FAILED", - "CAPTURE_SEQUENCE_COMPLETED", - "CAPTURE_SEQUENCE_ABORTED" - }; - - private static final String TAG = "BlockingCaptureListener"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); - - private final CameraCaptureSession.CaptureListener mProxy; - - private final StateWaiter mStateWaiter = new StateWaiter(sStateNames); - private final StateChangeListener mStateChangeListener = mStateWaiter.getListener(); - - /** - * Create a blocking capture listener without forwarding the capture listener invocations - * to another capture listener. - */ - public BlockingCaptureListener() { - mProxy = null; - } - - /** - * Create a blocking capture listener; forward original listener invocations - * into {@code listener}. - * - * @param listener a non-{@code null} listener to forward invocations into - * - * @throws NullPointerException if {@code listener} was {@code null} - */ - public BlockingCaptureListener(CameraCaptureSession.CaptureListener listener) { - if (listener == null) { - throw new NullPointerException("listener must not be null"); - } - mProxy = listener; - } - - /** - * Acquire the state waiter; can be used to block until a set of state transitions have - * been reached. - * - *

Only one thread should wait at a time.

- */ - public StateWaiter getStateWaiter() { - return mStateWaiter; - } - - @Override - public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, - long timestamp) { - if (mProxy != null) mProxy.onCaptureStarted(session, request, timestamp); - mStateChangeListener.onStateChanged(CAPTURE_STARTED); - } - - @Override - public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, - CaptureResult partialResult) { - if (mProxy != null) mProxy.onCaptureProgressed(session, request, partialResult); - mStateChangeListener.onStateChanged(CAPTURE_PROGRESSED); - } - - @Override - public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, - TotalCaptureResult result) { - if (mProxy != null) mProxy.onCaptureCompleted(session, request, result); - mStateChangeListener.onStateChanged(CAPTURE_COMPLETED); - } - - @Override - public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, - CaptureFailure failure) { - if (mProxy != null) mProxy.onCaptureFailed(session, request, failure); - mStateChangeListener.onStateChanged(CAPTURE_FAILED); - } - - @Override - public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, - long frameNumber) { - if (mProxy != null) mProxy.onCaptureSequenceCompleted(session, sequenceId, frameNumber); - mStateChangeListener.onStateChanged(CAPTURE_SEQUENCE_COMPLETED); - } - - @Override - public void onCaptureSequenceAborted(CameraCaptureSession session, int sequenceId) { - if (mProxy != null) mProxy.onCaptureSequenceAborted(session, sequenceId); - mStateChangeListener.onStateChanged(CAPTURE_SEQUENCE_ABORTED); - } -} diff --git a/camera2/public/src/com/android/ex/camera2/blocking/BlockingSessionCallback.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingSessionCallback.java new file mode 100644 index 0000000..e041d27 --- /dev/null +++ b/camera2/public/src/com/android/ex/camera2/blocking/BlockingSessionCallback.java @@ -0,0 +1,228 @@ +/* + * Copyright 2014 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.ex.camera2.blocking; + +import android.hardware.camera2.CameraCaptureSession; +import android.os.ConditionVariable; +import android.util.Log; + +import com.android.ex.camera2.exceptions.TimeoutRuntimeException; +import com.android.ex.camera2.utils.StateChangeListener; +import com.android.ex.camera2.utils.StateWaiter; + +import java.util.ArrayList; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + + +/** + * A camera session listener that implements blocking operations on session state changes. + * + *

Provides a waiter that can be used to block until the next unobserved state of the + * requested type arrives.

+ * + *

Pass-through all StateCallback changes to the proxy.

+ * + * @see #getStateWaiter + */ +public class BlockingSessionCallback extends CameraCaptureSession.StateCallback { + /** + * Session is configured, ready for captures + */ + public static final int SESSION_CONFIGURED = 0; + + /** + * Session has failed to configure, can't do any captures + */ + public static final int SESSION_CONFIGURE_FAILED = 1; + + /** + * Session is ready + */ + public static final int SESSION_READY = 2; + + /** + * Session is active (transitory) + */ + public static final int SESSION_ACTIVE = 3; + + /** + * Session is closed + */ + public static final int SESSION_CLOSED = 4; + + private final int NUM_STATES = 5; + + /* + * Private fields + */ + private static final String TAG = "BlockingSessionCallback"; + private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + + private final CameraCaptureSession.StateCallback mProxy; + private final SessionFuture mSessionFuture = new SessionFuture(); + + private final StateWaiter mStateWaiter = new StateWaiter(sStateNames); + private final StateChangeListener mStateChangeListener = mStateWaiter.getListener(); + + private static final String[] sStateNames = { + "SESSION_CONFIGURED", + "SESSION_CONFIGURE_FAILED", + "SESSION_READY", + "SESSION_ACTIVE", + "SESSION_CLOSED" + }; + + /** + * Create a blocking session listener without forwarding the session listener invocations + * to another session listener. + */ + public BlockingSessionCallback() { + mProxy = null; + } + + /** + * Create a blocking session listener; forward original listener invocations + * into {@code listener}. + * + * @param listener a non-{@code null} listener to forward invocations into + * + * @throws NullPointerException if {@code listener} was {@code null} + */ + public BlockingSessionCallback(CameraCaptureSession.StateCallback listener) { + if (listener == null) { + throw new NullPointerException("listener must not be null"); + } + mProxy = listener; + } + + /** + * Acquire the state waiter; can be used to block until a set of state transitions have + * been reached. + * + *

Only one thread should wait at a time.

+ */ + public StateWaiter getStateWaiter() { + return mStateWaiter; + } + + /** + * Return session if already have it; otherwise wait until any of the session listener + * invocations fire and the session is available. + * + *

Does not consume any of the states from the state waiter.

+ * + * @param timeoutMs how many milliseconds to wait for + * @return a non-{@code null} {@link CameraCaptureSession} instance + * + * @throws TimeoutRuntimeException if waiting for more than {@long timeoutMs} + */ + public CameraCaptureSession waitAndGetSession(long timeoutMs) { + try { + return mSessionFuture.get(timeoutMs, TimeUnit.MILLISECONDS); + } catch (TimeoutException e) { + throw new TimeoutRuntimeException( + String.format("Failed to get session after %s milliseconds", timeoutMs), e); + } + } + + /* + * CameraCaptureSession.StateCallback implementation + */ + + @Override + public void onActive(CameraCaptureSession session) { + mSessionFuture.setSession(session); + if (mProxy != null) mProxy.onActive(session); + mStateChangeListener.onStateChanged(SESSION_ACTIVE); + } + + @Override + public void onClosed(CameraCaptureSession session) { + mSessionFuture.setSession(session); + if (mProxy != null) mProxy.onClosed(session); + mStateChangeListener.onStateChanged(SESSION_CLOSED); + } + + @Override + public void onConfigured(CameraCaptureSession session) { + mSessionFuture.setSession(session); + if (mProxy != null) mProxy.onConfigured(session); + mStateChangeListener.onStateChanged(SESSION_CONFIGURED); + } + + @Override + public void onConfigureFailed(CameraCaptureSession session) { + mSessionFuture.setSession(session); + if (mProxy != null) mProxy.onConfigureFailed(session); + mStateChangeListener.onStateChanged(SESSION_CONFIGURE_FAILED); + } + + @Override + public void onReady(CameraCaptureSession session) { + mSessionFuture.setSession(session); + if (mProxy != null) mProxy.onReady(session); + mStateChangeListener.onStateChanged(SESSION_READY); + } + + private static class SessionFuture implements Future { + private volatile CameraCaptureSession mSession; + ConditionVariable mCondVar = new ConditionVariable(/*opened*/false); + + public void setSession(CameraCaptureSession session) { + mSession = session; + mCondVar.open(); + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return false; // don't allow canceling this task + } + + @Override + public boolean isCancelled() { + return false; // can never cancel this task + } + + @Override + public boolean isDone() { + return mSession != null; + } + + @Override + public CameraCaptureSession get() { + mCondVar.block(); + return mSession; + } + + @Override + public CameraCaptureSession get(long timeout, TimeUnit unit) throws TimeoutException { + long timeoutMs = unit.convert(timeout, TimeUnit.MILLISECONDS); + if (!mCondVar.block(timeoutMs)) { + throw new TimeoutException( + "Failed to receive session after " + timeout + " " + unit); + } + + if (mSession == null) { + throw new AssertionError(); + } + return mSession; + } + + } +} diff --git a/camera2/public/src/com/android/ex/camera2/blocking/BlockingSessionListener.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingSessionListener.java deleted file mode 100644 index 26bb652..0000000 --- a/camera2/public/src/com/android/ex/camera2/blocking/BlockingSessionListener.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2014 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.ex.camera2.blocking; - -import android.hardware.camera2.CameraCaptureSession; -import android.os.ConditionVariable; -import android.util.Log; - -import com.android.ex.camera2.exceptions.TimeoutRuntimeException; -import com.android.ex.camera2.utils.StateChangeListener; -import com.android.ex.camera2.utils.StateWaiter; - -import java.util.ArrayList; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - - -/** - * A camera session listener that implements blocking operations on session state changes. - * - *

Provides a waiter that can be used to block until the next unobserved state of the - * requested type arrives.

- * - *

Pass-through all StateListener changes to the proxy.

- * - * @see #getStateWaiter - */ -public class BlockingSessionListener extends CameraCaptureSession.StateListener { - /** - * Session is configured, ready for captures - */ - public static final int SESSION_CONFIGURED = 0; - - /** - * Session has failed to configure, can't do any captures - */ - public static final int SESSION_CONFIGURE_FAILED = 1; - - /** - * Session is ready - */ - public static final int SESSION_READY = 2; - - /** - * Session is active (transitory) - */ - public static final int SESSION_ACTIVE = 3; - - /** - * Session is closed - */ - public static final int SESSION_CLOSED = 4; - - private final int NUM_STATES = 5; - - /* - * Private fields - */ - private static final String TAG = "BlockingSessionListener"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); - - private final CameraCaptureSession.StateListener mProxy; - private final SessionFuture mSessionFuture = new SessionFuture(); - - private final StateWaiter mStateWaiter = new StateWaiter(sStateNames); - private final StateChangeListener mStateChangeListener = mStateWaiter.getListener(); - - private static final String[] sStateNames = { - "SESSION_CONFIGURED", - "SESSION_CONFIGURE_FAILED", - "SESSION_READY", - "SESSION_ACTIVE", - "SESSION_CLOSED" - }; - - /** - * Create a blocking session listener without forwarding the session listener invocations - * to another session listener. - */ - public BlockingSessionListener() { - mProxy = null; - } - - /** - * Create a blocking session listener; forward original listener invocations - * into {@code listener}. - * - * @param listener a non-{@code null} listener to forward invocations into - * - * @throws NullPointerException if {@code listener} was {@code null} - */ - public BlockingSessionListener(CameraCaptureSession.StateListener listener) { - if (listener == null) { - throw new NullPointerException("listener must not be null"); - } - mProxy = listener; - } - - /** - * Acquire the state waiter; can be used to block until a set of state transitions have - * been reached. - * - *

Only one thread should wait at a time.

- */ - public StateWaiter getStateWaiter() { - return mStateWaiter; - } - - /** - * Return session if already have it; otherwise wait until any of the session listener - * invocations fire and the session is available. - * - *

Does not consume any of the states from the state waiter.

- * - * @param timeoutMs how many milliseconds to wait for - * @return a non-{@code null} {@link CameraCaptureSession} instance - * - * @throws TimeoutRuntimeException if waiting for more than {@long timeoutMs} - */ - public CameraCaptureSession waitAndGetSession(long timeoutMs) { - try { - return mSessionFuture.get(timeoutMs, TimeUnit.MILLISECONDS); - } catch (TimeoutException e) { - throw new TimeoutRuntimeException( - String.format("Failed to get session after %s milliseconds", timeoutMs), e); - } - } - - /* - * CameraCaptureSession.StateListener implementation - */ - - @Override - public void onActive(CameraCaptureSession session) { - mSessionFuture.setSession(session); - if (mProxy != null) mProxy.onActive(session); - mStateChangeListener.onStateChanged(SESSION_ACTIVE); - } - - @Override - public void onClosed(CameraCaptureSession session) { - mSessionFuture.setSession(session); - if (mProxy != null) mProxy.onClosed(session); - mStateChangeListener.onStateChanged(SESSION_CLOSED); - } - - @Override - public void onConfigured(CameraCaptureSession session) { - mSessionFuture.setSession(session); - if (mProxy != null) mProxy.onConfigured(session); - mStateChangeListener.onStateChanged(SESSION_CONFIGURED); - } - - @Override - public void onConfigureFailed(CameraCaptureSession session) { - mSessionFuture.setSession(session); - if (mProxy != null) mProxy.onConfigureFailed(session); - mStateChangeListener.onStateChanged(SESSION_CONFIGURE_FAILED); - } - - @Override - public void onReady(CameraCaptureSession session) { - mSessionFuture.setSession(session); - if (mProxy != null) mProxy.onReady(session); - mStateChangeListener.onStateChanged(SESSION_READY); - } - - private static class SessionFuture implements Future { - private volatile CameraCaptureSession mSession; - ConditionVariable mCondVar = new ConditionVariable(/*opened*/false); - - public void setSession(CameraCaptureSession session) { - mSession = session; - mCondVar.open(); - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return false; // don't allow canceling this task - } - - @Override - public boolean isCancelled() { - return false; // can never cancel this task - } - - @Override - public boolean isDone() { - return mSession != null; - } - - @Override - public CameraCaptureSession get() { - mCondVar.block(); - return mSession; - } - - @Override - public CameraCaptureSession get(long timeout, TimeUnit unit) throws TimeoutException { - long timeoutMs = unit.convert(timeout, TimeUnit.MILLISECONDS); - if (!mCondVar.block(timeoutMs)) { - throw new TimeoutException( - "Failed to receive session after " + timeout + " " + unit); - } - - if (mSession == null) { - throw new AssertionError(); - } - return mSession; - } - - } -} diff --git a/camera2/public/src/com/android/ex/camera2/blocking/BlockingStateCallback.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingStateCallback.java new file mode 100644 index 0000000..5f93fbc --- /dev/null +++ b/camera2/public/src/com/android/ex/camera2/blocking/BlockingStateCallback.java @@ -0,0 +1,227 @@ +/* + * Copyright 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.ex.camera2.blocking; + +import android.hardware.camera2.CameraDevice; +import android.os.Handler; +import android.os.SystemClock; +import android.util.Log; + +import com.android.ex.camera2.exceptions.TimeoutRuntimeException; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + + +/** + * A camera device listener that implements blocking operations on state changes. + * + *

Provides wait calls that block until the next unobserved state of the + * requested type arrives. Unobserved states are states that have occurred since + * the last wait, or that will be received from the camera device in the + * future.

+ * + *

Pass-through all StateCallback changes to the proxy.

+ * + */ +public class BlockingStateCallback extends CameraDevice.StateCallback { + private static final String TAG = "BlockingStateCallback"; + private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + + private final CameraDevice.StateCallback mProxy; + + // Guards mWaiting + private final Object mLock = new Object(); + private boolean mWaiting = false; + + private final LinkedBlockingQueue mRecentStates = + new LinkedBlockingQueue(); + + private void setCurrentState(int state) { + if (VERBOSE) Log.v(TAG, "Camera device state now " + stateToString(state)); + try { + mRecentStates.put(state); + } catch(InterruptedException e) { + throw new RuntimeException("Unable to set device state", e); + } + } + + private static final String[] mStateNames = { + "STATE_UNINITIALIZED", + "STATE_OPENED", + "STATE_CLOSED", + "STATE_DISCONNECTED", + "STATE_ERROR" + }; + + /** + * Device has not reported any state yet + */ + public static final int STATE_UNINITIALIZED = -1; + + /** + * Device is in the first-opened state (transitory) + */ + public static final int STATE_OPENED = 0; + + /** + * Device is closed + */ + public static final int STATE_CLOSED = 1; + + /** + * Device is disconnected + */ + public static final int STATE_DISCONNECTED = 2; + + /** + * Device has encountered a fatal error + */ + public static final int STATE_ERROR = 3; + + /** + * Total number of reachable states + */ + private static int NUM_STATES = 4; + + public BlockingStateCallback() { + mProxy = null; + } + + public BlockingStateCallback(CameraDevice.StateCallback listener) { + mProxy = listener; + } + + @Override + public void onOpened(CameraDevice camera) { + if (mProxy != null) mProxy.onOpened(camera); + setCurrentState(STATE_OPENED); + } + + @Override + public void onDisconnected(CameraDevice camera) { + if (mProxy != null) mProxy.onDisconnected(camera); + setCurrentState(STATE_DISCONNECTED); + } + + @Override + public void onError(CameraDevice camera, int error) { + if (mProxy != null) mProxy.onError(camera, error); + setCurrentState(STATE_ERROR); + } + + @Override + public void onClosed(CameraDevice camera) { + if (mProxy != null) mProxy.onClosed(camera); + setCurrentState(STATE_CLOSED); + } + + /** + * Wait until the desired state is observed, checking all state + * transitions since the last state that was waited on. + * + *

Note: Only one waiter allowed at a time!

+ * + * @param desired state to observe a transition to + * @param timeout how long to wait in milliseconds + * + * @throws TimeoutRuntimeException if the desired state is not observed before timeout. + */ + public void waitForState(int state, long timeout) { + Integer[] stateArray = { state }; + + waitForAnyOfStates(Arrays.asList(stateArray), timeout); + } + + /** + * Wait until the one of the desired states is observed, checking all + * state transitions since the last state that was waited on. + * + *

Note: Only one waiter allowed at a time!

+ * + * @param states Set of desired states to observe a transition to. + * @param timeout how long to wait in milliseconds + * + * @return the state reached + * @throws TimeoutRuntimeException if none of the states is observed before timeout. + * + */ + public int waitForAnyOfStates(Collection states, final long timeout) { + synchronized(mLock) { + if (mWaiting) throw new IllegalStateException("Only one waiter allowed at a time"); + mWaiting = true; + } + if (VERBOSE) { + StringBuilder s = new StringBuilder("Waiting for state(s) "); + appendStates(s, states); + Log.v(TAG, s.toString()); + } + + Integer nextState = null; + long timeoutLeft = timeout; + long startMs = SystemClock.elapsedRealtime(); + try { + while ((nextState = mRecentStates.poll(timeoutLeft, TimeUnit.MILLISECONDS)) + != null) { + if (VERBOSE) { + Log.v(TAG, " Saw transition to " + stateToString(nextState)); + } + if (states.contains(nextState)) break; + long endMs = SystemClock.elapsedRealtime(); + timeoutLeft -= (endMs - startMs); + startMs = endMs; + } + } catch (InterruptedException e) { + throw new UnsupportedOperationException("Does not support interrupts on waits", e); + } + + synchronized(mLock) { + mWaiting = false; + } + + if (!states.contains(nextState)) { + StringBuilder s = new StringBuilder("Timed out after "); + s.append(timeout); + s.append(" ms waiting for state(s) "); + appendStates(s, states); + + throw new TimeoutRuntimeException(s.toString()); + } + + return nextState; + } + + /** + * Convert state integer to a String + */ + public static String stateToString(int state) { + return mStateNames[state + 1]; + } + + /** + * Append all states to string + */ + public static void appendStates(StringBuilder s, Collection states) { + boolean start = true; + for (Integer state: states) { + if (!start) s.append(" "); + s.append(stateToString(state)); + start = false; + } + } +} diff --git a/camera2/public/src/com/android/ex/camera2/blocking/BlockingStateListener.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingStateListener.java deleted file mode 100644 index 02c2ba3..0000000 --- a/camera2/public/src/com/android/ex/camera2/blocking/BlockingStateListener.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 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.ex.camera2.blocking; - -import android.hardware.camera2.CameraDevice; -import android.os.Handler; -import android.os.SystemClock; -import android.util.Log; - -import com.android.ex.camera2.exceptions.TimeoutRuntimeException; - -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; - - -/** - * A camera device listener that implements blocking operations on state changes. - * - *

Provides wait calls that block until the next unobserved state of the - * requested type arrives. Unobserved states are states that have occurred since - * the last wait, or that will be received from the camera device in the - * future.

- * - *

Pass-through all StateListener changes to the proxy.

- * - */ -public class BlockingStateListener extends CameraDevice.StateListener { - private static final String TAG = "BlockingStateListener"; - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); - - private final CameraDevice.StateListener mProxy; - - // Guards mWaiting - private final Object mLock = new Object(); - private boolean mWaiting = false; - - private final LinkedBlockingQueue mRecentStates = - new LinkedBlockingQueue(); - - private void setCurrentState(int state) { - if (VERBOSE) Log.v(TAG, "Camera device state now " + stateToString(state)); - try { - mRecentStates.put(state); - } catch(InterruptedException e) { - throw new RuntimeException("Unable to set device state", e); - } - } - - private static final String[] mStateNames = { - "STATE_UNINITIALIZED", - "STATE_OPENED", - "STATE_CLOSED", - "STATE_DISCONNECTED", - "STATE_ERROR" - }; - - /** - * Device has not reported any state yet - */ - public static final int STATE_UNINITIALIZED = -1; - - /** - * Device is in the first-opened state (transitory) - */ - public static final int STATE_OPENED = 0; - - /** - * Device is closed - */ - public static final int STATE_CLOSED = 1; - - /** - * Device is disconnected - */ - public static final int STATE_DISCONNECTED = 2; - - /** - * Device has encountered a fatal error - */ - public static final int STATE_ERROR = 3; - - /** - * Total number of reachable states - */ - private static int NUM_STATES = 4; - - public BlockingStateListener() { - mProxy = null; - } - - public BlockingStateListener(CameraDevice.StateListener listener) { - mProxy = listener; - } - - @Override - public void onOpened(CameraDevice camera) { - if (mProxy != null) mProxy.onOpened(camera); - setCurrentState(STATE_OPENED); - } - - @Override - public void onDisconnected(CameraDevice camera) { - if (mProxy != null) mProxy.onDisconnected(camera); - setCurrentState(STATE_DISCONNECTED); - } - - @Override - public void onError(CameraDevice camera, int error) { - if (mProxy != null) mProxy.onError(camera, error); - setCurrentState(STATE_ERROR); - } - - @Override - public void onClosed(CameraDevice camera) { - if (mProxy != null) mProxy.onClosed(camera); - setCurrentState(STATE_CLOSED); - } - - /** - * Wait until the desired state is observed, checking all state - * transitions since the last state that was waited on. - * - *

Note: Only one waiter allowed at a time!

- * - * @param desired state to observe a transition to - * @param timeout how long to wait in milliseconds - * - * @throws TimeoutRuntimeException if the desired state is not observed before timeout. - */ - public void waitForState(int state, long timeout) { - Integer[] stateArray = { state }; - - waitForAnyOfStates(Arrays.asList(stateArray), timeout); - } - - /** - * Wait until the one of the desired states is observed, checking all - * state transitions since the last state that was waited on. - * - *

Note: Only one waiter allowed at a time!

- * - * @param states Set of desired states to observe a transition to. - * @param timeout how long to wait in milliseconds - * - * @return the state reached - * @throws TimeoutRuntimeException if none of the states is observed before timeout. - * - */ - public int waitForAnyOfStates(Collection states, final long timeout) { - synchronized(mLock) { - if (mWaiting) throw new IllegalStateException("Only one waiter allowed at a time"); - mWaiting = true; - } - if (VERBOSE) { - StringBuilder s = new StringBuilder("Waiting for state(s) "); - appendStates(s, states); - Log.v(TAG, s.toString()); - } - - Integer nextState = null; - long timeoutLeft = timeout; - long startMs = SystemClock.elapsedRealtime(); - try { - while ((nextState = mRecentStates.poll(timeoutLeft, TimeUnit.MILLISECONDS)) - != null) { - if (VERBOSE) { - Log.v(TAG, " Saw transition to " + stateToString(nextState)); - } - if (states.contains(nextState)) break; - long endMs = SystemClock.elapsedRealtime(); - timeoutLeft -= (endMs - startMs); - startMs = endMs; - } - } catch (InterruptedException e) { - throw new UnsupportedOperationException("Does not support interrupts on waits", e); - } - - synchronized(mLock) { - mWaiting = false; - } - - if (!states.contains(nextState)) { - StringBuilder s = new StringBuilder("Timed out after "); - s.append(timeout); - s.append(" ms waiting for state(s) "); - appendStates(s, states); - - throw new TimeoutRuntimeException(s.toString()); - } - - return nextState; - } - - /** - * Convert state integer to a String - */ - public static String stateToString(int state) { - return mStateNames[state + 1]; - } - - /** - * Append all states to string - */ - public static void appendStates(StringBuilder s, Collection states) { - boolean start = true; - for (Integer state: states) { - if (!start) s.append(" "); - s.append(stateToString(state)); - start = false; - } - } -} diff --git a/camera2/public/src/com/android/ex/camera2/pos/AutoFocusStateMachine.java b/camera2/public/src/com/android/ex/camera2/pos/AutoFocusStateMachine.java index 9fa2af2..e8a3ab6 100644 --- a/camera2/public/src/com/android/ex/camera2/pos/AutoFocusStateMachine.java +++ b/camera2/public/src/com/android/ex/camera2/pos/AutoFocusStateMachine.java @@ -91,7 +91,7 @@ public class AutoFocusStateMachine { /** * Invoke every time we get a new CaptureResult via - * {@link CameraDevice.CaptureListener#onCaptureCompleted}. + * {@link CameraDevice.CaptureCallback#onCaptureCompleted}. * *

This function is responsible for dispatching updates via the * {@link AutoFocusStateListener} so without calling this on a regular basis, no diff --git a/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureCallbackForwarder.java b/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureCallbackForwarder.java new file mode 100644 index 0000000..97b5b6e --- /dev/null +++ b/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureCallbackForwarder.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 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.ex.camera2.utils; + +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCaptureSession.CaptureCallback; +import android.hardware.camera2.CaptureFailure; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; +import android.os.Handler; + +/** + * Proxy that forwards all updates to another {@link CaptureCallback}, invoking + * its callbacks on a separate {@link Handler}. + */ +public class Camera2CaptureCallbackForwarder extends CaptureCallback { + private CaptureCallback mListener; + private Handler mHandler; + + public Camera2CaptureCallbackForwarder(CaptureCallback listener, Handler handler) { + mListener = listener; + mHandler = handler; + } + + @Override + public void onCaptureCompleted(final CameraCaptureSession session, final CaptureRequest request, + final TotalCaptureResult result) { + mHandler.post(new Runnable() { + @Override + public void run() { + mListener.onCaptureCompleted(session, request, result); + }}); + } + + @Override + public void onCaptureFailed(final CameraCaptureSession session, final CaptureRequest request, + final CaptureFailure failure) { + mHandler.post(new Runnable() { + @Override + public void run() { + mListener.onCaptureFailed(session, request, failure); + }}); + } + + @Override + public void onCaptureProgressed(final CameraCaptureSession session, + final CaptureRequest request, + final CaptureResult partialResult) { + mHandler.post(new Runnable() { + @Override + public void run() { + mListener.onCaptureProgressed(session, request, partialResult); + }}); + } + + @Override + public void onCaptureSequenceAborted(final CameraCaptureSession session, final int sequenceId) { + mHandler.post(new Runnable() { + @Override + public void run() { + mListener.onCaptureSequenceAborted(session, sequenceId); + }}); + } + + @Override + public void onCaptureSequenceCompleted(final CameraCaptureSession session, final int sequenceId, + final long frameNumber) { + mHandler.post(new Runnable() { + @Override + public void run() { + mListener.onCaptureSequenceCompleted(session, sequenceId, frameNumber); + }}); + } + + @Override + public void onCaptureStarted(final CameraCaptureSession session, final CaptureRequest request, + final long timestamp) { + mHandler.post(new Runnable() { + @Override + public void run() { + mListener.onCaptureStarted(session, request, timestamp); + }}); + } +} diff --git a/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureCallbackSplitter.java b/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureCallbackSplitter.java new file mode 100644 index 0000000..f813076 --- /dev/null +++ b/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureCallbackSplitter.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014 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.ex.camera2.utils; + +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCaptureSession.CaptureCallback; +import android.hardware.camera2.CaptureFailure; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * Junction that allows notifying multiple {@link CaptureCallback}s whenever + * the {@link CameraCaptureSession} posts a capture-related update. + */ +public class Camera2CaptureCallbackSplitter extends CaptureCallback { + private final List mRecipients = new LinkedList<>(); + + /** + * @param recipients The listeners to notify. Any {@code null} passed here + * will be completely ignored. + */ + public Camera2CaptureCallbackSplitter(CaptureCallback... recipients) { + for (CaptureCallback listener : recipients) { + if (listener != null) { + mRecipients.add(listener); + } + } + } + + @Override + public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, + TotalCaptureResult result) { + for (CaptureCallback target : mRecipients) { + target.onCaptureCompleted(session, request, result); + } + } + + @Override + public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, + CaptureFailure failure) { + for (CaptureCallback target : mRecipients) { + target.onCaptureFailed(session, request, failure); + } + } + + @Override + public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, + CaptureResult partialResult) { + for (CaptureCallback target : mRecipients) { + target.onCaptureProgressed(session, request, partialResult); + } + } + + @Override + public void onCaptureSequenceAborted(CameraCaptureSession session, int sequenceId) { + for (CaptureCallback target : mRecipients) { + target.onCaptureSequenceAborted(session, sequenceId); + } + } + + @Override + public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, + long frameNumber) { + for (CaptureCallback target : mRecipients) { + target.onCaptureSequenceCompleted(session, sequenceId, frameNumber); + } + } + + @Override + public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, + long timestamp) { + for (CaptureCallback target : mRecipients) { + target.onCaptureStarted(session, request, timestamp); + } + } +} diff --git a/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerForwarder.java b/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerForwarder.java deleted file mode 100644 index 35b1c6d..0000000 --- a/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerForwarder.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2014 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.ex.camera2.utils; - -import android.hardware.camera2.CameraCaptureSession; -import android.hardware.camera2.CameraCaptureSession.CaptureListener; -import android.hardware.camera2.CaptureFailure; -import android.hardware.camera2.CaptureRequest; -import android.hardware.camera2.CaptureResult; -import android.hardware.camera2.TotalCaptureResult; -import android.os.Handler; - -/** - * Proxy that forwards all updates to another {@link CaptureListener}, invoking - * its callbacks on a separate {@link Handler}. - */ -public class Camera2CaptureListenerForwarder extends CaptureListener { - private CaptureListener mListener; - private Handler mHandler; - - public Camera2CaptureListenerForwarder(CaptureListener listener, Handler handler) { - mListener = listener; - mHandler = handler; - } - - @Override - public void onCaptureCompleted(final CameraCaptureSession session, final CaptureRequest request, - final TotalCaptureResult result) { - mHandler.post(new Runnable() { - @Override - public void run() { - mListener.onCaptureCompleted(session, request, result); - }}); - } - - @Override - public void onCaptureFailed(final CameraCaptureSession session, final CaptureRequest request, - final CaptureFailure failure) { - mHandler.post(new Runnable() { - @Override - public void run() { - mListener.onCaptureFailed(session, request, failure); - }}); - } - - @Override - public void onCaptureProgressed(final CameraCaptureSession session, - final CaptureRequest request, - final CaptureResult partialResult) { - mHandler.post(new Runnable() { - @Override - public void run() { - mListener.onCaptureProgressed(session, request, partialResult); - }}); - } - - @Override - public void onCaptureSequenceAborted(final CameraCaptureSession session, final int sequenceId) { - mHandler.post(new Runnable() { - @Override - public void run() { - mListener.onCaptureSequenceAborted(session, sequenceId); - }}); - } - - @Override - public void onCaptureSequenceCompleted(final CameraCaptureSession session, final int sequenceId, - final long frameNumber) { - mHandler.post(new Runnable() { - @Override - public void run() { - mListener.onCaptureSequenceCompleted(session, sequenceId, frameNumber); - }}); - } - - @Override - public void onCaptureStarted(final CameraCaptureSession session, final CaptureRequest request, - final long timestamp) { - mHandler.post(new Runnable() { - @Override - public void run() { - mListener.onCaptureStarted(session, request, timestamp); - }}); - } -} diff --git a/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerSplitter.java b/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerSplitter.java deleted file mode 100644 index a13dc04..0000000 --- a/camera2/utils/src/com/android/ex/camera2/utils/Camera2CaptureListenerSplitter.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2014 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.ex.camera2.utils; - -import android.hardware.camera2.CameraCaptureSession; -import android.hardware.camera2.CameraCaptureSession.CaptureListener; -import android.hardware.camera2.CaptureFailure; -import android.hardware.camera2.CaptureRequest; -import android.hardware.camera2.CaptureResult; -import android.hardware.camera2.TotalCaptureResult; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * Junction that allows notifying multiple {@link CaptureListener}s whenever - * the {@link CameraCaptureSession} posts a capture-related update. - */ -public class Camera2CaptureListenerSplitter extends CaptureListener { - private final List mRecipients = new LinkedList<>(); - - /** - * @param recipients The listeners to notify. Any {@code null} passed here - * will be completely ignored. - */ - public Camera2CaptureListenerSplitter(CaptureListener... recipients) { - for (CaptureListener listener : recipients) { - if (listener != null) { - mRecipients.add(listener); - } - } - } - - @Override - public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, - TotalCaptureResult result) { - for (CaptureListener target : mRecipients) { - target.onCaptureCompleted(session, request, result); - } - } - - @Override - public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, - CaptureFailure failure) { - for (CaptureListener target : mRecipients) { - target.onCaptureFailed(session, request, failure); - } - } - - @Override - public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, - CaptureResult partialResult) { - for (CaptureListener target : mRecipients) { - target.onCaptureProgressed(session, request, partialResult); - } - } - - @Override - public void onCaptureSequenceAborted(CameraCaptureSession session, int sequenceId) { - for (CaptureListener target : mRecipients) { - target.onCaptureSequenceAborted(session, sequenceId); - } - } - - @Override - public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, - long frameNumber) { - for (CaptureListener target : mRecipients) { - target.onCaptureSequenceCompleted(session, sequenceId, frameNumber); - } - } - - @Override - public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, - long timestamp) { - for (CaptureListener target : mRecipients) { - target.onCaptureStarted(session, request, timestamp); - } - } -} diff --git a/camera2/utils/tests/src/com/android/ex/camera2/utils/Camera2DeviceTester.java b/camera2/utils/tests/src/com/android/ex/camera2/utils/Camera2DeviceTester.java index 4db6dfb..e8639ba 100644 --- a/camera2/utils/tests/src/com/android/ex/camera2/utils/Camera2DeviceTester.java +++ b/camera2/utils/tests/src/com/android/ex/camera2/utils/Camera2DeviceTester.java @@ -52,7 +52,7 @@ public class Camera2DeviceTester { @InjectContext public Context mContext; - private class DeviceCapturer extends CameraDevice.StateListener { + private class DeviceCapturer extends CameraDevice.StateCallback { private CameraDevice mCamera; public CameraDevice captureCameraDevice() throws Exception { diff --git a/camera2/utils/tests/src/com/android/ex/camera2/utils/Camera2UtilsTest.java b/camera2/utils/tests/src/com/android/ex/camera2/utils/Camera2UtilsTest.java index 7847526..3156cf7 100644 --- a/camera2/utils/tests/src/com/android/ex/camera2/utils/Camera2UtilsTest.java +++ b/camera2/utils/tests/src/com/android/ex/camera2/utils/Camera2UtilsTest.java @@ -24,7 +24,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.graphics.Rect; -import android.hardware.camera2.CameraCaptureSession.CaptureListener; +import android.hardware.camera2.CameraCaptureSession.CaptureCallback; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureRequest.Key; @@ -33,65 +33,65 @@ import android.view.Surface; import org.junit.Test; public class Camera2UtilsTest extends Camera2DeviceTester { - private void captureListenerSplitterAllCallbacksReceived(CaptureListener splitter, - CaptureListener... terminals) { + private void captureListenerSplitterAllCallbacksReceived(CaptureCallback splitter, + CaptureCallback... terminals) { splitter.onCaptureCompleted(null, null, null); - for (CaptureListener each : terminals) { + for (CaptureCallback each : terminals) { verify(each).onCaptureCompleted(null, null, null); } splitter.onCaptureFailed(null, null, null); - for (CaptureListener each : terminals) { + for (CaptureCallback each : terminals) { verify(each).onCaptureFailed(null, null, null); } splitter.onCaptureProgressed(null, null, null); - for (CaptureListener each : terminals) { + for (CaptureCallback each : terminals) { verify(each).onCaptureProgressed(null, null, null); } splitter.onCaptureSequenceAborted(null, 0); - for (CaptureListener each : terminals) { + for (CaptureCallback each : terminals) { verify(each).onCaptureSequenceAborted(null, 0); } splitter.onCaptureSequenceCompleted(null, 0, 0L); - for (CaptureListener each : terminals) { + for (CaptureCallback each : terminals) { verify(each).onCaptureSequenceCompleted(null, 0, 0L); } splitter.onCaptureStarted(null, null, 0L); - for (CaptureListener each : terminals) { + for (CaptureCallback each : terminals) { verify(each).onCaptureStarted(null, null, 0L); } } @Test public void captureListenerSplitter() { - CaptureListener firstBackingListener = mock(CaptureListener.class); - CaptureListener secondBackingListener = mock(CaptureListener.class); + CaptureCallback firstBackingListener = mock(CaptureCallback.class); + CaptureCallback secondBackingListener = mock(CaptureCallback.class); captureListenerSplitterAllCallbacksReceived( - new Camera2CaptureListenerSplitter(firstBackingListener, secondBackingListener), + new Camera2CaptureCallbackSplitter(firstBackingListener, secondBackingListener), firstBackingListener, secondBackingListener); } @Test public void captureListenerSplitterEmpty() { - captureListenerSplitterAllCallbacksReceived(new Camera2CaptureListenerSplitter()); + captureListenerSplitterAllCallbacksReceived(new Camera2CaptureCallbackSplitter()); } @Test public void captureListenerSplitterNoNpe() { captureListenerSplitterAllCallbacksReceived( - new Camera2CaptureListenerSplitter((CaptureListener) null)); + new Camera2CaptureCallbackSplitter((CaptureCallback) null)); } @Test public void captureListenerSplitterMultipleNulls() { captureListenerSplitterAllCallbacksReceived( - new Camera2CaptureListenerSplitter(null, null, null)); + new Camera2CaptureCallbackSplitter(null, null, null)); } @Test public void captureListenerSplitterValidAndNull() { - CaptureListener onlyRealBackingListener = mock(CaptureListener.class); + CaptureCallback onlyRealBackingListener = mock(CaptureCallback.class); captureListenerSplitterAllCallbacksReceived( - new Camera2CaptureListenerSplitter(null, onlyRealBackingListener), + new Camera2CaptureCallbackSplitter(null, onlyRealBackingListener), onlyRealBackingListener); } -- cgit v1.2.3