Merge "SyncSM02: implement addState function" into main
This commit is contained in:
@@ -18,11 +18,15 @@ package com.android.networkstack.tethering.util;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.util.ArrayMap;
|
||||||
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.internal.util.State;
|
import com.android.internal.util.State;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of a state machine, meant to be called synchronously.
|
* An implementation of a state machine, meant to be called synchronously.
|
||||||
@@ -35,6 +39,7 @@ public class SyncStateMachine {
|
|||||||
@NonNull private final String mName;
|
@NonNull private final String mName;
|
||||||
@NonNull private final Thread mMyThread;
|
@NonNull private final Thread mMyThread;
|
||||||
private final boolean mDbg;
|
private final boolean mDbg;
|
||||||
|
private final ArrayMap<State, StateInfo> mStateInfo = new ArrayMap<>();
|
||||||
|
|
||||||
// mCurrentState is the current state. mDestState is the target state that mCurrentState will
|
// mCurrentState is the current state. mDestState is the target state that mCurrentState will
|
||||||
// transition to. The value of mDestState can be changed when a state processes a message and
|
// transition to. The value of mDestState can be changed when a state processes a message and
|
||||||
@@ -91,9 +96,9 @@ public class SyncStateMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add all of states to the state machine. Different StateInfos which have same state but have
|
* Add all of states to the state machine. Different StateInfos which have same state are not
|
||||||
* different parents are not allowed. A state can not have multiple parent states.
|
* allowed. In other words, a state can not have multiple parent states. #addAllStates can
|
||||||
* This can only be called once either from mMyThread or before mMyThread started.
|
* only be called once either from mMyThread or before mMyThread started.
|
||||||
*/
|
*/
|
||||||
public final void addAllStates(@NonNull final List<StateInfo> stateInfos) {
|
public final void addAllStates(@NonNull final List<StateInfo> stateInfos) {
|
||||||
ensureCorrectOrNotStartedThread();
|
ensureCorrectOrNotStartedThread();
|
||||||
@@ -101,13 +106,39 @@ public class SyncStateMachine {
|
|||||||
if (mCurrentState != null) {
|
if (mCurrentState != null) {
|
||||||
throw new IllegalStateException("State only can be added before started");
|
throw new IllegalStateException("State only can be added before started");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stateInfos.isEmpty()) throw new IllegalStateException("Empty state is not allowed");
|
||||||
|
|
||||||
|
if (!mStateInfo.isEmpty()) throw new IllegalStateException("States are already configured");
|
||||||
|
|
||||||
|
final Set<Class> usedClasses = new ArraySet<>();
|
||||||
|
for (final StateInfo info : stateInfos) {
|
||||||
|
Objects.requireNonNull(info.state);
|
||||||
|
if (!usedClasses.add(info.state.getClass())) {
|
||||||
|
throw new IllegalStateException("Adding the same state multiple times in a state "
|
||||||
|
+ "machine is forbidden because it tends to be confusing; it can be done "
|
||||||
|
+ "with anonymous subclasses but consider carefully whether you want to "
|
||||||
|
+ "use a single state or other alternatives instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
mStateInfo.put(info.state, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether all of parent states indicated from StateInfo are added.
|
||||||
|
for (final StateInfo info : stateInfos) {
|
||||||
|
if (info.parent != null) ensureExistingState(info.parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the state machine. The initial state can't be child state.
|
* Start the state machine. The initial state can't be child state.
|
||||||
|
*
|
||||||
|
* @param initialState the first state of this machine. The state must be exact state object
|
||||||
|
* setting up by {@link #addAllStates}, not a copy of it.
|
||||||
*/
|
*/
|
||||||
public final void start(@NonNull final State initialState) {
|
public final void start(@NonNull final State initialState) {
|
||||||
ensureCorrectThread();
|
ensureCorrectThread();
|
||||||
|
ensureExistingState(initialState);
|
||||||
|
|
||||||
mCurrentState = initialState;
|
mCurrentState = initialState;
|
||||||
mDestState = initialState;
|
mDestState = initialState;
|
||||||
@@ -127,11 +158,13 @@ public class SyncStateMachine {
|
|||||||
* This function can NOT be called inside the State enter and exit function. The transition
|
* This function can NOT be called inside the State enter and exit function. The transition
|
||||||
* target is always defined and can never be changed mid-way of state transition.
|
* target is always defined and can never be changed mid-way of state transition.
|
||||||
*
|
*
|
||||||
* @param destState will be the state to transition to.
|
* @param destState will be the state to transition to. The state must be the same instance set
|
||||||
|
* up by {@link #addAllStates}, not a copy of it.
|
||||||
*/
|
*/
|
||||||
public final void transitionTo(@NonNull final State destState) {
|
public final void transitionTo(@NonNull final State destState) {
|
||||||
if (mDbg) Log.d(mName, "transitionTo " + destState);
|
if (mDbg) Log.d(mName, "transitionTo " + destState);
|
||||||
ensureCorrectThread();
|
ensureCorrectThread();
|
||||||
|
ensureExistingState(destState);
|
||||||
|
|
||||||
if (mDestState == mCurrentState) {
|
if (mDestState == mCurrentState) {
|
||||||
mDestState = destState;
|
mDestState = destState;
|
||||||
@@ -151,4 +184,8 @@ public class SyncStateMachine {
|
|||||||
|
|
||||||
ensureCorrectThread();
|
ensureCorrectThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ensureExistingState(@NonNull final State state) {
|
||||||
|
if (!mStateInfo.containsKey(state)) throw new IllegalStateException("Invalid state");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user