FileDocCategorySizeDatePackage
StateWaiter.javaAPI DocAndroid 5.1 API7702Thu Mar 12 22:22:48 GMT 2015com.android.ex.camera2.utils

StateWaiter

public final class StateWaiter extends Object
Block until a specific state change occurs.

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.

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.

Fields Summary
private static final String
TAG
private static final boolean
VERBOSE
private final String[]
mStateNames
private final int
mStateCount
private final StateChangeListener
mListener
private final AtomicBoolean
mWaiting
Guard waitForState, waitForAnyState to only have one waiter
private final LinkedBlockingQueue
mQueuedStates
Constructors Summary
public StateWaiter(String[] stateNames)
Create a new state waiter.

All {@code state}/{@code states} arguments used in other methods must be in the range of {@code [0, stateNames.length - 1]}.

param
stateNames an array of string names, used to mark the range of the valid states


                                                  
       
        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));
            }
        };
    
Methods Summary
public voidappendStateNames(java.lang.StringBuilder s, java.util.Collection states)
Append all states to string

        checkStateCollectionInRange(states);

        boolean start = true;
        for (Integer state : states) {
            if (!start) {
                s.append(" ");
            }

            s.append(getStateName(state));
            start = false;
        }
    
private java.util.CollectioncheckStateCollectionInRange(java.util.Collection states)

        for (int state : states) {
            checkStateInRange(state);
        }

        return states;
    
private intcheckStateInRange(int state)

        if (state < 0 || state >= mStateCount) {
            throw new IllegalArgumentException("State out of range " + state);
        }

        return state;
    
public StateChangeListenergetListener()

        return mListener;
    
public java.lang.StringgetStateName(int state)
Convert state integer to a String

        return mStateNames[checkStateInRange(state)];
    
private voidqueueStateTransition(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);
        }
    
public intwaitForAnyOfStates(java.util.Collection states, long 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.

Any intermediate state transitions that are not in {@code states} are ignored.

Note: Only one waiter allowed at a time!

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

        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;
    
public voidwaitForState(int state, long timeoutMs)
Wait until the desired state is observed, checking all state transitions since the last time a state was waited on.

Any intermediate state transitions that is not {@code state} are ignored.

Note: Only one waiter allowed at a time!

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

        Integer[] stateArray = { checkStateInRange(state) };

        waitForAnyOfStates(Arrays.asList(stateArray), timeoutMs);