import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Calendar;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Vector;
* machine will cause <code>haltedProcessMessage</code> to be invoked.</p>
*
* <p>If it is desirable to completely stop the state machine call <code>quit</code> or
- * <code>abort</code>. These will call <code>exit</code> of the current state and its parents, call
- * <code>onQuiting</code> and then exit Thread/Loopers.</p>
+ * <code>quitNow</code>. These will call <code>exit</code> of the current state and its parents,
+ * call <code>onQuiting</code> and then exit Thread/Loopers.</p>
*
* <p>In addition to <code>processMessage</code> each <code>State</code> has
* an <code>enter</code> method and <code>exit</exit> method which may be overridden.</p>
* {@hide}
*/
public static class LogRec {
+ private StateMachine mSm;
private long mTime;
private int mWhat;
private String mInfo;
- private State mState;
- private State mOrgState;
- private State mTransitionToState;
+ private IState mState;
+ private IState mOrgState;
+ private IState mDstState;
/**
* Constructor
* @param transToState is the state that was transitioned to after the message was
* processed.
*/
- LogRec(Message msg, String info, State state, State orgState, State transToState) {
- update(msg, info, state, orgState, transToState);
+ LogRec(StateMachine sm, Message msg, String info, IState state, IState orgState,
+ IState transToState) {
+ update(sm, msg, info, state, orgState, transToState);
}
/**
* Update the information in the record.
* @param state that handled the message
- * @param orgState is the first state the received the message but
- * did not processes the message.
- * @param transToState is the state that was transitioned to after the message was
- * processed.
+ * @param orgState is the first state the received the message
+ * @param dstState is the state that was the transition target when logging
*/
- public void update(Message msg, String info, State state, State orgState,
- State transToState) {
+ public void update(StateMachine sm, Message msg, String info, IState state, IState orgState,
+ IState dstState) {
+ mSm = sm;
mTime = System.currentTimeMillis();
mWhat = (msg != null) ? msg.what : 0;
mInfo = info;
mState = state;
mOrgState = orgState;
- mTransitionToState = transToState;
+ mDstState = dstState;
}
/**
/**
* @return the state that handled this message
*/
- public State getState() {
+ public IState getState() {
return mState;
}
/**
- * @return the original state that received the message.
+ * @return the state destination state if a transition is occurring or null if none.
*/
- public State getOriginalState() {
- return mOrgState;
+ public IState getDestState() {
+ return mDstState;
}
+
/**
- * @return as string
+ * @return the original state that received the message.
*/
- public String toString(StateMachine sm) {
+ public IState getOriginalState() {
+ return mOrgState;
+ }
+
+ @Override
+ public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("time=");
Calendar c = Calendar.getInstance();
sb.append(" org=");
sb.append(mOrgState == null ? "<null>" : mOrgState.getName());
sb.append(" dest=");
- sb.append(mTransitionToState == null ? "<null>" : mTransitionToState.getName());
+ sb.append(mDstState == null ? "<null>" : mDstState.getName());
sb.append(" what=");
- String what = sm.getWhatToString(mWhat);
+ String what = mSm != null ? mSm.getWhatToString(mWhat) : "";
if (TextUtils.isEmpty(what)) {
sb.append(mWhat);
sb.append("(0x");
* processed.
*
*/
- synchronized void add(Message msg, String messageInfo, State state, State orgState,
- State transToState) {
+ synchronized void add(StateMachine sm, Message msg, String messageInfo, IState state,
+ IState orgState,
+ IState transToState) {
mCount += 1;
if (mLogRecVector.size() < mMaxSize) {
- mLogRecVector.add(new LogRec(msg, messageInfo, state, orgState, transToState));
+ mLogRecVector.add(new LogRec(sm, msg, messageInfo, state, orgState, transToState));
} else {
LogRec pmi = mLogRecVector.get(mOldestIndex);
mOldestIndex += 1;
if (mOldestIndex >= mMaxSize) {
mOldestIndex = 0;
}
- pmi.update(msg, messageInfo, state, orgState, transToState);
+ pmi.update(sm, msg, messageInfo, state, orgState, transToState);
}
}
}
throw new RuntimeException("StateMachine.handleMessage: " +
"The start method not called, received msg: " + msg);
}
- performTransitions(msgProcessedState);
+ performTransitions(msgProcessedState, msg);
- if (mDbg) mSm.log("handleMessage: X");
+ // We need to check if mSm == null here as we could be quitting.
+ if (mDbg && mSm != null) mSm.log("handleMessage: X");
}
/**
* Do any transitions
* @param msgProcessedState is the state that processed the message
*/
- private void performTransitions(State msgProcessedState) {
+ private void performTransitions(State msgProcessedState, Message msg) {
/**
* If transitionTo has been called, exit and then enter
* the appropriate states. We loop on this to allow
* enter and exit methods to use transitionTo.
*/
- State destState = null;
State orgState = mStateStack[mStateStackTopIndex].state;
- /** Record whether message needs to be logged before transitions */
- boolean recordLogMsg = mSm.recordLogRec(mMsg);
+ /**
+ * Record whether message needs to be logged before we transition and
+ * and we won't log special messages SM_INIT_CMD or SM_QUIT_CMD which
+ * always set msg.obj to the handler.
+ */
+ boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj == mSmHandlerObj);
- while (mDestState != null) {
- if (mDbg) mSm.log("handleMessage: new destination call exit");
+ if (mLogRecords.logOnlyTransitions()) {
+ /** Record only if there is a transition */
+ if (mDestState != null) {
+ mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
+ orgState, mDestState);
+ }
+ } else if (recordLogMsg) {
+ /** Record message */
+ mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
+ orgState, mDestState);
+ }
+ State destState = mDestState;
+ if (destState != null) {
/**
- * Save mDestState locally and set to null
- * to know if enter/exit use transitionTo.
+ * Process the transitions including transitions in the enter/exit methods
*/
- destState = mDestState;
- mDestState = null;
+ while (true) {
+ if (mDbg) mSm.log("handleMessage: new destination call exit/enter");
- /**
- * Determine the states to exit and enter and return the
- * common ancestor state of the enter/exit states. Then
- * invoke the exit methods then the enter methods.
- */
- StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
- invokeExitMethods(commonStateInfo);
- int stateStackEnteringIndex = moveTempStateStackToStateStack();
- invokeEnterMethods(stateStackEnteringIndex);
+ /**
+ * Determine the states to exit and enter and return the
+ * common ancestor state of the enter/exit states. Then
+ * invoke the exit methods then the enter methods.
+ */
+ StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
+ invokeExitMethods(commonStateInfo);
+ int stateStackEnteringIndex = moveTempStateStackToStateStack();
+ invokeEnterMethods(stateStackEnteringIndex);
- /**
- * Since we have transitioned to a new state we need to have
- * any deferred messages moved to the front of the message queue
- * so they will be processed before any other messages in the
- * message queue.
- */
- moveDeferredMessageAtFrontOfQueue();
+ /**
+ * Since we have transitioned to a new state we need to have
+ * any deferred messages moved to the front of the message queue
+ * so they will be processed before any other messages in the
+ * message queue.
+ */
+ moveDeferredMessageAtFrontOfQueue();
+
+ if (destState != mDestState) {
+ // A new mDestState so continue looping
+ destState = mDestState;
+ } else {
+ // No change in mDestState so we're done
+ break;
+ }
+ }
+ mDestState = null;
}
/**
mSm.onHalting();
}
}
-
- // Log only if state machine has not quit
- if (mSm != null) {
- if (mLogRecords.logOnlyTransitions()) {
- /** Record only if there is a transition */
- if (destState != null) {
- mLogRecords.add(mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
- orgState, destState);
- }
- } else if (recordLogMsg) {
- /** Record message */
- mLogRecords.add(mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
- orgState, destState);
- }
- }
}
/**
}
/**
- * @return current message
- */
- protected final Message getCurrentMessage() {
- return mSmHandler.getCurrentMessage();
- }
-
- /**
- * @return current state
- */
- protected final IState getCurrentState() {
- return mSmHandler.getCurrentState();
- }
-
- /**
* Add a new state to the state machine, parent will be null
* @param state to add
*/
}
/**
+ * @return current message
+ */
+ protected final Message getCurrentMessage() {
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return null;
+ return smh.getCurrentMessage();
+ }
+
+ /**
+ * @return current state
+ */
+ protected final IState getCurrentState() {
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return null;
+ return smh.getCurrentState();
+ }
+
+ /**
* transition to destination state. Upon returning
* from processMessage the current state's exit will
* be executed and upon the next message arriving
* @return number of log records
*/
public final int getLogRecSize() {
- return mSmHandler.mLogRecords.size();
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return 0;
+ return smh.mLogRecords.size();
}
/**
* @return the total number of records processed
*/
public final int getLogRecCount() {
- return mSmHandler.mLogRecords.count();
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return 0;
+ return smh.mLogRecords.count();
}
/**
- * @return a log record
+ * @return a log record, or null if index is out of range
*/
public final LogRec getLogRec(int index) {
- return mSmHandler.mLogRecords.get(index);
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return null;
+ return smh.mLogRecords.get(index);
}
/**
- * Add the string to LogRecords.
- *
- * @param string
+ * @return a copy of LogRecs as a collection
*/
- protected void addLogRec(String string) {
- mSmHandler.mLogRecords.add(null, string, null, null, null);
+ public final Collection<LogRec> copyLogRecs() {
+ Vector<LogRec> vlr = new Vector<LogRec>();
+ SmHandler smh = mSmHandler;
+ if (smh != null) {
+ for (LogRec lr : smh.mLogRecords.mLogRecVector) {
+ vlr.add(lr);
+ }
+ }
+ return vlr;
}
/**
- * Add the string and state to LogRecords
+ * Add the string to LogRecords.
*
* @param string
- * @param state current state
*/
- protected void addLogRec(String string, State state) {
- mSmHandler.mLogRecords.add(null, string, state, null, null);
+ protected void addLogRec(String string) {
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
+ smh.mLogRecords.add(this, smh.getCurrentMessage(), string, smh.getCurrentState(),
+ smh.mStateStack[smh.mStateStackTopIndex].state, smh.mDestState);
}
/**
}
/**
- * @return Handler
+ * @return Handler, maybe null if state machine has quit.
*/
public final Handler getHandler() {
return mSmHandler;
}
/**
- * Get a message and set Message.target = this.
+ * Get a message and set Message.target state machine handler.
*
- * @return message or null if SM has quit
+ * Note: The handler can be null if the state machine has quit,
+ * which means target will be null and may cause a AndroidRuntimeException
+ * in MessageQueue#enqueMessage if sent directly or if sent using
+ * StateMachine#sendMessage the message will just be ignored.
+ *
+ * @return A Message object from the global pool
*/
public final Message obtainMessage()
{
- if (mSmHandler == null) return null;
-
return Message.obtain(mSmHandler);
}
/**
- * Get a message and set Message.target = this and what
+ * Get a message and set Message.target state machine handler, what.
+ *
+ * Note: The handler can be null if the state machine has quit,
+ * which means target will be null and may cause a AndroidRuntimeException
+ * in MessageQueue#enqueMessage if sent directly or if sent using
+ * StateMachine#sendMessage the message will just be ignored.
*
* @param what is the assigned to Message.what.
- * @return message or null if SM has quit
+ * @return A Message object from the global pool
*/
public final Message obtainMessage(int what) {
- if (mSmHandler == null) return null;
-
return Message.obtain(mSmHandler, what);
}
/**
- * Get a message and set Message.target = this,
+ * Get a message and set Message.target state machine handler,
* what and obj.
*
+ * Note: The handler can be null if the state machine has quit,
+ * which means target will be null and may cause a AndroidRuntimeException
+ * in MessageQueue#enqueMessage if sent directly or if sent using
+ * StateMachine#sendMessage the message will just be ignored.
+ *
* @param what is the assigned to Message.what.
* @param obj is assigned to Message.obj.
- * @return message or null if SM has quit
+ * @return A Message object from the global pool
*/
public final Message obtainMessage(int what, Object obj)
{
- if (mSmHandler == null) return null;
-
return Message.obtain(mSmHandler, what, obj);
}
/**
- * Get a message and set Message.target = this,
+ * Get a message and set Message.target state machine handler,
* what, arg1 and arg2
*
+ * Note: The handler can be null if the state machine has quit,
+ * which means target will be null and may cause a AndroidRuntimeException
+ * in MessageQueue#enqueMessage if sent directly or if sent using
+ * StateMachine#sendMessage the message will just be ignored.
+ *
* @param what is assigned to Message.what
* @param arg1 is assigned to Message.arg1
* @param arg2 is assigned to Message.arg2
- * @return A Message object from the global pool or null if
- * SM has quit
+ * @return A Message object from the global pool
*/
public final Message obtainMessage(int what, int arg1, int arg2)
{
- if (mSmHandler == null) return null;
-
return Message.obtain(mSmHandler, what, arg1, arg2);
}
/**
- * Get a message and set Message.target = this,
+ * Get a message and set Message.target state machine handler,
* what, arg1, arg2 and obj
*
+ * Note: The handler can be null if the state machine has quit,
+ * which means target will be null and may cause a AndroidRuntimeException
+ * in MessageQueue#enqueMessage if sent directly or if sent using
+ * StateMachine#sendMessage the message will just be ignored.
+ *
* @param what is assigned to Message.what
* @param arg1 is assigned to Message.arg1
* @param arg2 is assigned to Message.arg2
* @param obj is assigned to Message.obj
- * @return A Message object from the global pool or null if
- * SM has quit
+ * @return A Message object from the global pool
*/
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
- if (mSmHandler == null) return null;
-
return Message.obtain(mSmHandler, what, arg1, arg2, obj);
}
/**
* Enqueue a message to this state machine.
+ *
+ * Message is ignored if state machine has quit.
*/
public final void sendMessage(int what) {
// mSmHandler can be null if the state machine has quit.
- if (mSmHandler == null) return;
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
- mSmHandler.sendMessage(obtainMessage(what));
+ smh.sendMessage(obtainMessage(what));
}
/**
* Enqueue a message to this state machine.
+ *
+ * Message is ignored if state machine has quit.
*/
public final void sendMessage(int what, Object obj) {
// mSmHandler can be null if the state machine has quit.
- if (mSmHandler == null) return;
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
- mSmHandler.sendMessage(obtainMessage(what,obj));
+ smh.sendMessage(obtainMessage(what,obj));
}
/**
* Enqueue a message to this state machine.
+ *
+ * Message is ignored if state machine has quit.
*/
public final void sendMessage(Message msg) {
// mSmHandler can be null if the state machine has quit.
- if (mSmHandler == null) return;
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
- mSmHandler.sendMessage(msg);
+ smh.sendMessage(msg);
}
/**
* Enqueue a message to this state machine after a delay.
+ *
+ * Message is ignored if state machine has quit.
*/
public final void sendMessageDelayed(int what, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
- if (mSmHandler == null) return;
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
- mSmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
+ smh.sendMessageDelayed(obtainMessage(what), delayMillis);
}
/**
* Enqueue a message to this state machine after a delay.
+ *
+ * Message is ignored if state machine has quit.
*/
public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
- if (mSmHandler == null) return;
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
- mSmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
+ smh.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
}
/**
* Enqueue a message to this state machine after a delay.
+ *
+ * Message is ignored if state machine has quit.
*/
public final void sendMessageDelayed(Message msg, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
- if (mSmHandler == null) return;
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
- mSmHandler.sendMessageDelayed(msg, delayMillis);
+ smh.sendMessageDelayed(msg, delayMillis);
}
/**
* Enqueue a message to the front of the queue for this state machine.
* Protected, may only be called by instances of StateMachine.
+ *
+ * Message is ignored if state machine has quit.
*/
protected final void sendMessageAtFrontOfQueue(int what, Object obj) {
- mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
+
+ smh.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
}
/**
* Enqueue a message to the front of the queue for this state machine.
* Protected, may only be called by instances of StateMachine.
+ *
+ * Message is ignored if state machine has quit.
*/
protected final void sendMessageAtFrontOfQueue(int what) {
- mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
+
+ smh.sendMessageAtFrontOfQueue(obtainMessage(what));
}
/**
* Enqueue a message to the front of the queue for this state machine.
* Protected, may only be called by instances of StateMachine.
+ *
+ * Message is ignored if state machine has quit.
*/
protected final void sendMessageAtFrontOfQueue(Message msg) {
- mSmHandler.sendMessageAtFrontOfQueue(msg);
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
+
+ smh.sendMessageAtFrontOfQueue(msg);
}
/**
* Protected, may only be called by instances of StateMachine.
*/
protected final void removeMessages(int what) {
- mSmHandler.removeMessages(what);
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
+
+ smh.removeMessages(what);
+ }
+
+ /**
+ * Validate that the message was sent by
+ * {@link StateMachine#quit} or {@link StateMachine#quitNow}.
+ * */
+ protected final boolean isQuit(Message msg) {
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return msg.what == SM_QUIT_CMD;
+
+ return smh.isQuit(msg);
}
/**
*/
protected final void quit() {
// mSmHandler can be null if the state machine is already stopped.
- if (mSmHandler == null) return;
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
- mSmHandler.quit();
+ smh.quit();
}
/**
*/
protected final void quitNow() {
// mSmHandler can be null if the state machine is already stopped.
- if (mSmHandler == null) return;
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
- mSmHandler.quitNow();
+ smh.quitNow();
}
/**
*/
public boolean isDbg() {
// mSmHandler can be null if the state machine has quit.
- if (mSmHandler == null) return false;
+ SmHandler smh = mSmHandler;
+ if (smh == null) return false;
- return mSmHandler.isDbg();
+ return smh.isDbg();
}
/**
*/
public void setDbg(boolean dbg) {
// mSmHandler can be null if the state machine has quit.
- if (mSmHandler == null) return;
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
- mSmHandler.setDbg(dbg);
+ smh.setDbg(dbg);
}
/**
*/
public void start() {
// mSmHandler can be null if the state machine has quit.
- if (mSmHandler == null) return;
+ SmHandler smh = mSmHandler;
+ if (smh == null) return;
/** Send the complete construction message */
- mSmHandler.completeConstruction();
+ smh.completeConstruction();
}
/**
pw.println(getName() + ":");
pw.println(" total records=" + getLogRecCount());
for (int i=0; i < getLogRecSize(); i++) {
- pw.printf(" rec[%d]: %s\n", i, getLogRec(i).toString(this));
+ pw.printf(" rec[%d]: %s\n", i, getLogRec(i).toString());
pw.flush();
}
pw.println("curState=" + getCurrentState().getName());
package com.android.internal.util;
+import java.util.Collection;
+import java.util.Iterator;
+
import android.os.Debug;
import android.os.HandlerThread;
import android.os.Looper;
}
}
+ private void dumpLogRecs(StateMachine sm) {
+ int size = sm.getLogRecSize();
+ tlog("size=" + size + " count=" + sm.getLogRecCount());
+ for (int i = 0; i < size; i++) {
+ LogRec lr = sm.getLogRec(i);
+ tlog(lr.toString());
+ }
+ }
+
+ private void dumpLogRecs(Collection<LogRec> clr) {
+ int size = clr.size();
+ tlog("size=" + size);
+ for (LogRec lr : clr) {
+ tlog(lr.toString());
+ }
+ }
+
/**
* Tests {@link StateMachine#quit()}.
*/
class StateMachineQuitTest extends StateMachine {
- Object mWaitUntilTestDone = new Object();
+ Collection<LogRec> mLogRecs;
StateMachineQuitTest(String name) {
super(name);
@Override
public void onQuitting() {
- Log.d(TAG, "onQuitting");
+ log("onQuitting");
addLogRec(ON_QUITTING);
+ mLogRecs = mThisSm.copyLogRecs();
synchronized (mThisSm) {
mThisSm.notifyAll();
}
-
- // Don't leave onQuitting before the test is done as everything is cleared
- // including the log records.
- synchronized (mWaitUntilTestDone) {
- try {
- mWaitUntilTestDone.wait();
- } catch(InterruptedException e) {
- }
- }
}
class S1 extends State {
+ @Override
public void exit() {
- Log.d(TAG, "S1.exit");
- addLogRec(EXIT, mS1);
+ log("S1.exit");
+ addLogRec(EXIT);
}
@Override
public boolean processMessage(Message message) {
switch(message.what) {
// Sleep and assume the other messages will be queued up.
case TEST_CMD_1: {
- Log.d(TAG, "TEST_CMD_1");
+ log("TEST_CMD_1");
sleep(500);
quit();
break;
}
default: {
- Log.d(TAG, "default what=" + message.what);
+ log("default what=" + message.what);
break;
}
}
StateMachineQuitTest smQuitTest = new StateMachineQuitTest("smQuitTest");
smQuitTest.start();
- if (smQuitTest.isDbg()) Log.d(TAG, "testStateMachineQuit E");
+ if (smQuitTest.isDbg()) tlog("testStateMachineQuit E");
synchronized (smQuitTest) {
// wait for the messages to be handled
smQuitTest.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachineQuit: exception while waiting " + e.getMessage());
+ tloge("testStateMachineQuit: exception while waiting " + e.getMessage());
}
}
- assertEquals(8, smQuitTest.getLogRecCount());
+ dumpLogRecs(smQuitTest.mLogRecs);
+ assertEquals(8, smQuitTest.mLogRecs.size());
LogRec lr;
-
- for (int i = 0; i < 6; i++) {
- lr = smQuitTest.getLogRec(i);
- assertEquals(i+1, lr.getWhat());
+ Iterator<LogRec> itr = smQuitTest.mLogRecs.iterator();
+ for (int i = 1; i <= 6; i++) {
+ lr = itr.next();
+ assertEquals(i, lr.getWhat());
assertEquals(smQuitTest.mS1, lr.getState());
assertEquals(smQuitTest.mS1, lr.getOriginalState());
}
- lr = smQuitTest.getLogRec(6);
+ lr = itr.next();
assertEquals(EXIT, lr.getInfo());
assertEquals(smQuitTest.mS1, lr.getState());
- lr = smQuitTest.getLogRec(7);
+ lr = itr.next();
assertEquals(ON_QUITTING, lr.getInfo());
- synchronized (smQuitTest.mWaitUntilTestDone) {
- smQuitTest.mWaitUntilTestDone.notifyAll();
- }
- if (smQuitTest.isDbg()) Log.d(TAG, "testStateMachineQuit X");
+ if (smQuitTest.isDbg()) tlog("testStateMachineQuit X");
}
/**
* Tests {@link StateMachine#quitNow()}
*/
class StateMachineQuitNowTest extends StateMachine {
- Object mWaitUntilTestDone = new Object();
+ public Collection<LogRec> mLogRecs = null;
StateMachineQuitNowTest(String name) {
super(name);
@Override
public void onQuitting() {
- Log.d(TAG, "onQuitting");
+ log("onQuitting");
addLogRec(ON_QUITTING);
+ // Get a copy of the log records since we're quitting and they will disappear
+ mLogRecs = mThisSm.copyLogRecs();
+
synchronized (mThisSm) {
mThisSm.notifyAll();
}
-
- // Don't leave onQuitting before the test is done as everything is cleared
- // including the log records.
- synchronized (mWaitUntilTestDone) {
- try {
- mWaitUntilTestDone.wait();
- } catch(InterruptedException e) {
- }
- }
}
class S1 extends State {
+ @Override
public void exit() {
- Log.d(TAG, "S1.exit");
- addLogRec(EXIT, mS1);
+ log("S1.exit");
+ addLogRec(EXIT);
}
@Override
public boolean processMessage(Message message) {
switch(message.what) {
// Sleep and assume the other messages will be queued up.
case TEST_CMD_1: {
- Log.d(TAG, "TEST_CMD_1");
+ log("TEST_CMD_1");
sleep(500);
quitNow();
break;
}
default: {
- Log.d(TAG, "default what=" + message.what);
+ log("default what=" + message.what);
break;
}
}
StateMachineQuitNowTest smQuitNowTest = new StateMachineQuitNowTest("smQuitNowTest");
smQuitNowTest.start();
- if (smQuitNowTest.isDbg()) Log.d(TAG, "testStateMachineQuitNow E");
+ if (smQuitNowTest.isDbg()) tlog("testStateMachineQuitNow E");
synchronized (smQuitNowTest) {
- // Send 6 messages but we'll QuitNow on the first so even though
+ // Send 6 message we'll QuitNow on the first even though
// we send 6 only one will be processed.
for (int i = 1; i <= 6; i++) {
smQuitNowTest.sendMessage(smQuitNowTest.obtainMessage(i));
// wait for the messages to be handled
smQuitNowTest.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachineQuitNow: exception while waiting " + e.getMessage());
+ tloge("testStateMachineQuitNow: exception while waiting " + e.getMessage());
}
}
- // Only three records because we executed quitNow.
- assertEquals(3, smQuitNowTest.getLogRecCount());
+ tlog("testStateMachineQuiteNow: logRecs=" + smQuitNowTest.mLogRecs);
+ assertEquals(3, smQuitNowTest.mLogRecs.size());
- LogRec lr;
-
- lr = smQuitNowTest.getLogRec(0);
+ Iterator<LogRec> itr = smQuitNowTest.mLogRecs.iterator();
+ LogRec lr = itr.next();
assertEquals(1, lr.getWhat());
assertEquals(smQuitNowTest.mS1, lr.getState());
assertEquals(smQuitNowTest.mS1, lr.getOriginalState());
- lr = smQuitNowTest.getLogRec(1);
+ lr = itr.next();
assertEquals(EXIT, lr.getInfo());
assertEquals(smQuitNowTest.mS1, lr.getState());
- lr = smQuitNowTest.getLogRec(2);
+ lr = itr.next();
assertEquals(ON_QUITTING, lr.getInfo());
- synchronized (smQuitNowTest.mWaitUntilTestDone) {
- smQuitNowTest.mWaitUntilTestDone.notifyAll();
- }
- if (smQuitNowTest.isDbg()) Log.d(TAG, "testStateMachineQuitNow X");
+ if (smQuitNowTest.isDbg()) tlog("testStateMachineQuitNow X");
}
/**
@Override
public void enter() {
// Test transitions in enter on the initial state work
- addLogRec(ENTER, mS1);
+ addLogRec(ENTER);
transitionTo(mS2);
- Log.d(TAG, "S1.enter");
+ log("S1.enter");
}
@Override
public void exit() {
- // Test that message is HSM_INIT_CMD
- addLogRec(EXIT, mS1);
- Log.d(TAG, "S1.exit");
+ addLogRec(EXIT);
+ log("S1.exit");
}
}
class S2 extends State {
@Override
public void enter() {
- addLogRec(ENTER, mS2);
- Log.d(TAG, "S2.enter");
+ addLogRec(ENTER);
+ log("S2.enter");
}
@Override
public void exit() {
- addLogRec(EXIT, mS2);
- assertEquals(TEST_CMD_1, getCurrentMessage().what);
-
// Test transition in exit work
transitionTo(mS4);
- Log.d(TAG, "S2.exit");
+
+ assertEquals(TEST_CMD_1, getCurrentMessage().what);
+ addLogRec(EXIT);
+
+ log("S2.exit");
}
@Override
public boolean processMessage(Message message) {
// Start a transition to S3 but it will be
// changed to a transition to S4 in exit
transitionTo(mS3);
- Log.d(TAG, "S2.processMessage");
+ log("S2.processMessage");
return HANDLED;
}
}
class S3 extends State {
@Override
public void enter() {
- addLogRec(ENTER, mS3);
- Log.d(TAG, "S3.enter");
+ addLogRec(ENTER);
+ log("S3.enter");
}
@Override
public void exit() {
- addLogRec(EXIT, mS3);
- Log.d(TAG, "S3.exit");
+ addLogRec(EXIT);
+ log("S3.exit");
}
}
class S4 extends State {
@Override
public void enter() {
- addLogRec(ENTER, mS4);
+ addLogRec(ENTER);
// Test that we can do halting in an enter/exit
transitionToHaltingState();
- Log.d(TAG, "S4.enter");
+ log("S4.enter");
}
@Override
public void exit() {
- addLogRec(EXIT, mS4);
- Log.d(TAG, "S4.exit");
+ addLogRec(EXIT);
+ log("S4.exit");
}
}
new StateMachineEnterExitTransitionToTest("smEnterExitTranstionToTest");
smEnterExitTranstionToTest.start();
if (smEnterExitTranstionToTest.isDbg()) {
- Log.d(TAG, "testStateMachineEnterExitTransitionToTest E");
+ tlog("testStateMachineEnterExitTransitionToTest E");
}
synchronized (smEnterExitTranstionToTest) {
// wait for the messages to be handled
smEnterExitTranstionToTest.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachineEnterExitTransitionToTest: exception while waiting "
+ tloge("testStateMachineEnterExitTransitionToTest: exception while waiting "
+ e.getMessage());
}
}
- assertEquals(smEnterExitTranstionToTest.getLogRecCount(), 9);
+ dumpLogRecs(smEnterExitTranstionToTest);
+ assertEquals(9, smEnterExitTranstionToTest.getLogRecCount());
LogRec lr;
lr = smEnterExitTranstionToTest.getLogRec(0);
assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
assertEquals(smEnterExitTranstionToTest.mS2, lr.getOriginalState());
+ assertEquals(smEnterExitTranstionToTest.mS3, lr.getDestState());
lr = smEnterExitTranstionToTest.getLogRec(4);
- assertEquals(EXIT, lr.getInfo());
+ assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(smEnterExitTranstionToTest.mS2, lr.getState());
+ assertEquals(smEnterExitTranstionToTest.mS2, lr.getOriginalState());
+ assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
+ assertEquals(EXIT, lr.getInfo());
lr = smEnterExitTranstionToTest.getLogRec(5);
+ assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(ENTER, lr.getInfo());
assertEquals(smEnterExitTranstionToTest.mS3, lr.getState());
+ assertEquals(smEnterExitTranstionToTest.mS3, lr.getOriginalState());
+ assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
lr = smEnterExitTranstionToTest.getLogRec(6);
+ assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(EXIT, lr.getInfo());
assertEquals(smEnterExitTranstionToTest.mS3, lr.getState());
+ assertEquals(smEnterExitTranstionToTest.mS3, lr.getOriginalState());
+ assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
lr = smEnterExitTranstionToTest.getLogRec(7);
+ assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(ENTER, lr.getInfo());
assertEquals(smEnterExitTranstionToTest.mS4, lr.getState());
+ assertEquals(smEnterExitTranstionToTest.mS4, lr.getOriginalState());
+ assertEquals(smEnterExitTranstionToTest.mS4, lr.getDestState());
lr = smEnterExitTranstionToTest.getLogRec(8);
+ assertEquals(TEST_CMD_1, lr.getWhat());
assertEquals(EXIT, lr.getInfo());
assertEquals(smEnterExitTranstionToTest.mS4, lr.getState());
+ assertEquals(smEnterExitTranstionToTest.mS4, lr.getOriginalState());
if (smEnterExitTranstionToTest.isDbg()) {
- Log.d(TAG, "testStateMachineEnterExitTransitionToTest X");
+ tlog("testStateMachineEnterExitTransitionToTest X");
}
}
StateMachine0 sm0 = new StateMachine0("sm0");
sm0.start();
- if (sm0.isDbg()) Log.d(TAG, "testStateMachine0 E");
+ if (sm0.isDbg()) tlog("testStateMachine0 E");
synchronized (sm0) {
// Send 6 messages
// wait for the messages to be handled
sm0.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachine0: exception while waiting " + e.getMessage());
+ tloge("testStateMachine0: exception while waiting " + e.getMessage());
}
}
assertEquals(6, sm0.getLogRecCount());
assertEquals(3, sm0.getLogRecSize());
+ dumpLogRecs(sm0);
+
LogRec lr;
lr = sm0.getLogRec(0);
assertEquals(TEST_CMD_4, lr.getWhat());
assertEquals(sm0.mS1, lr.getState());
assertEquals(sm0.mS1, lr.getOriginalState());
- if (sm0.isDbg()) Log.d(TAG, "testStateMachine0 X");
+ if (sm0.isDbg()) tlog("testStateMachine0 X");
}
/**
// Set the initial state
setInitialState(mS1);
- if (DBG) Log.d(TAG, "StateMachine1: ctor X");
+ if (DBG) log("StateMachine1: ctor X");
}
class S1 extends State {
public void testStateMachine1() throws Exception {
StateMachine1 sm1 = new StateMachine1("sm1");
sm1.start();
- if (sm1.isDbg()) Log.d(TAG, "testStateMachine1 E");
+ if (sm1.isDbg()) tlog("testStateMachine1 E");
synchronized (sm1) {
// Send two messages
// wait for the messages to be handled
sm1.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachine1: exception while waiting " + e.getMessage());
+ tloge("testStateMachine1: exception while waiting " + e.getMessage());
}
}
assertEquals(2, sm1.mEnterCount);
assertEquals(2, sm1.mExitCount);
- if (sm1.isDbg()) Log.d(TAG, "testStateMachine1 X");
+ if (sm1.isDbg()) tlog("testStateMachine1 X");
}
/**
// Set the initial state
setInitialState(mS1);
- if (DBG) Log.d(TAG, "StateMachine2: ctor X");
+ if (DBG) log("StateMachine2: ctor X");
}
class S1 extends State {
public void testStateMachine2() throws Exception {
StateMachine2 sm2 = new StateMachine2("sm2");
sm2.start();
- if (sm2.isDbg()) Log.d(TAG, "testStateMachine2 E");
+ if (sm2.isDbg()) tlog("testStateMachine2 E");
synchronized (sm2) {
// Send two messages
// wait for the messages to be handled
sm2.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachine2: exception while waiting " + e.getMessage());
+ tloge("testStateMachine2: exception while waiting " + e.getMessage());
}
}
assertTrue(sm2.mDidEnter);
assertTrue(sm2.mDidExit);
- if (sm2.isDbg()) Log.d(TAG, "testStateMachine2 X");
+ if (sm2.isDbg()) tlog("testStateMachine2 X");
}
/**
// Set the initial state will be the child
setInitialState(mChildState);
- if (DBG) Log.d(TAG, "StateMachine3: ctor X");
+ if (DBG) log("StateMachine3: ctor X");
}
class ParentState extends State {
public void testStateMachine3() throws Exception {
StateMachine3 sm3 = new StateMachine3("sm3");
sm3.start();
- if (sm3.isDbg()) Log.d(TAG, "testStateMachine3 E");
+ if (sm3.isDbg()) tlog("testStateMachine3 E");
synchronized (sm3) {
// Send two messages
// wait for the messages to be handled
sm3.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachine3: exception while waiting " + e.getMessage());
+ tloge("testStateMachine3: exception while waiting " + e.getMessage());
}
}
assertEquals(sm3.mParentState, lr.getState());
assertEquals(sm3.mChildState, lr.getOriginalState());
- if (sm3.isDbg()) Log.d(TAG, "testStateMachine3 X");
+ if (sm3.isDbg()) tlog("testStateMachine3 X");
}
/**
// Set the initial state will be child 1
setInitialState(mChildState1);
- if (DBG) Log.d(TAG, "StateMachine4: ctor X");
+ if (DBG) log("StateMachine4: ctor X");
}
class ParentState extends State {
public void testStateMachine4() throws Exception {
StateMachine4 sm4 = new StateMachine4("sm4");
sm4.start();
- if (sm4.isDbg()) Log.d(TAG, "testStateMachine4 E");
+ if (sm4.isDbg()) tlog("testStateMachine4 E");
synchronized (sm4) {
// Send two messages
// wait for the messages to be handled
sm4.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachine4: exception while waiting " + e.getMessage());
+ tloge("testStateMachine4: exception while waiting " + e.getMessage());
}
}
assertEquals(sm4.mParentState, lr.getState());
assertEquals(sm4.mChildState2, lr.getOriginalState());
- if (sm4.isDbg()) Log.d(TAG, "testStateMachine4 X");
+ if (sm4.isDbg()) tlog("testStateMachine4 X");
}
/**
// Set the initial state will be the child
setInitialState(mChildState1);
- if (DBG) Log.d(TAG, "StateMachine5: ctor X");
+ if (DBG) log("StateMachine5: ctor X");
}
class ParentState1 extends State {
public void testStateMachine5() throws Exception {
StateMachine5 sm5 = new StateMachine5("sm5");
sm5.start();
- if (sm5.isDbg()) Log.d(TAG, "testStateMachine5 E");
+ if (sm5.isDbg()) tlog("testStateMachine5 E");
synchronized (sm5) {
// Send 6 messages
// wait for the messages to be handled
sm5.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachine5: exception while waiting " + e.getMessage());
+ tloge("testStateMachine5: exception while waiting " + e.getMessage());
}
}
assertEquals(sm5.mParentState2, lr.getState());
assertEquals(sm5.mParentState2, lr.getOriginalState());
- if (sm5.isDbg()) Log.d(TAG, "testStateMachine5 X");
+ if (sm5.isDbg()) tlog("testStateMachine5 X");
}
/**
// Set the initial state
setInitialState(mS1);
- if (DBG) Log.d(TAG, "StateMachine6: ctor X");
+ if (DBG) log("StateMachine6: ctor X");
}
class S1 extends State {
StateMachine6 sm6 = new StateMachine6("sm6");
sm6.start();
- if (sm6.isDbg()) Log.d(TAG, "testStateMachine6 E");
+ if (sm6.isDbg()) tlog("testStateMachine6 E");
synchronized (sm6) {
// Send a message
// wait for the messages to be handled
sm6.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachine6: exception while waiting " + e.getMessage());
+ tloge("testStateMachine6: exception while waiting " + e.getMessage());
}
}
*/
long arrivalTimeDiff = sm6.mArrivalTimeMsg2 - sm6.mArrivalTimeMsg1;
long expectedDelay = DELAY_TIME - DELAY_FUDGE;
- if (sm6.isDbg()) Log.d(TAG, "testStateMachine6: expect " + arrivalTimeDiff
+ if (sm6.isDbg()) tlog("testStateMachine6: expect " + arrivalTimeDiff
+ " >= " + expectedDelay);
assertTrue(arrivalTimeDiff >= expectedDelay);
- if (sm6.isDbg()) Log.d(TAG, "testStateMachine6 X");
+ if (sm6.isDbg()) tlog("testStateMachine6 X");
}
/**
// Set the initial state
setInitialState(mS1);
- if (DBG) Log.d(TAG, "StateMachine7: ctor X");
+ if (DBG) log("StateMachine7: ctor X");
}
class S1 extends State {
StateMachine7 sm7 = new StateMachine7("sm7");
sm7.start();
- if (sm7.isDbg()) Log.d(TAG, "testStateMachine7 E");
+ if (sm7.isDbg()) tlog("testStateMachine7 E");
synchronized (sm7) {
// Send a message
// wait for the messages to be handled
sm7.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachine7: exception while waiting " + e.getMessage());
+ tloge("testStateMachine7: exception while waiting " + e.getMessage());
}
}
*/
long arrivalTimeDiff = sm7.mArrivalTimeMsg3 - sm7.mArrivalTimeMsg2;
long expectedDelay = sm7.SM7_DELAY_TIME - SM7_DELAY_FUDGE;
- if (sm7.isDbg()) Log.d(TAG, "testStateMachine7: expect " + arrivalTimeDiff
+ if (sm7.isDbg()) tlog("testStateMachine7: expect " + arrivalTimeDiff
+ " >= " + expectedDelay);
assertTrue(arrivalTimeDiff >= expectedDelay);
- if (sm7.isDbg()) Log.d(TAG, "testStateMachine7 X");
+ if (sm7.isDbg()) tlog("testStateMachine7 X");
}
/**
@SmallTest
public void testStateMachineUnhandledMessage() throws Exception {
- StateMachineUnhandledMessage sm = new StateMachineUnhandledMessage("sm");
+ StateMachineUnhandledMessage sm = new StateMachineUnhandledMessage("smUnhandledMessage");
sm.start();
- if (sm.isDbg()) Log.d(TAG, "testStateMachineUnhandledMessage E");
+ if (sm.isDbg()) tlog("testStateMachineUnhandledMessage E");
synchronized (sm) {
// Send 2 messages
// wait for the messages to be handled
sm.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachineUnhandledMessage: exception while waiting "
+ tloge("testStateMachineUnhandledMessage: exception while waiting "
+ e.getMessage());
}
}
- assertEquals(sm.getLogRecCount(), 2);
+ assertEquals(2, sm.getLogRecSize());
assertEquals(2, sm.mUnhandledMessageCount);
- if (sm.isDbg()) Log.d(TAG, "testStateMachineUnhandledMessage X");
+ if (sm.isDbg()) tlog("testStateMachineUnhandledMessage X");
}
/**
@MediumTest
public void testStateMachineSharedThread() throws Exception {
- if (DBG) Log.d(TAG, "testStateMachineSharedThread E");
+ if (DBG) tlog("testStateMachineSharedThread E");
// Create and start the handler thread
HandlerThread smThread = new HandlerThread("testStateMachineSharedThread");
// Create the state machines
StateMachineSharedThread sms[] = new StateMachineSharedThread[10];
for (int i = 0; i < sms.length; i++) {
- sms[i] = new StateMachineSharedThread("sm", smThread.getLooper(), sms.length);
+ sms[i] = new StateMachineSharedThread("smSharedThread",
+ smThread.getLooper(), sms.length);
sms[i].start();
}
try {
waitObject.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testStateMachineSharedThread: exception while waiting "
+ tloge("testStateMachineSharedThread: exception while waiting "
+ e.getMessage());
}
}
for (StateMachineSharedThread sm : sms) {
- assertEquals(sm.getLogRecCount(), 4);
- for (int i = 0; i < sm.getLogRecCount(); i++) {
+ assertEquals(4, sm.getLogRecCount());
+ for (int i = 0; i < sm.getLogRecSize(); i++) {
LogRec lr = sm.getLogRec(i);
assertEquals(i+1, lr.getWhat());
assertEquals(sm.mS1, lr.getState());
}
}
- if (DBG) Log.d(TAG, "testStateMachineSharedThread X");
+ if (DBG) tlog("testStateMachineSharedThread X");
+ }
+
+ static class Hsm1 extends StateMachine {
+ private static final String HSM1_TAG = "hsm1";
+
+ public static final int CMD_1 = 1;
+ public static final int CMD_2 = 2;
+ public static final int CMD_3 = 3;
+ public static final int CMD_4 = 4;
+ public static final int CMD_5 = 5;
+
+ public static Hsm1 makeHsm1() {
+ Log.d(HSM1_TAG, "makeHsm1 E");
+ Hsm1 sm = new Hsm1(HSM1_TAG);
+ sm.start();
+ Log.d(HSM1_TAG, "makeHsm1 X");
+ return sm;
+ }
+
+ Hsm1(String name) {
+ super(name);
+ log("ctor E");
+
+ // Add states, use indentation to show hierarchy
+ addState(mP1);
+ addState(mS1, mP1);
+ addState(mS2, mP1);
+ addState(mP2);
+
+ // Set the initial state
+ setInitialState(mS1);
+ log("ctor X");
+ }
+
+ class P1 extends State {
+ @Override
+ public void enter() {
+ log("P1.enter");
+ }
+ @Override
+ public void exit() {
+ log("P1.exit");
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retVal;
+ log("P1.processMessage what=" + message.what);
+ switch(message.what) {
+ case CMD_2:
+ // CMD_2 will arrive in mS2 before CMD_3
+ sendMessage(CMD_3);
+ deferMessage(message);
+ transitionTo(mS2);
+ retVal = true;
+ break;
+ default:
+ // Any message we don't understand in this state invokes unhandledMessage
+ retVal = false;
+ break;
+ }
+ return retVal;
+ }
+ }
+
+ class S1 extends State {
+ @Override
+ public void enter() {
+ log("S1.enter");
+ }
+ @Override
+ public void exit() {
+ log("S1.exit");
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ log("S1.processMessage what=" + message.what);
+ if (message.what == CMD_1) {
+ // Transition to ourself to show that enter/exit is called
+ transitionTo(mS1);
+ return HANDLED;
+ } else {
+ // Let parent process all other messages
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ class S2 extends State {
+ @Override
+ public void enter() {
+ log("S2.enter");
+ }
+ @Override
+ public void exit() {
+ log("S2.exit");
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retVal;
+ log("S2.processMessage what=" + message.what);
+ switch(message.what) {
+ case(CMD_2):
+ sendMessage(CMD_4);
+ retVal = true;
+ break;
+ case(CMD_3):
+ deferMessage(message);
+ transitionTo(mP2);
+ retVal = true;
+ break;
+ default:
+ retVal = false;
+ break;
+ }
+ return retVal;
+ }
+ }
+
+ class P2 extends State {
+ @Override
+ public void enter() {
+ log("P2.enter");
+ sendMessage(CMD_5);
+ }
+ @Override
+ public void exit() {
+ log("P2.exit");
+ }
+ @Override
+ public boolean processMessage(Message message) {
+ log("P2.processMessage what=" + message.what);
+ switch(message.what) {
+ case(CMD_3):
+ break;
+ case(CMD_4):
+ break;
+ case(CMD_5):
+ transitionToHaltingState();
+ break;
+ }
+ return HANDLED;
+ }
+ }
+
+ @Override
+ protected void onHalting() {
+ log("halting");
+ synchronized (this) {
+ this.notifyAll();
+ }
+ }
+
+ P1 mP1 = new P1();
+ S1 mS1 = new S1();
+ S2 mS2 = new S2();
+ P2 mP2 = new P2();
}
@MediumTest
public void testHsm1() throws Exception {
- if (DBG) Log.d(TAG, "testHsm1 E");
+ if (DBG) tlog("testHsm1 E");
Hsm1 sm = Hsm1.makeHsm1();
try {
sm.wait();
} catch (InterruptedException e) {
- Log.e(TAG, "testHsm1: exception while waiting " + e.getMessage());
+ tloge("testHsm1: exception while waiting " + e.getMessage());
}
}
+ dumpLogRecs(sm);
+
assertEquals(7, sm.getLogRecCount());
+
LogRec lr = sm.getLogRec(0);
assertEquals(Hsm1.CMD_1, lr.getWhat());
assertEquals(sm.mS1, lr.getState());
assertEquals(sm.mP2, lr.getState());
assertEquals(sm.mP2, lr.getOriginalState());
- if (DBG) Log.d(TAG, "testStateMachineSharedThread X");
- }
-}
-
-class Hsm1 extends StateMachine {
- private static final String TAG = "hsm1";
-
- public static final int CMD_1 = 1;
- public static final int CMD_2 = 2;
- public static final int CMD_3 = 3;
- public static final int CMD_4 = 4;
- public static final int CMD_5 = 5;
-
- public static Hsm1 makeHsm1() {
- Log.d(TAG, "makeHsm1 E");
- Hsm1 sm = new Hsm1("hsm1");
- sm.start();
- Log.d(TAG, "makeHsm1 X");
- return sm;
- }
-
- Hsm1(String name) {
- super(name);
- Log.d(TAG, "ctor E");
-
- // Add states, use indentation to show hierarchy
- addState(mP1);
- addState(mS1, mP1);
- addState(mS2, mP1);
- addState(mP2);
-
- // Set the initial state
- setInitialState(mS1);
- Log.d(TAG, "ctor X");
- }
-
- class P1 extends State {
- @Override
- public void enter() {
- Log.d(TAG, "P1.enter");
- }
- @Override
- public void exit() {
- Log.d(TAG, "P1.exit");
- }
- @Override
- public boolean processMessage(Message message) {
- boolean retVal;
- Log.d(TAG, "P1.processMessage what=" + message.what);
- switch(message.what) {
- case CMD_2:
- // CMD_2 will arrive in mS2 before CMD_3
- sendMessage(CMD_3);
- deferMessage(message);
- transitionTo(mS2);
- retVal = true;
- break;
- default:
- // Any message we don't understand in this state invokes unhandledMessage
- retVal = false;
- break;
- }
- return retVal;
- }
+ if (DBG) tlog("testStateMachineSharedThread X");
}
- class S1 extends State {
- @Override
- public void enter() {
- Log.d(TAG, "S1.enter");
- }
- @Override
- public void exit() {
- Log.d(TAG, "S1.exit");
- }
- @Override
- public boolean processMessage(Message message) {
- Log.d(TAG, "S1.processMessage what=" + message.what);
- if (message.what == CMD_1) {
- // Transition to ourself to show that enter/exit is called
- transitionTo(mS1);
- return HANDLED;
- } else {
- // Let parent process all other messages
- return NOT_HANDLED;
- }
- }
+ private void tlog(String s) {
+ Log.d(TAG, s);
}
- class S2 extends State {
- @Override
- public void enter() {
- Log.d(TAG, "S2.enter");
- }
- @Override
- public void exit() {
- Log.d(TAG, "S2.exit");
- }
- @Override
- public boolean processMessage(Message message) {
- boolean retVal;
- Log.d(TAG, "S2.processMessage what=" + message.what);
- switch(message.what) {
- case(CMD_2):
- sendMessage(CMD_4);
- retVal = true;
- break;
- case(CMD_3):
- deferMessage(message);
- transitionTo(mP2);
- retVal = true;
- break;
- default:
- retVal = false;
- break;
- }
- return retVal;
- }
- }
-
- class P2 extends State {
- @Override
- public void enter() {
- Log.d(TAG, "P2.enter");
- sendMessage(CMD_5);
- }
- @Override
- public void exit() {
- Log.d(TAG, "P2.exit");
- }
- @Override
- public boolean processMessage(Message message) {
- Log.d(TAG, "P2.processMessage what=" + message.what);
- switch(message.what) {
- case(CMD_3):
- break;
- case(CMD_4):
- break;
- case(CMD_5):
- transitionToHaltingState();
- break;
- }
- return HANDLED;
- }
+ private void tloge(String s) {
+ Log.e(TAG, s);
}
-
- @Override
- protected void onHalting() {
- Log.d(TAG, "halting");
- synchronized (this) {
- this.notifyAll();
- }
- }
-
- P1 mP1 = new P1();
- S1 mS1 = new S1();
- S2 mS2 = new S2();
- P2 mP2 = new P2();
}