This source file includes following definitions.
- getListener
- waitForState
- waitForAnyOfStates
- getStateName
- appendStateNames
- queueStateTransition
- checkStateInRange
- checkStateCollectionInRange
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;
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;
private final AtomicBoolean mWaiting = new AtomicBoolean(false);
private final LinkedBlockingQueue<Integer> mQueuedStates = new LinkedBlockingQueue<>();
public StateWaiter(String[] stateNames) {
mStateCount = stateNames.length;
mStateNames = new String[mStateCount];
System.arraycopy(stateNames, 0, mStateNames, 0, mStateCount);
mListener = new StateChangeListener() {
@Override
public void onStateChanged(int state) {
queueStateTransition(checkStateInRange(state));
}
};
}
public StateChangeListener getListener() {
return mListener;
}
public void waitForState(int state, long timeoutMs) {
Integer[] stateArray = { checkStateInRange(state) };
waitForAnyOfStates(Arrays.asList(stateArray), timeoutMs);
}
public int waitForAnyOfStates(Collection<Integer> states, final long timeoutMs) {
checkStateCollectionInRange(states);
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 {
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 String getStateName(int state) {
return mStateNames[checkStateInRange(state)];
}
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;
}
}