FileDocCategorySizeDatePackage
StateMachine.javaAPI DocAndroid 5.1 API68450Thu Mar 12 22:22:10 GMT 2015com.android.internal.util

StateMachine

public class StateMachine extends Object
{@hide}

The state machine defined here is a hierarchical state machine which processes messages and can have states arranged hierarchically.

A state is a State object and must implement processMessage and optionally enter/exit/getName. The enter/exit methods are equivalent to the construction and destruction in Object Oriented programming and are used to perform initialization and cleanup of the state respectively. The getName method returns the name of the state the default implementation returns the class name it may be desirable to have this return the name of the state instance name instead. In particular if a particular state class has multiple instances.

When a state machine is created addState is used to build the hierarchy and setInitialState is used to identify which of these is the initial state. After construction the programmer calls start which initializes and starts the state machine. The first action the StateMachine is to the invoke enter for all of the initial state's hierarchy, starting at its eldest parent. The calls to enter will be done in the context of the StateMachines Handler not in the context of the call to start and they will be invoked before any messages are processed. For example, given the simple state machine below mP1.enter will be invoked and then mS1.enter. Finally, messages sent to the state machine will be processed by the current state, in our simple state machine below that would initially be mS1.processMessage.

mP1 / \ mS2 mS1 ----> initial state

After the state machine is created and started, messages are sent to a state machine using sendMessage and the messages are created using obtainMessage. When the state machine receives a message the current state's processMessage is invoked. In the above example mS1.processMessage will be invoked first. The state may use transitionTo to change the current state to a new state

Each state in the state machine may have a zero or one parent states and if a child state is unable to handle a message it may have the message processed by its parent by returning false or NOT_HANDLED. If a message is never processed unhandledMessage will be invoked to give one last chance for the state machine to process the message.

When all processing is completed a state machine may choose to call transitionToHaltingState. When the current processingMessage returns the state machine will transfer to an internal HaltingState and invoke halting. Any message subsequently received by the state machine will cause haltedProcessMessage to be invoked.

If it is desirable to completely stop the state machine call quit or quitNow. These will call exit of the current state and its parents, call onQuiting and then exit Thread/Loopers.

In addition to processMessage each State has an enter method and exit method which may be overridden.

Since the states are arranged in a hierarchy transitioning to a new state causes current states to be exited and new states to be entered. To determine the list of states to be entered/exited the common parent closest to the current state is found. We then exit from the current state and its parent's up to but not including the common parent state and then enter all of the new states below the common parent down to the destination state. If there is no common parent all states are exited and then the new states are entered.

Two other methods that states can use are deferMessage and sendMessageAtFrontOfQueue. The sendMessageAtFrontOfQueue sends a message but places it on the front of the queue rather than the back. The deferMessage causes the message to be saved on a list until a transition is made to a new state. At which time all of the deferred messages will be put on the front of the state machine queue with the oldest message at the front. These will then be processed by the new current state before any other messages that are on the queue or might be added later. Both of these are protected and may only be invoked from within a state machine.

To illustrate some of these properties we'll use state machine with an 8 state hierarchy:

mP0 / \ mP1 mS0 / \ mS2 mS1 / \ \ mS3 mS4 mS5 ---> initial state

After starting mS5 the list of active states is mP0, mP1, mS1 and mS5. So the order of calling processMessage when a message is received is mS5, mS1, mP1, mP0 assuming each processMessage indicates it can't handle this message by returning false or NOT_HANDLED.

Now assume mS5.processMessage receives a message it can handle, and during the handling determines the machine should change states. It could call transitionTo(mS4) and return true or HANDLED. Immediately after returning from processMessage the state machine runtime will find the common parent, which is mP1. It will then call mS5.exit, mS1.exit, mS2.enter and then mS4.enter. The new list of active states is mP0, mP1, mS2 and mS4. So when the next message is received mS4.processMessage will be invoked.

Now for some concrete examples, here is the canonical HelloWorld as a state machine. It responds with "Hello World" being printed to the log for every message.

class HelloWorld extends StateMachine { HelloWorld(String name) { super(name); addState(mState1); setInitialState(mState1); } public static HelloWorld makeHelloWorld() { HelloWorld hw = new HelloWorld("hw"); hw.start(); return hw; } class State1 extends State { @Override public boolean processMessage(Message message) { log("Hello World"); return HANDLED; } } State1 mState1 = new State1(); } void testHelloWorld() { HelloWorld hw = makeHelloWorld(); hw.sendMessage(hw.obtainMessage()); }

A more interesting state machine is one with four states with two independent parent states.

mP1 mP2 / \ mS2 mS1

Here is a description of this state machine using pseudo code.

state mP1 { enter { log("mP1.enter"); } exit { log("mP1.exit"); } on msg { CMD_2 { send(CMD_3); defer(msg); transitonTo(mS2); return HANDLED; } return NOT_HANDLED; } } INITIAL state mS1 parent mP1 { enter { log("mS1.enter"); } exit { log("mS1.exit"); } on msg { CMD_1 { transitionTo(mS1); return HANDLED; } return NOT_HANDLED; } } state mS2 parent mP1 { enter { log("mS2.enter"); } exit { log("mS2.exit"); } on msg { CMD_2 { send(CMD_4); return HANDLED; } CMD_3 { defer(msg); transitionTo(mP2); return HANDLED; } return NOT_HANDLED; } } state mP2 { enter { log("mP2.enter"); send(CMD_5); } exit { log("mP2.exit"); } on msg { CMD_3, CMD_4 { return HANDLED; } CMD_5 { transitionTo(HaltingState); return HANDLED; } return NOT_HANDLED; } }

The implementation is below and also in StateMachineTest:

class Hsm1 extends StateMachine { 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("makeHsm1 E"); Hsm1 sm = new Hsm1("hsm1"); sm.start(); log("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("mP1.enter"); } @Override public boolean processMessage(Message message) { boolean retVal; log("mP1.processMessage what=" + message.what); switch(message.what) { case CMD_2: // CMD_2 will arrive in mS2 before CMD_3 sendMessage(obtainMessage(CMD_3)); deferMessage(message); transitionTo(mS2); retVal = HANDLED; break; default: // Any message we don't understand in this state invokes unhandledMessage retVal = NOT_HANDLED; break; } return retVal; } @Override public void exit() { log("mP1.exit"); } } class S1 extends State { @Override public void enter() { log("mS1.enter"); } @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; } } @Override public void exit() { log("mS1.exit"); } } class S2 extends State { @Override public void enter() { log("mS2.enter"); } @Override public boolean processMessage(Message message) { boolean retVal; log("mS2.processMessage what=" + message.what); switch(message.what) { case(CMD_2): sendMessage(obtainMessage(CMD_4)); retVal = HANDLED; break; case(CMD_3): deferMessage(message); transitionTo(mP2); retVal = HANDLED; break; default: retVal = NOT_HANDLED; break; } return retVal; } @Override public void exit() { log("mS2.exit"); } } class P2 extends State { @Override public void enter() { log("mP2.enter"); sendMessage(obtainMessage(CMD_5)); } @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 public void exit() { log("mP2.exit"); } } @Override void onHalting() { log("halting"); synchronized (this) { this.notifyAll(); } } P1 mP1 = new P1(); S1 mS1 = new S1(); S2 mS2 = new S2(); P2 mP2 = new P2(); }

If this is executed by sending two messages CMD_1 and CMD_2 (Note the synchronize is only needed because we use hsm.wait())

Hsm1 hsm = makeHsm1(); synchronize(hsm) { hsm.sendMessage(obtainMessage(hsm.CMD_1)); hsm.sendMessage(obtainMessage(hsm.CMD_2)); try { // wait for the messages to be handled hsm.wait(); } catch (InterruptedException e) { loge("exception while waiting " + e.getMessage()); } }

The output is:

D/hsm1 ( 1999): makeHsm1 E D/hsm1 ( 1999): ctor E D/hsm1 ( 1999): ctor X D/hsm1 ( 1999): mP1.enter D/hsm1 ( 1999): mS1.enter D/hsm1 ( 1999): makeHsm1 X D/hsm1 ( 1999): mS1.processMessage what=1 D/hsm1 ( 1999): mS1.exit D/hsm1 ( 1999): mS1.enter D/hsm1 ( 1999): mS1.processMessage what=2 D/hsm1 ( 1999): mP1.processMessage what=2 D/hsm1 ( 1999): mS1.exit D/hsm1 ( 1999): mS2.enter D/hsm1 ( 1999): mS2.processMessage what=2 D/hsm1 ( 1999): mS2.processMessage what=3 D/hsm1 ( 1999): mS2.exit D/hsm1 ( 1999): mP1.exit D/hsm1 ( 1999): mP2.enter D/hsm1 ( 1999): mP2.processMessage what=3 D/hsm1 ( 1999): mP2.processMessage what=4 D/hsm1 ( 1999): mP2.processMessage what=5 D/hsm1 ( 1999): mP2.exit D/hsm1 ( 1999): halting

Fields Summary
private String
mName
private static final int
SM_QUIT_CMD
Message.what value when quitting
private static final int
SM_INIT_CMD
Message.what value when initializing
public static final boolean
HANDLED
Convenience constant that maybe returned by processMessage to indicate the the message was processed and is not to be processed by parent states
public static final boolean
NOT_HANDLED
Convenience constant that maybe returned by processMessage to indicate the the message was NOT processed and is to be processed by parent states
private SmHandler
mSmHandler
private android.os.HandlerThread
mSmThread
Constructors Summary
protected StateMachine(String name)
Constructor creates a StateMachine with its own thread.

param
name of the state machine

        mSmThread = new HandlerThread(name);
        mSmThread.start();
        Looper looper = mSmThread.getLooper();

        initStateMachine(name, looper);
    
protected StateMachine(String name, android.os.Looper looper)
Constructor creates a StateMachine using the looper.

param
name of the state machine

        initStateMachine(name, looper);
    
protected StateMachine(String name, android.os.Handler handler)
Constructor creates a StateMachine using the handler.

param
name of the state machine

        initStateMachine(name, handler.getLooper());
    
Methods Summary
protected voidaddLogRec(java.lang.String string)
Add the string to LogRecords.

param
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);
    
protected final voidaddState(State state, State parent)
Add a new state to the state machine

param
state the state to add
param
parent the parent of state

        mSmHandler.addState(state, parent);
    
protected final voidaddState(State state)
Add a new state to the state machine, parent will be null

param
state to add

        mSmHandler.addState(state, null);
    
public final java.util.CollectioncopyLogRecs()

return
a copy of LogRecs as a collection

        Vector<LogRec> vlr = new Vector<LogRec>();
        SmHandler smh = mSmHandler;
        if (smh != null) {
            for (LogRec lr : smh.mLogRecords.mLogRecVector) {
                vlr.add(lr);
            }
        }
        return vlr;
    
protected final voiddeferMessage(android.os.Message msg)
Defer this message until next state transition. Upon transitioning all deferred messages will be placed on the queue and reprocessed in the original order. (i.e. The next state the oldest messages will be processed first)

param
msg is deferred until the next transition.

        mSmHandler.deferMessage(msg);
    
public voiddump(java.io.FileDescriptor fd, java.io.PrintWriter pw, java.lang.String[] args)
Dump the current state.

param
fd
param
pw
param
args

        // Cannot just invoke pw.println(this.toString()) because if the
        // resulting string is to long it won't be displayed.
        pw.println(getName() + ":");
        pw.println(" total records=" + getLogRecCount());
        for (int i = 0; i < getLogRecSize(); i++) {
            pw.println(" rec[" + i + "]: " + getLogRec(i).toString());
            pw.flush();
        }
        pw.println("curState=" + getCurrentState().getName());
    
protected final android.os.MessagegetCurrentMessage()

return
current message

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return null;
        return smh.getCurrentMessage();
    
protected final IStategetCurrentState()

return
current state

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return null;
        return smh.getCurrentState();
    
public final android.os.HandlergetHandler()

return
Handler, maybe null if state machine has quit.

        return mSmHandler;
    
public final com.android.internal.util.StateMachine$LogRecgetLogRec(int index)

return
a log record, or null if index is out of range

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return null;
        return smh.mLogRecords.get(index);
    
public final intgetLogRecCount()

return
the total number of records processed

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return 0;
        return smh.mLogRecords.count();
    
public final intgetLogRecSize()

return
number of log records

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return 0;
        return smh.mLogRecords.size();
    
protected java.lang.StringgetLogRecString(android.os.Message msg)
Return a string to be logged by LogRec, default is an empty string. Override if additional information is desired.

param
msg that was processed
return
information to be logged as a String

        return "";
    
public final java.lang.StringgetName()

return
the name

        return mName;
    
protected java.lang.StringgetWhatToString(int what)

return
the string for msg.what

        return null;
    
protected voidhaltedProcessMessage(android.os.Message msg)
Called for any message that is received after transitionToHalting is called.

    
private voidinitStateMachine(java.lang.String name, android.os.Looper looper)
Initialize.

param
looper for this state machine
param
name of the state machine

        mName = name;
        mSmHandler = new SmHandler(looper, this);
    
public booleanisDbg()

return
if debugging is enabled

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return false;

        return smh.isDbg();
    
protected final booleanisQuit(android.os.Message msg)
Validate that the message was sent by {@link StateMachine#quit} or {@link StateMachine#quitNow}.

        // 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 voidlog(java.lang.String s)
Log with debug

param
s is string log

        Log.d(mName, s);
    
protected voidlogAndAddLogRec(java.lang.String s)
Log with debug and add to the LogRecords.

param
s is string log

        addLogRec(s);
        log(s);
    
protected voidlogd(java.lang.String s)
Log with debug attribute

param
s is string log

        Log.d(mName, s);
    
protected voidloge(java.lang.String s)
Log with error attribute

param
s is string log

        Log.e(mName, s);
    
protected voidloge(java.lang.String s, java.lang.Throwable e)
Log with error attribute

param
s is string log
param
e is a Throwable which logs additional information.

        Log.e(mName, s, e);
    
protected voidlogi(java.lang.String s)
Log with info attribute

param
s is string log

        Log.i(mName, s);
    
protected voidlogv(java.lang.String s)
Log with verbose attribute

param
s is string log

        Log.v(mName, s);
    
protected voidlogw(java.lang.String s)
Log with warning attribute

param
s is string log

        Log.w(mName, s);
    
public final android.os.MessageobtainMessage()
Get a message and set Message.target state machine handler. 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

        return Message.obtain(mSmHandler);
    
public final android.os.MessageobtainMessage(int 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
A Message object from the global pool

        return Message.obtain(mSmHandler, what);
    
public final android.os.MessageobtainMessage(int what, java.lang.Object obj)
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
A Message object from the global pool

        return Message.obtain(mSmHandler, what, obj);
    
public final android.os.MessageobtainMessage(int what, int arg1)
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
return
A Message object from the global pool

        // use this obtain so we don't match the obtain(h, what, Object) method
        return Message.obtain(mSmHandler, what, arg1, 0);
    
public final android.os.MessageobtainMessage(int what, int arg1, int arg2)
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

        return Message.obtain(mSmHandler, what, arg1, arg2);
    
public final android.os.MessageobtainMessage(int what, int arg1, int arg2, java.lang.Object obj)
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

        return Message.obtain(mSmHandler, what, arg1, arg2, obj);
    
protected voidonHalting()
This will be called once after handling a message that called transitionToHalting. All subsequent messages will invoke {@link StateMachine#haltedProcessMessage(Message)}

    
protected voidonQuitting()
This will be called once after a quit message that was NOT handled by the derived StateMachine. The StateMachine will stop and any subsequent messages will be ignored. In addition, if this StateMachine created the thread, the thread will be stopped after this method returns.

    
protected final voidquit()
Quit the state machine after all currently queued up messages are processed.

        // mSmHandler can be null if the state machine is already stopped.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.quit();
    
protected final voidquitNow()
Quit the state machine immediately all currently queued messages will be discarded.

        // mSmHandler can be null if the state machine is already stopped.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.quitNow();
    
protected booleanrecordLogRec(android.os.Message msg)

return
true if msg should be saved in the log, default is true.

        return true;
    
protected final voidremoveMessages(int what)
Removes a message from the message queue. Protected, may only be called by instances of StateMachine.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.removeMessages(what);
    
public final voidsendMessage(int what)
Enqueue a message to this state machine. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessage(obtainMessage(what));
    
public final voidsendMessage(int what, java.lang.Object obj)
Enqueue a message to this state machine. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessage(obtainMessage(what, obj));
    
public final voidsendMessage(int what, int arg1)
Enqueue a message to this state machine. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessage(obtainMessage(what, arg1));
    
public final voidsendMessage(int what, int arg1, int arg2)
Enqueue a message to this state machine. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessage(obtainMessage(what, arg1, arg2));
    
public final voidsendMessage(int what, int arg1, int arg2, java.lang.Object obj)
Enqueue a message to this state machine. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessage(obtainMessage(what, arg1, arg2, obj));
    
public final voidsendMessage(android.os.Message msg)
Enqueue a message to this state machine. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessage(msg);
    
protected final voidsendMessageAtFrontOfQueue(int 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.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageAtFrontOfQueue(obtainMessage(what));
    
protected final voidsendMessageAtFrontOfQueue(int what, java.lang.Object 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.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
    
protected final voidsendMessageAtFrontOfQueue(int what, int arg1)
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.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageAtFrontOfQueue(obtainMessage(what, arg1));
    
protected final voidsendMessageAtFrontOfQueue(int what, int arg1, int arg2)
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.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageAtFrontOfQueue(obtainMessage(what, arg1, arg2));
    
protected final voidsendMessageAtFrontOfQueue(int what, int arg1, int arg2, java.lang.Object 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.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageAtFrontOfQueue(obtainMessage(what, arg1, arg2, obj));
    
protected final voidsendMessageAtFrontOfQueue(android.os.Message msg)
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.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageAtFrontOfQueue(msg);
    
public final voidsendMessageDelayed(int what, long delayMillis)
Enqueue a message to this state machine after a delay. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageDelayed(obtainMessage(what), delayMillis);
    
public final voidsendMessageDelayed(int what, java.lang.Object obj, long delayMillis)
Enqueue a message to this state machine after a delay. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
    
public final voidsendMessageDelayed(int what, int arg1, long delayMillis)
Enqueue a message to this state machine after a delay. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageDelayed(obtainMessage(what, arg1), delayMillis);
    
public final voidsendMessageDelayed(int what, int arg1, int arg2, long delayMillis)
Enqueue a message to this state machine after a delay. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageDelayed(obtainMessage(what, arg1, arg2), delayMillis);
    
public final voidsendMessageDelayed(int what, int arg1, int arg2, java.lang.Object obj, long delayMillis)
Enqueue a message to this state machine after a delay. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageDelayed(obtainMessage(what, arg1, arg2, obj), delayMillis);
    
public final voidsendMessageDelayed(android.os.Message msg, long delayMillis)
Enqueue a message to this state machine after a delay. Message is ignored if state machine has quit.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageDelayed(msg, delayMillis);
    
public voidsetDbg(boolean dbg)
Set debug enable/disabled.

param
dbg is true to enable debugging.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.setDbg(dbg);
    
protected final voidsetInitialState(State initialState)
Set the initial state. This must be invoked before and messages are sent to the state machine.

param
initialState is the state which will receive the first message.

        mSmHandler.setInitialState(initialState);
    
public final voidsetLogOnlyTransitions(boolean enable)
Set to log only messages that cause a state transition

param
enable {@code true} to enable, {@code false} to disable

        mSmHandler.mLogRecords.setLogOnlyTransitions(enable);
    
public final voidsetLogRecSize(int maxSize)
Set number of log records to maintain and clears all current records.

param
maxSize number of messages to maintain at anyone time.

        mSmHandler.mLogRecords.setSize(maxSize);
    
public voidstart()
Start the state machine.

        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        /** Send the complete construction message */
        smh.completeConstruction();
    
public java.lang.StringtoString()

        StringWriter sr = new StringWriter();
        PrintWriter pr = new PrintWriter(sr);
        dump(null, pr, null);
        pr.flush();
        pr.close();
        return sr.toString();
    
protected final voidtransitionTo(IState destState)
transition to destination state. Upon returning from processMessage the current state's exit will be executed and upon the next message arriving destState.enter will be invoked. this function can also be called inside the enter function of the previous transition target, but the behavior is undefined when it is called mid-way through a previous transition (for example, calling this in the enter() routine of a intermediate node when the current transition target is one of the nodes descendants).

param
destState will be the state that receives the next message.

        mSmHandler.transitionTo(destState);
    
protected final voidtransitionToHaltingState()
transition to halt state. Upon returning from processMessage we will exit all current states, execute the onHalting() method and then for all subsequent messages haltedProcessMessage will be called.

        mSmHandler.transitionTo(mSmHandler.mHaltingState);
    
protected voidunhandledMessage(android.os.Message msg)
Called when message wasn't handled

param
msg that couldn't be handled.

        if (mSmHandler.mDbg) loge(" - unhandledMessage: msg.what=" + msg.what);