StateMachine.java revision 64c42cae4482fe0157e977b8ddd0f2c2436b3f31
1/**
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.util;
18
19import android.os.Handler;
20import android.os.HandlerThread;
21import android.os.Looper;
22import android.os.Message;
23import android.util.Log;
24
25import java.util.ArrayList;
26import java.util.HashMap;
27import java.util.Vector;
28
29/**
30 * {@hide}
31 *
32 * <p>The state machine defined here is a hierarchical state machine which processes messages
33 * and can have states arranged hierarchically.</p>
34 *
35 * <p>A state is a <code>State</code> object and must implement
36 * <code>processMessage</code> and optionally <code>enter/exit/getName</code>.
37 * The enter/exit methods are equivalent to the construction and destruction
38 * in Object Oriented programming and are used to perform initialization and
39 * cleanup of the state respectively. The <code>getName</code> method returns the
40 * name of the state the default implementation returns the class name it may be
41 * desirable to have this return the name of the state instance name instead.
42 * In particular if a particular state class has multiple instances.</p>
43 *
44 * <p>When a state machine is created <code>addState</code> is used to build the
45 * hierarchy and <code>setInitialState</code> is used to identify which of these
46 * is the initial state. After construction the programmer calls <code>start</code>
47 * which initializes the state machine and calls <code>enter</code> for all of the initial
48 * state's hierarchy, starting at its eldest parent. For example given the simple
49 * state machine below after start is called mP1.enter will have been called and
50 * then mS1.enter.</p>
51<code>
52        mP1
53       /   \
54      mS2   mS1 ----> initial state
55</code>
56 * <p>After the state machine is created and started, messages are sent to a state
57 * machine using <code>sendMessage</code> and the messages are created using
58 * <code>obtainMessage</code>. When the state machine receives a message the
59 * current state's <code>processMessage</code> is invoked. In the above example
60 * mS1.processMessage will be invoked first. The state may use <code>transitionTo</code>
61 * to change the current state to a new state</p>
62 *
63 * <p>Each state in the state machine may have a zero or one parent states and if
64 * a child state is unable to handle a message it may have the message processed
65 * by its parent by returning false or NOT_HANDLED. If a message is never processed
66 * <code>unhandledMessage</code> will be invoked to give one last chance for the state machine
67 * to process the message.</p>
68 *
69 * <p>When all processing is completed a state machine may choose to call
70 * <code>transitionToHaltingState</code>. When the current <code>processingMessage</code>
71 * returns the state machine will transfer to an internal <code>HaltingState</code>
72 * and invoke <code>halting</code>. Any message subsequently received by the state
73 * machine will cause <code>haltedProcessMessage</code> to be invoked.</p>
74 *
75 * <p>If it is desirable to completely stop the state machine call <code>quit</code>. This
76 * will exit the current state and its parent and then exit from the controlling thread
77 * and no further messages will be processed.</p>
78 *
79 * <p>In addition to <code>processMessage</code> each <code>State</code> has
80 * an <code>enter</code> method and <code>exit</exit> method which may be overridden.</p>
81 *
82 * <p>Since the states are arranged in a hierarchy transitioning to a new state
83 * causes current states to be exited and new states to be entered. To determine
84 * the list of states to be entered/exited the common parent closest to
85 * the current state is found. We then exit from the current state and its
86 * parent's up to but not including the common parent state and then enter all
87 * of the new states below the common parent down to the destination state.
88 * If there is no common parent all states are exited and then the new states
89 * are entered.</p>
90 *
91 * <p>Two other methods that states can use are <code>deferMessage</code> and
92 * <code>sendMessageAtFrontOfQueue</code>. The <code>sendMessageAtFrontOfQueue</code> sends
93 * a message but places it on the front of the queue rather than the back. The
94 * <code>deferMessage</code> causes the message to be saved on a list until a
95 * transition is made to a new state. At which time all of the deferred messages
96 * will be put on the front of the state machine queue with the oldest message
97 * at the front. These will then be processed by the new current state before
98 * any other messages that are on the queue or might be added later. Both of
99 * these are protected and may only be invoked from within a state machine.</p>
100 *
101 * <p>To illustrate some of these properties we'll use state machine with an 8
102 * state hierarchy:</p>
103<code>
104          mP0
105         /   \
106        mP1   mS0
107       /   \
108      mS2   mS1
109     /  \    \
110    mS3  mS4  mS5  ---> initial state
111</code>
112 * <p>After starting mS5 the list of active states is mP0, mP1, mS1 and mS5.
113 * So the order of calling processMessage when a message is received is mS5,
114 * mS1, mP1, mP0 assuming each processMessage indicates it can't handle this
115 * message by returning false or NOT_HANDLED.</p>
116 *
117 * <p>Now assume mS5.processMessage receives a message it can handle, and during
118 * the handling determines the machine should change states. It could call
119 * transitionTo(mS4) and return true or HANDLED. Immediately after returning from
120 * processMessage the state machine runtime will find the common parent,
121 * which is mP1. It will then call mS5.exit, mS1.exit, mS2.enter and then
122 * mS4.enter. The new list of active states is mP0, mP1, mS2 and mS4. So
123 * when the next message is received mS4.processMessage will be invoked.</p>
124 *
125 * <p>Now for some concrete examples, here is the canonical HelloWorld as a state machine.
126 * It responds with "Hello World" being printed to the log for every message.</p>
127<code>
128class HelloWorld extends StateMachine {
129    HelloWorld(String name) {
130        super(name);
131        addState(mState1);
132        setInitialState(mState1);
133    }
134
135    public static HelloWorld makeHelloWorld() {
136        HelloWorld hw = new HelloWorld("hw");
137        hw.start();
138        return hw;
139    }
140
141    class State1 extends State {
142        &#64;Override public boolean processMessage(Message message) {
143            Log.d(TAG, "Hello World");
144            return HANDLED;
145        }
146    }
147    State1 mState1 = new State1();
148}
149
150void testHelloWorld() {
151    HelloWorld hw = makeHelloWorld();
152    hw.sendMessage(hw.obtainMessage());
153}
154</code>
155 * <p>A more interesting state machine is one with four states
156 * with two independent parent states.</p>
157<code>
158        mP1      mP2
159       /   \
160      mS2   mS1
161</code>
162 * <p>Here is a description of this state machine using pseudo code.</p>
163 <code>
164state mP1 {
165     enter { log("mP1.enter"); }
166     exit { log("mP1.exit");  }
167     on msg {
168         CMD_2 {
169             send(CMD_3);
170             defer(msg);
171             transitonTo(mS2);
172             return HANDLED;
173         }
174         return NOT_HANDLED;
175     }
176}
177
178INITIAL
179state mS1 parent mP1 {
180     enter { log("mS1.enter"); }
181     exit  { log("mS1.exit");  }
182     on msg {
183         CMD_1 {
184             transitionTo(mS1);
185             return HANDLED;
186         }
187         return NOT_HANDLED;
188     }
189}
190
191state mS2 parent mP1 {
192     enter { log("mS2.enter"); }
193     exit  { log("mS2.exit");  }
194     on msg {
195         CMD_2 {
196             send(CMD_4);
197             return HANDLED;
198         }
199         CMD_3 {
200             defer(msg);
201             transitionTo(mP2);
202             return HANDLED;
203         }
204         return NOT_HANDLED;
205     }
206}
207
208state mP2 {
209     enter {
210         log("mP2.enter");
211         send(CMD_5);
212     }
213     exit { log("mP2.exit"); }
214     on msg {
215         CMD_3, CMD_4 { return HANDLED; }
216         CMD_5 {
217             transitionTo(HaltingState);
218             return HANDLED;
219         }
220         return NOT_HANDLED;
221     }
222}
223</code>
224 * <p>The implementation is below and also in StateMachineTest:</p>
225<code>
226class Hsm1 extends StateMachine {
227    private static final String TAG = "hsm1";
228
229    public static final int CMD_1 = 1;
230    public static final int CMD_2 = 2;
231    public static final int CMD_3 = 3;
232    public static final int CMD_4 = 4;
233    public static final int CMD_5 = 5;
234
235    public static Hsm1 makeHsm1() {
236        Log.d(TAG, "makeHsm1 E");
237        Hsm1 sm = new Hsm1("hsm1");
238        sm.start();
239        Log.d(TAG, "makeHsm1 X");
240        return sm;
241    }
242
243    Hsm1(String name) {
244        super(name);
245        Log.d(TAG, "ctor E");
246
247        // Add states, use indentation to show hierarchy
248        addState(mP1);
249            addState(mS1, mP1);
250            addState(mS2, mP1);
251        addState(mP2);
252
253        // Set the initial state
254        setInitialState(mS1);
255        Log.d(TAG, "ctor X");
256    }
257
258    class P1 extends State {
259        &#64;Override public void enter() {
260            Log.d(TAG, "mP1.enter");
261        }
262        &#64;Override public boolean processMessage(Message message) {
263            boolean retVal;
264            Log.d(TAG, "mP1.processMessage what=" + message.what);
265            switch(message.what) {
266            case CMD_2:
267                // CMD_2 will arrive in mS2 before CMD_3
268                sendMessage(obtainMessage(CMD_3));
269                deferMessage(message);
270                transitionTo(mS2);
271                retVal = HANDLED;
272                break;
273            default:
274                // Any message we don't understand in this state invokes unhandledMessage
275                retVal = NOT_HANDLED;
276                break;
277            }
278            return retVal;
279        }
280        &#64;Override public void exit() {
281            Log.d(TAG, "mP1.exit");
282        }
283    }
284
285    class S1 extends State {
286        &#64;Override public void enter() {
287            Log.d(TAG, "mS1.enter");
288        }
289        &#64;Override public boolean processMessage(Message message) {
290            Log.d(TAG, "S1.processMessage what=" + message.what);
291            if (message.what == CMD_1) {
292                // Transition to ourself to show that enter/exit is called
293                transitionTo(mS1);
294                return HANDLED;
295            } else {
296                // Let parent process all other messages
297                return NOT_HANDLED;
298            }
299        }
300        &#64;Override public void exit() {
301            Log.d(TAG, "mS1.exit");
302        }
303    }
304
305    class S2 extends State {
306        &#64;Override public void enter() {
307            Log.d(TAG, "mS2.enter");
308        }
309        &#64;Override public boolean processMessage(Message message) {
310            boolean retVal;
311            Log.d(TAG, "mS2.processMessage what=" + message.what);
312            switch(message.what) {
313            case(CMD_2):
314                sendMessage(obtainMessage(CMD_4));
315                retVal = HANDLED;
316                break;
317            case(CMD_3):
318                deferMessage(message);
319                transitionTo(mP2);
320                retVal = HANDLED;
321                break;
322            default:
323                retVal = NOT_HANDLED;
324                break;
325            }
326            return retVal;
327        }
328        &#64;Override public void exit() {
329            Log.d(TAG, "mS2.exit");
330        }
331    }
332
333    class P2 extends State {
334        &#64;Override public void enter() {
335            Log.d(TAG, "mP2.enter");
336            sendMessage(obtainMessage(CMD_5));
337        }
338        &#64;Override public boolean processMessage(Message message) {
339            Log.d(TAG, "P2.processMessage what=" + message.what);
340            switch(message.what) {
341            case(CMD_3):
342                break;
343            case(CMD_4):
344                break;
345            case(CMD_5):
346                transitionToHaltingState();
347                break;
348            }
349            return HANDLED;
350        }
351        &#64;Override public void exit() {
352            Log.d(TAG, "mP2.exit");
353        }
354    }
355
356    &#64;Override
357    void halting() {
358        Log.d(TAG, "halting");
359        synchronized (this) {
360            this.notifyAll();
361        }
362    }
363
364    P1 mP1 = new P1();
365    S1 mS1 = new S1();
366    S2 mS2 = new S2();
367    P2 mP2 = new P2();
368}
369</code>
370 * <p>If this is executed by sending two messages CMD_1 and CMD_2
371 * (Note the synchronize is only needed because we use hsm.wait())</p>
372<code>
373Hsm1 hsm = makeHsm1();
374synchronize(hsm) {
375     hsm.sendMessage(obtainMessage(hsm.CMD_1));
376     hsm.sendMessage(obtainMessage(hsm.CMD_2));
377     try {
378          // wait for the messages to be handled
379          hsm.wait();
380     } catch (InterruptedException e) {
381          Log.e(TAG, "exception while waiting " + e.getMessage());
382     }
383}
384</code>
385 * <p>The output is:</p>
386<code>
387D/hsm1    ( 1999): makeHsm1 E
388D/hsm1    ( 1999): ctor E
389D/hsm1    ( 1999): ctor X
390D/hsm1    ( 1999): mP1.enter
391D/hsm1    ( 1999): mS1.enter
392D/hsm1    ( 1999): makeHsm1 X
393D/hsm1    ( 1999): mS1.processMessage what=1
394D/hsm1    ( 1999): mS1.exit
395D/hsm1    ( 1999): mS1.enter
396D/hsm1    ( 1999): mS1.processMessage what=2
397D/hsm1    ( 1999): mP1.processMessage what=2
398D/hsm1    ( 1999): mS1.exit
399D/hsm1    ( 1999): mS2.enter
400D/hsm1    ( 1999): mS2.processMessage what=2
401D/hsm1    ( 1999): mS2.processMessage what=3
402D/hsm1    ( 1999): mS2.exit
403D/hsm1    ( 1999): mP1.exit
404D/hsm1    ( 1999): mP2.enter
405D/hsm1    ( 1999): mP2.processMessage what=3
406D/hsm1    ( 1999): mP2.processMessage what=4
407D/hsm1    ( 1999): mP2.processMessage what=5
408D/hsm1    ( 1999): mP2.exit
409D/hsm1    ( 1999): halting
410</code>
411 */
412public class StateMachine {
413
414    private static final String TAG = "StateMachine";
415    private String mName;
416
417    /** Message.what value when quitting */
418    public static final int SM_QUIT_CMD = -1;
419
420    /** Message.what value when initializing */
421    public static final int SM_INIT_CMD = -1;
422
423    /**
424     * Convenience constant that maybe returned by processMessage
425     * to indicate the the message was processed and is not to be
426     * processed by parent states
427     */
428    public static final boolean HANDLED = true;
429
430    /**
431     * Convenience constant that maybe returned by processMessage
432     * to indicate the the message was NOT processed and is to be
433     * processed by parent states
434     */
435    public static final boolean NOT_HANDLED = false;
436
437    /**
438     * {@hide}
439     *
440     * The information maintained for a processed message.
441     */
442    public static class ProcessedMessageInfo {
443        private int what;
444        private State state;
445        private State orgState;
446
447        /**
448         * Constructor
449         * @param message
450         * @param state that handled the message
451         * @param orgState is the first state the received the message but
452         * did not processes the message.
453         */
454        ProcessedMessageInfo(Message message, State state, State orgState) {
455            update(message, state, orgState);
456        }
457
458        /**
459         * Update the information in the record.
460         * @param state that handled the message
461         * @param orgState is the first state the received the message but
462         * did not processes the message.
463         */
464        public void update(Message message, State state, State orgState) {
465            this.what = message.what;
466            this.state = state;
467            this.orgState = orgState;
468        }
469
470        /**
471         * @return the command that was executing
472         */
473        public int getWhat() {
474            return what;
475        }
476
477        /**
478         * @return the state that handled this message
479         */
480        public State getState() {
481            return state;
482        }
483
484        /**
485         * @return the original state that received the message.
486         */
487        public State getOriginalState() {
488            return orgState;
489        }
490
491        /**
492         * @return as string
493         */
494        @Override
495        public String toString() {
496            StringBuilder sb = new StringBuilder();
497            sb.append("what=");
498            sb.append(what);
499            sb.append(" state=");
500            sb.append(cn(state));
501            sb.append(" orgState=");
502            sb.append(cn(orgState));
503            return sb.toString();
504        }
505
506        /**
507         * @return an objects class name
508         */
509        private String cn(Object n) {
510            if (n == null) {
511                return "null";
512            } else {
513                String name = n.getClass().getName();
514                int lastDollar = name.lastIndexOf('$');
515                return name.substring(lastDollar + 1);
516            }
517        }
518    }
519
520    /**
521     * A list of messages recently processed by the state machine.
522     *
523     * The class maintains a list of messages that have been most
524     * recently processed. The list is finite and may be set in the
525     * constructor or by calling setSize. The public interface also
526     * includes size which returns the number of recent messages,
527     * count which is the number of message processed since the
528     * the last setSize, get which returns a processed message and
529     * add which adds a processed messaged.
530     */
531    private static class ProcessedMessages {
532
533        private static final int DEFAULT_SIZE = 20;
534
535        private Vector<ProcessedMessageInfo> mMessages = new Vector<ProcessedMessageInfo>();
536        private int mMaxSize = DEFAULT_SIZE;
537        private int mOldestIndex = 0;
538        private int mCount = 0;
539
540        /**
541         * Constructor
542         */
543        ProcessedMessages() {
544        }
545
546        /**
547         * Set size of messages to maintain and clears all current messages.
548         *
549         * @param maxSize number of messages to maintain at anyone time.
550        */
551        void setSize(int maxSize) {
552            mMaxSize = maxSize;
553            mCount = 0;
554            mMessages.clear();
555        }
556
557        /**
558         * @return the number of recent messages.
559         */
560        int size() {
561            return mMessages.size();
562        }
563
564        /**
565         * @return the total number of messages processed since size was set.
566         */
567        int count() {
568            return mCount;
569        }
570
571        /**
572         * @return the information on a particular record. 0 is the oldest
573         * record and size()-1 is the newest record. If the index is to
574         * large null is returned.
575         */
576        ProcessedMessageInfo get(int index) {
577            int nextIndex = mOldestIndex + index;
578            if (nextIndex >= mMaxSize) {
579                nextIndex -= mMaxSize;
580            }
581            if (nextIndex >= size()) {
582                return null;
583            } else {
584                return mMessages.get(nextIndex);
585            }
586        }
587
588        /**
589         * Add a processed message.
590         *
591         * @param message
592         * @param state that handled the message
593         * @param orgState is the first state the received the message but
594         * did not processes the message.
595         */
596        void add(Message message, State state, State orgState) {
597            mCount += 1;
598            if (mMessages.size() < mMaxSize) {
599                mMessages.add(new ProcessedMessageInfo(message, state, orgState));
600            } else {
601                ProcessedMessageInfo pmi = mMessages.get(mOldestIndex);
602                mOldestIndex += 1;
603                if (mOldestIndex >= mMaxSize) {
604                    mOldestIndex = 0;
605                }
606                pmi.update(message, state, orgState);
607            }
608        }
609    }
610
611    private static class SmHandler extends Handler {
612
613        /** The debug flag */
614        private boolean mDbg = false;
615
616        /** The quit object */
617        private static final Object mQuitObj = new Object();
618
619        /** The current message */
620        private Message mMsg;
621
622        /** A list of messages that this state machine has processed */
623        private ProcessedMessages mProcessedMessages = new ProcessedMessages();
624
625        /** true if construction of the state machine has not been completed */
626        private boolean mIsConstructionCompleted;
627
628        /** Stack used to manage the current hierarchy of states */
629        private StateInfo mStateStack[];
630
631        /** Top of mStateStack */
632        private int mStateStackTopIndex = -1;
633
634        /** A temporary stack used to manage the state stack */
635        private StateInfo mTempStateStack[];
636
637        /** The top of the mTempStateStack */
638        private int mTempStateStackCount;
639
640        /** State used when state machine is halted */
641        private HaltingState mHaltingState = new HaltingState();
642
643        /** State used when state machine is quitting */
644        private QuittingState mQuittingState = new QuittingState();
645
646        /** Reference to the StateMachine */
647        private StateMachine mSm;
648
649        /**
650         * Information about a state.
651         * Used to maintain the hierarchy.
652         */
653        private class StateInfo {
654            /** The state */
655            State state;
656
657            /** The parent of this state, null if there is no parent */
658            StateInfo parentStateInfo;
659
660            /** True when the state has been entered and on the stack */
661            boolean active;
662
663            /**
664             * Convert StateInfo to string
665             */
666            @Override
667            public String toString() {
668                return "state=" + state.getName() + ",active=" + active
669                        + ",parent=" + ((parentStateInfo == null) ?
670                                        "null" : parentStateInfo.state.getName());
671            }
672        }
673
674        /** The map of all of the states in the state machine */
675        private HashMap<State, StateInfo> mStateInfo =
676            new HashMap<State, StateInfo>();
677
678        /** The initial state that will process the first message */
679        private State mInitialState;
680
681        /** The destination state when transitionTo has been invoked */
682        private State mDestState;
683
684        /** The list of deferred messages */
685        private ArrayList<Message> mDeferredMessages = new ArrayList<Message>();
686
687        /**
688         * State entered when transitionToHaltingState is called.
689         */
690        private class HaltingState extends State {
691            @Override
692            public boolean processMessage(Message msg) {
693                mSm.haltedProcessMessage(msg);
694                return true;
695            }
696        }
697
698        /**
699         * State entered when a valid quit message is handled.
700         */
701        private class QuittingState extends State {
702            @Override
703            public boolean processMessage(Message msg) {
704                return NOT_HANDLED;
705            }
706        }
707
708        /**
709         * Handle messages sent to the state machine by calling
710         * the current state's processMessage. It also handles
711         * the enter/exit calls and placing any deferred messages
712         * back onto the queue when transitioning to a new state.
713         */
714        @Override
715        public final void handleMessage(Message msg) {
716            if (mDbg) Log.d(TAG, "handleMessage: E msg.what=" + msg.what);
717
718            /** Save the current message */
719            mMsg = msg;
720
721            /**
722             * Check that construction was completed
723             */
724            if (!mIsConstructionCompleted) {
725                Log.e(TAG, "The start method not called, ignore msg: " + msg);
726                return;
727            }
728
729            /**
730             * Process the message abiding by the hierarchical semantics
731             * and perform any requested transitions.
732             */
733            processMsg(msg);
734            performTransitions();
735
736            if (mDbg) Log.d(TAG, "handleMessage: X");
737        }
738
739        /**
740         * Do any transitions
741         */
742        private void performTransitions() {
743            /**
744             * If transitionTo has been called, exit and then enter
745             * the appropriate states. We loop on this to allow
746             * enter and exit methods to use transitionTo.
747             */
748            State destState = null;
749            while (mDestState != null) {
750                if (mDbg) Log.d(TAG, "handleMessage: new destination call exit");
751
752                /**
753                 * Save mDestState locally and set to null
754                 * to know if enter/exit use transitionTo.
755                 */
756                destState = mDestState;
757                mDestState = null;
758
759                /**
760                 * Determine the states to exit and enter and return the
761                 * common ancestor state of the enter/exit states. Then
762                 * invoke the exit methods then the enter methods.
763                 */
764                StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
765                invokeExitMethods(commonStateInfo);
766                int stateStackEnteringIndex = moveTempStateStackToStateStack();
767                invokeEnterMethods(stateStackEnteringIndex);
768
769
770                /**
771                 * Since we have transitioned to a new state we need to have
772                 * any deferred messages moved to the front of the message queue
773                 * so they will be processed before any other messages in the
774                 * message queue.
775                 */
776                moveDeferredMessageAtFrontOfQueue();
777            }
778
779            /**
780             * After processing all transitions check and
781             * see if the last transition was to quit or halt.
782             */
783            if (destState != null) {
784                if (destState == mQuittingState) {
785                    /**
786                     * We are quitting so ignore all messages.
787                     */
788                    mSm.quitting();
789                    if (mSm.mSmThread != null) {
790                        // If we made the thread then quit looper which stops the thread.
791                        getLooper().quit();
792                        mSm.mSmThread = null;
793                    }
794                } else if (destState == mHaltingState) {
795                    /**
796                     * Call halting() if we've transitioned to the halting
797                     * state. All subsequent messages will be processed in
798                     * in the halting state which invokes haltedProcessMessage(msg);
799                     */
800                    mSm.halting();
801                }
802            }
803        }
804
805        /**
806         * Complete the construction of the state machine.
807         */
808        private final void completeConstruction() {
809            if (mDbg) Log.d(TAG, "completeConstruction: E");
810
811            /**
812             * Determine the maximum depth of the state hierarchy
813             * so we can allocate the state stacks.
814             */
815            int maxDepth = 0;
816            for (StateInfo si : mStateInfo.values()) {
817                int depth = 0;
818                for (StateInfo i = si; i != null; depth++) {
819                    i = i.parentStateInfo;
820                }
821                if (maxDepth < depth) {
822                    maxDepth = depth;
823                }
824            }
825            if (mDbg) Log.d(TAG, "completeConstruction: maxDepth=" + maxDepth);
826
827            mStateStack = new StateInfo[maxDepth];
828            mTempStateStack = new StateInfo[maxDepth];
829            setupInitialStateStack();
830
831            /**
832             * Construction is complete call all enter methods
833             * starting at the first entry.
834             */
835            mIsConstructionCompleted = true;
836            mMsg = obtainMessage(SM_INIT_CMD);
837            invokeEnterMethods(0);
838
839            /**
840             * Perform any transitions requested by the enter methods
841             */
842            performTransitions();
843
844            if (mDbg) Log.d(TAG, "completeConstruction: X");
845        }
846
847        /**
848         * Process the message. If the current state doesn't handle
849         * it, call the states parent and so on. If it is never handled then
850         * call the state machines unhandledMessage method.
851         */
852        private final void processMsg(Message msg) {
853            StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
854            if (mDbg) {
855                Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
856            }
857            while (!curStateInfo.state.processMessage(msg)) {
858                /**
859                 * Not processed
860                 */
861                curStateInfo = curStateInfo.parentStateInfo;
862                if (curStateInfo == null) {
863                    /**
864                     * No parents left so it's not handled
865                     */
866                    mSm.unhandledMessage(msg);
867                    if (isQuit(msg)) {
868                        transitionTo(mQuittingState);
869                    }
870                    break;
871                }
872                if (mDbg) {
873                    Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
874                }
875            }
876
877            /**
878             * Record that we processed the message
879             */
880            if (curStateInfo != null) {
881                State orgState = mStateStack[mStateStackTopIndex].state;
882                mProcessedMessages.add(msg, curStateInfo.state, orgState);
883            } else {
884                mProcessedMessages.add(msg, null, null);
885            }
886        }
887
888        /**
889         * Call the exit method for each state from the top of stack
890         * up to the common ancestor state.
891         */
892        private final void invokeExitMethods(StateInfo commonStateInfo) {
893            while ((mStateStackTopIndex >= 0) &&
894                    (mStateStack[mStateStackTopIndex] != commonStateInfo)) {
895                State curState = mStateStack[mStateStackTopIndex].state;
896                if (mDbg) Log.d(TAG, "invokeExitMethods: " + curState.getName());
897                curState.exit();
898                mStateStack[mStateStackTopIndex].active = false;
899                mStateStackTopIndex -= 1;
900            }
901        }
902
903        /**
904         * Invoke the enter method starting at the entering index to top of state stack
905         */
906        private final void invokeEnterMethods(int stateStackEnteringIndex) {
907            for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
908                if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());
909                mStateStack[i].state.enter();
910                mStateStack[i].active = true;
911            }
912        }
913
914        /**
915         * Move the deferred message to the front of the message queue.
916         */
917        private final void moveDeferredMessageAtFrontOfQueue() {
918            /**
919             * The oldest messages on the deferred list must be at
920             * the front of the queue so start at the back, which
921             * as the most resent message and end with the oldest
922             * messages at the front of the queue.
923             */
924            for (int i = mDeferredMessages.size() - 1; i >= 0; i-- ) {
925                Message curMsg = mDeferredMessages.get(i);
926                if (mDbg) Log.d(TAG, "moveDeferredMessageAtFrontOfQueue; what=" + curMsg.what);
927                sendMessageAtFrontOfQueue(curMsg);
928            }
929            mDeferredMessages.clear();
930        }
931
932        /**
933         * Move the contents of the temporary stack to the state stack
934         * reversing the order of the items on the temporary stack as
935         * they are moved.
936         *
937         * @return index into mStateStack where entering needs to start
938         */
939        private final int moveTempStateStackToStateStack() {
940            int startingIndex = mStateStackTopIndex + 1;
941            int i = mTempStateStackCount - 1;
942            int j = startingIndex;
943            while (i >= 0) {
944                if (mDbg) Log.d(TAG, "moveTempStackToStateStack: i=" + i + ",j=" + j);
945                mStateStack[j] = mTempStateStack[i];
946                j += 1;
947                i -= 1;
948            }
949
950            mStateStackTopIndex = j - 1;
951            if (mDbg) {
952                Log.d(TAG, "moveTempStackToStateStack: X mStateStackTop="
953                      + mStateStackTopIndex + ",startingIndex=" + startingIndex
954                      + ",Top=" + mStateStack[mStateStackTopIndex].state.getName());
955            }
956            return startingIndex;
957        }
958
959        /**
960         * Setup the mTempStateStack with the states we are going to enter.
961         *
962         * This is found by searching up the destState's ancestors for a
963         * state that is already active i.e. StateInfo.active == true.
964         * The destStae and all of its inactive parents will be on the
965         * TempStateStack as the list of states to enter.
966         *
967         * @return StateInfo of the common ancestor for the destState and
968         * current state or null if there is no common parent.
969         */
970        private final StateInfo setupTempStateStackWithStatesToEnter(State destState) {
971            /**
972             * Search up the parent list of the destination state for an active
973             * state. Use a do while() loop as the destState must always be entered
974             * even if it is active. This can happen if we are exiting/entering
975             * the current state.
976             */
977            mTempStateStackCount = 0;
978            StateInfo curStateInfo = mStateInfo.get(destState);
979            do {
980                mTempStateStack[mTempStateStackCount++] = curStateInfo;
981                curStateInfo = curStateInfo.parentStateInfo;
982            } while ((curStateInfo != null) && !curStateInfo.active);
983
984            if (mDbg) {
985                Log.d(TAG, "setupTempStateStackWithStatesToEnter: X mTempStateStackCount="
986                      + mTempStateStackCount + ",curStateInfo: " + curStateInfo);
987            }
988            return curStateInfo;
989        }
990
991        /**
992         * Initialize StateStack to mInitialState.
993         */
994        private final void setupInitialStateStack() {
995            if (mDbg) {
996                Log.d(TAG, "setupInitialStateStack: E mInitialState="
997                    + mInitialState.getName());
998            }
999
1000            StateInfo curStateInfo = mStateInfo.get(mInitialState);
1001            for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
1002                mTempStateStack[mTempStateStackCount] = curStateInfo;
1003                curStateInfo = curStateInfo.parentStateInfo;
1004            }
1005
1006            // Empty the StateStack
1007            mStateStackTopIndex = -1;
1008
1009            moveTempStateStackToStateStack();
1010        }
1011
1012        /**
1013         * @return current message
1014         */
1015        private final Message getCurrentMessage() {
1016            return mMsg;
1017        }
1018
1019        /**
1020         * @return current state
1021         */
1022        private final IState getCurrentState() {
1023            return mStateStack[mStateStackTopIndex].state;
1024        }
1025
1026        /**
1027         * Add a new state to the state machine. Bottom up addition
1028         * of states is allowed but the same state may only exist
1029         * in one hierarchy.
1030         *
1031         * @param state the state to add
1032         * @param parent the parent of state
1033         * @return stateInfo for this state
1034         */
1035        private final StateInfo addState(State state, State parent) {
1036            if (mDbg) {
1037                Log.d(TAG, "addStateInternal: E state=" + state.getName()
1038                        + ",parent=" + ((parent == null) ? "" : parent.getName()));
1039            }
1040            StateInfo parentStateInfo = null;
1041            if (parent != null) {
1042                parentStateInfo = mStateInfo.get(parent);
1043                if (parentStateInfo == null) {
1044                    // Recursively add our parent as it's not been added yet.
1045                    parentStateInfo = addState(parent, null);
1046                }
1047            }
1048            StateInfo stateInfo = mStateInfo.get(state);
1049            if (stateInfo == null) {
1050                stateInfo = new StateInfo();
1051                mStateInfo.put(state, stateInfo);
1052            }
1053
1054            // Validate that we aren't adding the same state in two different hierarchies.
1055            if ((stateInfo.parentStateInfo != null) &&
1056                    (stateInfo.parentStateInfo != parentStateInfo)) {
1057                    throw new RuntimeException("state already added");
1058            }
1059            stateInfo.state = state;
1060            stateInfo.parentStateInfo = parentStateInfo;
1061            stateInfo.active = false;
1062            if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo);
1063            return stateInfo;
1064        }
1065
1066        /**
1067         * Constructor
1068         *
1069         * @param looper for dispatching messages
1070         * @param sm the hierarchical state machine
1071         */
1072        private SmHandler(Looper looper, StateMachine sm) {
1073            super(looper);
1074            mSm = sm;
1075
1076            addState(mHaltingState, null);
1077            addState(mQuittingState, null);
1078        }
1079
1080        /** @see StateMachine#setInitialState(State) */
1081        private final void setInitialState(State initialState) {
1082            if (mDbg) Log.d(TAG, "setInitialState: initialState" + initialState.getName());
1083            mInitialState = initialState;
1084        }
1085
1086        /** @see StateMachine#transitionTo(IState) */
1087        private final void transitionTo(IState destState) {
1088            mDestState = (State) destState;
1089            if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + mDestState.getName());
1090        }
1091
1092        /** @see StateMachine#deferMessage(Message) */
1093        private final void deferMessage(Message msg) {
1094            if (mDbg) Log.d(TAG, "deferMessage: msg=" + msg.what);
1095
1096            /* Copy the "msg" to "newMsg" as "msg" will be recycled */
1097            Message newMsg = obtainMessage();
1098            newMsg.copyFrom(msg);
1099
1100            mDeferredMessages.add(newMsg);
1101        }
1102
1103        /** @see StateMachine#deferMessage(Message) */
1104        private final void quit() {
1105            if (mDbg) Log.d(TAG, "quit:");
1106            sendMessage(obtainMessage(SM_QUIT_CMD, mQuitObj));
1107        }
1108
1109        /** @see StateMachine#isQuit(Message) */
1110        private final boolean isQuit(Message msg) {
1111            return (msg.what == SM_QUIT_CMD) && (msg.obj == mQuitObj);
1112        }
1113
1114        /** @see StateMachine#isDbg() */
1115        private final boolean isDbg() {
1116            return mDbg;
1117        }
1118
1119        /** @see StateMachine#setDbg(boolean) */
1120        private final void setDbg(boolean dbg) {
1121            mDbg = dbg;
1122        }
1123
1124        /** @see StateMachine#setProcessedMessagesSize(int) */
1125        private final void setProcessedMessagesSize(int maxSize) {
1126            mProcessedMessages.setSize(maxSize);
1127        }
1128
1129        /** @see StateMachine#getProcessedMessagesSize() */
1130        private final int getProcessedMessagesSize() {
1131            return mProcessedMessages.size();
1132        }
1133
1134        /** @see StateMachine#getProcessedMessagesCount() */
1135        private final int getProcessedMessagesCount() {
1136            return mProcessedMessages.count();
1137        }
1138
1139        /** @see StateMachine#getProcessedMessageInfo(int) */
1140        private final ProcessedMessageInfo getProcessedMessageInfo(int index) {
1141            return mProcessedMessages.get(index);
1142        }
1143
1144    }
1145
1146    private SmHandler mSmHandler;
1147    private HandlerThread mSmThread;
1148
1149    /**
1150     * Initialize.
1151     *
1152     * @param looper for this state machine
1153     * @param name of the state machine
1154     */
1155    private void initStateMachine(String name, Looper looper) {
1156        mName = name;
1157        mSmHandler = new SmHandler(looper, this);
1158    }
1159
1160    /**
1161     * Constructor creates a StateMachine with its own thread.
1162     *
1163     * @param name of the state machine
1164     */
1165    protected StateMachine(String name) {
1166        mSmThread = new HandlerThread(name);
1167        mSmThread.start();
1168        Looper looper = mSmThread.getLooper();
1169
1170        initStateMachine(name, looper);
1171    }
1172
1173    /**
1174     * Constructor creates an StateMachine using the looper.
1175     *
1176     * @param name of the state machine
1177     */
1178    protected StateMachine(String name, Looper looper) {
1179        initStateMachine(name, looper);
1180    }
1181
1182    /**
1183     * Add a new state to the state machine
1184     * @param state the state to add
1185     * @param parent the parent of state
1186     */
1187    protected final void addState(State state, State parent) {
1188        mSmHandler.addState(state, parent);
1189    }
1190
1191    /**
1192     * @return current message
1193     */
1194    protected final Message getCurrentMessage() {
1195        return mSmHandler.getCurrentMessage();
1196    }
1197
1198    /**
1199     * @return current state
1200     */
1201    protected final IState getCurrentState() {
1202        return mSmHandler.getCurrentState();
1203    }
1204
1205    /**
1206     * Add a new state to the state machine, parent will be null
1207     * @param state to add
1208     */
1209    protected final void addState(State state) {
1210        mSmHandler.addState(state, null);
1211    }
1212
1213    /**
1214     * Set the initial state. This must be invoked before
1215     * and messages are sent to the state machine.
1216     *
1217     * @param initialState is the state which will receive the first message.
1218     */
1219    protected final void setInitialState(State initialState) {
1220        mSmHandler.setInitialState(initialState);
1221    }
1222
1223    /**
1224     * transition to destination state. Upon returning
1225     * from processMessage the current state's exit will
1226     * be executed and upon the next message arriving
1227     * destState.enter will be invoked.
1228     *
1229     * @param destState will be the state that receives the next message.
1230     */
1231    protected final void transitionTo(IState destState) {
1232        mSmHandler.transitionTo(destState);
1233    }
1234
1235    /**
1236     * transition to halt state. Upon returning
1237     * from processMessage we will exit all current
1238     * states, execute the halting() method and then
1239     * all subsequent messages haltedProcessMesage
1240     * will be called.
1241     */
1242    protected final void transitionToHaltingState() {
1243        mSmHandler.transitionTo(mSmHandler.mHaltingState);
1244    }
1245
1246    /**
1247     * Defer this message until next state transition.
1248     * Upon transitioning all deferred messages will be
1249     * placed on the queue and reprocessed in the original
1250     * order. (i.e. The next state the oldest messages will
1251     * be processed first)
1252     *
1253     * @param msg is deferred until the next transition.
1254     */
1255    protected final void deferMessage(Message msg) {
1256        mSmHandler.deferMessage(msg);
1257    }
1258
1259
1260    /**
1261     * Called when message wasn't handled
1262     *
1263     * @param msg that couldn't be handled.
1264     */
1265    protected void unhandledMessage(Message msg) {
1266        if (mSmHandler.mDbg) Log.e(TAG, mName + " - unhandledMessage: msg.what=" + msg.what);
1267    }
1268
1269    /**
1270     * Called for any message that is received after
1271     * transitionToHalting is called.
1272     */
1273    protected void haltedProcessMessage(Message msg) {
1274    }
1275
1276    /**
1277     * This will be called once after handling a message that called
1278     * transitionToHalting. All subsequent messages will invoke
1279     * {@link StateMachine#haltedProcessMessage(Message)}
1280     */
1281    protected void halting() {
1282    }
1283
1284    /**
1285     * This will be called once after a quit message that was NOT handled by
1286     * the derived StateMachine. The StateMachine will stop and any subsequent messages will be
1287     * ignored. In addition, if this StateMachine created the thread, the thread will
1288     * be stopped after this method returns.
1289     */
1290    protected void quitting() {
1291    }
1292
1293    /**
1294     * @return the name
1295     */
1296    public final String getName() {
1297        return mName;
1298    }
1299
1300    /**
1301     * Set size of messages to maintain and clears all current messages.
1302     *
1303     * @param maxSize number of messages to maintain at anyone time.
1304     */
1305    public final void setProcessedMessagesSize(int maxSize) {
1306        mSmHandler.setProcessedMessagesSize(maxSize);
1307    }
1308
1309    /**
1310     * @return number of messages processed
1311     */
1312    public final int getProcessedMessagesSize() {
1313        return mSmHandler.getProcessedMessagesSize();
1314    }
1315
1316    /**
1317     * @return the total number of messages processed
1318     */
1319    public final int getProcessedMessagesCount() {
1320        return mSmHandler.getProcessedMessagesCount();
1321    }
1322
1323    /**
1324     * @return a processed message information
1325     */
1326    public final ProcessedMessageInfo getProcessedMessageInfo(int index) {
1327        return mSmHandler.getProcessedMessageInfo(index);
1328    }
1329
1330    /**
1331     * @return Handler
1332     */
1333    public final Handler getHandler() {
1334        return mSmHandler;
1335    }
1336
1337    /**
1338     * Get a message and set Message.target = this.
1339     *
1340     * @return message
1341     */
1342    public final Message obtainMessage()
1343    {
1344        return Message.obtain(mSmHandler);
1345    }
1346
1347    /**
1348     * Get a message and set Message.target = this and what
1349     *
1350     * @param what is the assigned to Message.what.
1351     * @return message
1352     */
1353    public final Message obtainMessage(int what) {
1354        return Message.obtain(mSmHandler, what);
1355    }
1356
1357    /**
1358     * Get a message and set Message.target = this,
1359     * what and obj.
1360     *
1361     * @param what is the assigned to Message.what.
1362     * @param obj is assigned to Message.obj.
1363     * @return message
1364     */
1365    public final Message obtainMessage(int what, Object obj)
1366    {
1367        return Message.obtain(mSmHandler, what, obj);
1368    }
1369
1370    /**
1371     * Get a message and set Message.target = this,
1372     * what, arg1 and arg2
1373     *
1374     * @param what  is assigned to Message.what
1375     * @param arg1  is assigned to Message.arg1
1376     * @param arg2  is assigned to Message.arg2
1377     * @return  A Message object from the global pool.
1378     */
1379    public final Message obtainMessage(int what, int arg1, int arg2)
1380    {
1381        return Message.obtain(mSmHandler, what, arg1, arg2);
1382    }
1383
1384    /**
1385     * Get a message and set Message.target = this,
1386     * what, arg1, arg2 and obj
1387     *
1388     * @param what  is assigned to Message.what
1389     * @param arg1  is assigned to Message.arg1
1390     * @param arg2  is assigned to Message.arg2
1391     * @param obj is assigned to Message.obj
1392     * @return  A Message object from the global pool.
1393     */
1394    public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
1395    {
1396        return Message.obtain(mSmHandler, what, arg1, arg2, obj);
1397    }
1398
1399    /**
1400     * Enqueue a message to this state machine.
1401     */
1402    public final void sendMessage(int what) {
1403        mSmHandler.sendMessage(obtainMessage(what));
1404    }
1405
1406    /**
1407     * Enqueue a message to this state machine.
1408     */
1409    public final void sendMessage(int what, Object obj) {
1410        mSmHandler.sendMessage(obtainMessage(what,obj));
1411    }
1412
1413    /**
1414     * Enqueue a message to this state machine.
1415     */
1416    public final void sendMessage(Message msg) {
1417        mSmHandler.sendMessage(msg);
1418    }
1419
1420    /**
1421     * Enqueue a message to this state machine after a delay.
1422     */
1423    public final void sendMessageDelayed(int what, long delayMillis) {
1424        mSmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
1425    }
1426
1427    /**
1428     * Enqueue a message to this state machine after a delay.
1429     */
1430    public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
1431        mSmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
1432    }
1433
1434    /**
1435     * Enqueue a message to this state machine after a delay.
1436     */
1437    public final void sendMessageDelayed(Message msg, long delayMillis) {
1438        mSmHandler.sendMessageDelayed(msg, delayMillis);
1439    }
1440
1441    /**
1442     * Enqueue a message to the front of the queue for this state machine.
1443     * Protected, may only be called by instances of StateMachine.
1444     */
1445    protected final void sendMessageAtFrontOfQueue(int what, Object obj) {
1446        mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
1447    }
1448
1449    /**
1450     * Enqueue a message to the front of the queue for this state machine.
1451     * Protected, may only be called by instances of StateMachine.
1452     */
1453    protected final void sendMessageAtFrontOfQueue(int what) {
1454        mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
1455    }
1456
1457    /**
1458     * Enqueue a message to the front of the queue for this state machine.
1459     * Protected, may only be called by instances of StateMachine.
1460     */
1461    protected final void sendMessageAtFrontOfQueue(Message msg) {
1462        mSmHandler.sendMessageAtFrontOfQueue(msg);
1463    }
1464
1465    /**
1466     * Removes a message from the message queue.
1467     * Protected, may only be called by instances of StateMachine.
1468     */
1469    protected final void removeMessages(int what) {
1470        mSmHandler.removeMessages(what);
1471    }
1472
1473    /**
1474     * Conditionally quit the looper and stop execution.
1475     *
1476     * This sends the SM_QUIT_MSG to the state machine and
1477     * if not handled by any state's processMessage then the
1478     * state machine will be stopped and no further messages
1479     * will be processed.
1480     */
1481    public final void quit() {
1482        mSmHandler.quit();
1483    }
1484
1485    /**
1486     * @return ture if msg is quit
1487     */
1488    protected final boolean isQuit(Message msg) {
1489        return mSmHandler.isQuit(msg);
1490    }
1491
1492    /**
1493     * @return if debugging is enabled
1494     */
1495    public boolean isDbg() {
1496        return mSmHandler.isDbg();
1497    }
1498
1499    /**
1500     * Set debug enable/disabled.
1501     *
1502     * @param dbg is true to enable debugging.
1503     */
1504    public void setDbg(boolean dbg) {
1505        mSmHandler.setDbg(dbg);
1506    }
1507
1508    /**
1509     * Start the state machine.
1510     */
1511    public void start() {
1512        /** Send the complete construction message */
1513        mSmHandler.completeConstruction();
1514    }
1515}
1516