diff options
Diffstat (limited to 'camera2/public/src')
7 files changed, 642 insertions, 77 deletions
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 de036e1..02dbbba 100644 --- a/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java +++ b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCameraManager.java @@ -275,26 +275,6 @@ public class BlockingCameraManager { } @Override - public void onUnconfigured(CameraDevice camera) { - if (mProxy != null) mProxy.onUnconfigured(camera); - } - - @Override - public void onIdle(CameraDevice camera) { - if (mProxy != null) mProxy.onIdle(camera); - } - - @Override - public void onActive(CameraDevice camera) { - if (mProxy != null) mProxy.onActive(camera); - } - - @Override - public void onBusy(CameraDevice camera) { - if (mProxy != null) mProxy.onBusy(camera); - } - - @Override public void onClosed(CameraDevice camera) { if (mProxy != null) mProxy.onClosed(camera); } diff --git a/camera2/public/src/com/android/ex/camera2/blocking/BlockingCaptureListener.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCaptureListener.java new file mode 100644 index 0000000..eae85d1 --- /dev/null +++ b/camera2/public/src/com/android/ex/camera2/blocking/BlockingCaptureListener.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. + * + * <p>Provides a waiter that can be used to block until the next unobserved state of the + * requested type arrives.</p> + * + * <p>Pass-through all StateListener changes to the proxy.</p> + * + * @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. + * + * <p>Only one thread should wait at a time.</p> + */ + 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/BlockingSessionListener.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingSessionListener.java new file mode 100644 index 0000000..26bb652 --- /dev/null +++ b/camera2/public/src/com/android/ex/camera2/blocking/BlockingSessionListener.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. + * + * <p>Provides a waiter that can be used to block until the next unobserved state of the + * requested type arrives.</p> + * + * <p>Pass-through all StateListener changes to the proxy.</p> + * + * @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. + * + * <p>Only one thread should wait at a time.</p> + */ + 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. + * + * <p>Does not consume any of the states from the state waiter.</p> + * + * @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<CameraCaptureSession> { + 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/BlockingStateListener.java b/camera2/public/src/com/android/ex/camera2/blocking/BlockingStateListener.java index 619ba0a..02c2ba3 100644 --- a/camera2/public/src/com/android/ex/camera2/blocking/BlockingStateListener.java +++ b/camera2/public/src/com/android/ex/camera2/blocking/BlockingStateListener.java @@ -64,10 +64,6 @@ public class BlockingStateListener extends CameraDevice.StateListener { private static final String[] mStateNames = { "STATE_UNINITIALIZED", "STATE_OPENED", - "STATE_UNCONFIGURED", - "STATE_IDLE", - "STATE_ACTIVE", - "STATE_BUSY", "STATE_CLOSED", "STATE_DISCONNECTED", "STATE_ERROR" @@ -84,44 +80,24 @@ public class BlockingStateListener extends CameraDevice.StateListener { public static final int STATE_OPENED = 0; /** - * Device is unconfigured - */ - public static final int STATE_UNCONFIGURED = 1; - - /** - * Device is idle - */ - public static final int STATE_IDLE = 2; - - /** - * Device is active (transitory) - */ - public static final int STATE_ACTIVE = 3; - - /** - * Device is busy (transitory) - */ - public static final int STATE_BUSY = 4; - - /** * Device is closed */ - public static final int STATE_CLOSED = 5; + public static final int STATE_CLOSED = 1; /** * Device is disconnected */ - public static final int STATE_DISCONNECTED = 6; + public static final int STATE_DISCONNECTED = 2; /** * Device has encountered a fatal error */ - public static final int STATE_ERROR = 7; + public static final int STATE_ERROR = 3; /** * Total number of reachable states */ - private static int NUM_STATES = 8; + private static int NUM_STATES = 4; public BlockingStateListener() { mProxy = null; @@ -133,50 +109,26 @@ public class BlockingStateListener extends CameraDevice.StateListener { @Override public void onOpened(CameraDevice camera) { - setCurrentState(STATE_OPENED); if (mProxy != null) mProxy.onOpened(camera); + setCurrentState(STATE_OPENED); } @Override public void onDisconnected(CameraDevice camera) { - setCurrentState(STATE_DISCONNECTED); if (mProxy != null) mProxy.onDisconnected(camera); + setCurrentState(STATE_DISCONNECTED); } @Override public void onError(CameraDevice camera, int error) { - setCurrentState(STATE_ERROR); if (mProxy != null) mProxy.onError(camera, error); - } - - @Override - public void onUnconfigured(CameraDevice camera) { - setCurrentState(STATE_UNCONFIGURED); - if (mProxy != null) mProxy.onUnconfigured(camera); - } - - @Override - public void onIdle(CameraDevice camera) { - setCurrentState(STATE_IDLE); - if (mProxy != null) mProxy.onIdle(camera); - } - - @Override - public void onActive(CameraDevice camera) { - setCurrentState(STATE_ACTIVE); - if (mProxy != null) mProxy.onActive(camera); - } - - @Override - public void onBusy(CameraDevice camera) { - setCurrentState(STATE_BUSY); - if (mProxy != null) mProxy.onBusy(camera); + setCurrentState(STATE_ERROR); } @Override public void onClosed(CameraDevice camera) { - setCurrentState(STATE_CLOSED); if (mProxy != null) mProxy.onClosed(camera); + setCurrentState(STATE_CLOSED); } /** 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 500fb12..9fa2af2 100644 --- a/camera2/public/src/com/android/ex/camera2/pos/AutoFocusStateMachine.java +++ b/camera2/public/src/com/android/ex/camera2/pos/AutoFocusStateMachine.java @@ -16,7 +16,7 @@ package com.android.ex.camera2.pos; import android.hardware.camera2.CameraDevice; -import android.hardware.camera2.CameraMetadata.Key; +import android.hardware.camera2.CaptureResult.Key; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.util.Log; diff --git a/camera2/public/src/com/android/ex/camera2/utils/StateChangeListener.java b/camera2/public/src/com/android/ex/camera2/utils/StateChangeListener.java new file mode 100644 index 0000000..48cca17 --- /dev/null +++ b/camera2/public/src/com/android/ex/camera2/utils/StateChangeListener.java @@ -0,0 +1,21 @@ +/* + * 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.utils; + +public interface StateChangeListener { + public void onStateChanged(int state); +} diff --git a/camera2/public/src/com/android/ex/camera2/utils/StateWaiter.java b/camera2/public/src/com/android/ex/camera2/utils/StateWaiter.java new file mode 100644 index 0000000..ec57829 --- /dev/null +++ b/camera2/public/src/com/android/ex/camera2/utils/StateWaiter.java @@ -0,0 +1,220 @@ +/* + * 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.utils; + +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; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Block until a specific state change occurs. + * + * <p>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.</p> + * + * <p>Thread interruptions are not supported; interrupting a thread that is either + * waiting with {@link #waitForState} / {@link #waitForAnyOfStates} or is currently in + * {@link StateChangeListener#onStateChanged} (provided by {@link #getListener}) will result in an + * {@link UnsupportedOperationException} being raised on that thread.</p> + */ +public final class StateWaiter { + + private static final String TAG = "StateWaiter"; + private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + + private final String[] mStateNames; + private final int mStateCount; + private final StateChangeListener mListener; + + /** Guard waitForState, waitForAnyState to only have one waiter */ + private final AtomicBoolean mWaiting = new AtomicBoolean(false); + + private final LinkedBlockingQueue<Integer> mQueuedStates = new LinkedBlockingQueue<>(); + + /** + * Create a new state waiter. + * + * <p>All {@code state}/{@code states} arguments used in other methods must be + * in the range of {@code [0, stateNames.length - 1]}.</p> + * + * @param stateNames an array of string names, used to mark the range of the valid states + */ + public StateWaiter(String[] stateNames) { + mStateCount = stateNames.length; + mStateNames = new String[mStateCount]; + System.arraycopy(stateNames, /*srcPos*/0, mStateNames, /*dstPos*/0, mStateCount); + + mListener = new StateChangeListener() { + @Override + public void onStateChanged(int state) { + queueStateTransition(checkStateInRange(state)); + } + }; + } + + public StateChangeListener getListener() { + return mListener; + } + + /** + * Wait until the desired state is observed, checking all state + * transitions since the last time a state was waited on. + * + * <p>Any intermediate state transitions that is not {@code state} are ignored.</p> + * + * <p>Note: Only one waiter allowed at a time!</p> + * + * @param desired state to observe a transition to + * @param timeoutMs how long to wait in milliseconds + * + * @throws IllegalArgumentException if {@code state} was out of range + * @throws TimeoutRuntimeException if the desired state is not observed before timeout. + * @throws IllegalStateException if another thread is already waiting for a state transition + */ + public void waitForState(int state, long timeoutMs) { + Integer[] stateArray = { checkStateInRange(state) }; + + waitForAnyOfStates(Arrays.asList(stateArray), timeoutMs); + } + + /** + * Wait until the one of the desired {@code states} is observed, checking all + * state transitions since the last time a state was waited on. + * + * <p>Any intermediate state transitions that are not in {@code states} are ignored.</p> + * + * <p>Note: Only one waiter allowed at a time!</p> + * + * @param states Set of desired states to observe a transition to. + * @param timeoutMs how long to wait in milliseconds + * + * @return the state reached + * + * @throws IllegalArgumentException if {@code state} was out of range + * @throws TimeoutRuntimeException if none of the states is observed before timeout. + * @throws IllegalStateException if another thread is already waiting for a state transition + */ + public int waitForAnyOfStates(Collection<Integer> states, final long timeoutMs) { + checkStateCollectionInRange(states); + + // Acquire exclusive waiting privileges + if (mWaiting.getAndSet(true)) { + throw new IllegalStateException("Only one waiter allowed at a time"); + } + + Integer nextState = null; + try { + if (VERBOSE) { + StringBuilder s = new StringBuilder("Waiting for state(s) "); + appendStateNames(s, states); + Log.v(TAG, s.toString()); + } + + long timeoutLeft = timeoutMs; + long startMs = SystemClock.elapsedRealtime(); + while ((nextState = mQueuedStates.poll(timeoutLeft, TimeUnit.MILLISECONDS)) != null) { + if (VERBOSE) { + Log.v(TAG, " Saw transition to " + getStateName(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); + } finally { + // Release exclusive waiting privileges + mWaiting.set(false); + } + + if (!states.contains(nextState)) { + StringBuilder s = new StringBuilder("Timed out after "); + s.append(timeoutMs); + s.append(" ms waiting for state(s) "); + appendStateNames(s, states); + + throw new TimeoutRuntimeException(s.toString()); + } + + return nextState; + } + + /** + * Convert state integer to a String + */ + public String getStateName(int state) { + return mStateNames[checkStateInRange(state)]; + } + + /** + * Append all states to string + */ + public void appendStateNames(StringBuilder s, Collection<Integer> states) { + checkStateCollectionInRange(states); + + boolean start = true; + for (Integer state : states) { + if (!start) { + s.append(" "); + } + + s.append(getStateName(state)); + start = false; + } + } + + private void queueStateTransition(int state) { + if (VERBOSE) Log.v(TAG, "setCurrentState - state now " + getStateName(state)); + + try { + mQueuedStates.put(state); + } catch(InterruptedException e) { + throw new UnsupportedOperationException("Unable to set current state", e); + } + } + + private int checkStateInRange(int state) { + if (state < 0 || state >= mStateCount) { + throw new IllegalArgumentException("State out of range " + state); + } + + return state; + } + + private Collection<Integer> checkStateCollectionInRange(Collection<Integer> states) { + for (int state : states) { + checkStateInRange(state); + } + + return states; + } + +} |