1fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville/**
2fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Copyright (C) 2009 The Android Open Source Project
3fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
4fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
5fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * you may not use this file except in compliance with the License.
6fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * You may obtain a copy of the License at
7fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
8fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
9fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
10fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Unless required by applicable law or agreed to in writing, software
11fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
12fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * See the License for the specific language governing permissions and
14fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * limitations under the License.
15fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville */
16fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
17fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savillepackage com.android.internal.util;
18fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
19fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savilleimport android.os.Handler;
20fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savilleimport android.os.HandlerThread;
21fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savilleimport android.os.Looper;
22fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savilleimport android.os.Message;
23fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savilleimport android.util.Log;
24fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
25fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savilleimport java.util.ArrayList;
26fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savilleimport java.util.HashMap;
27fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
28fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville/**
29fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * {@hide}
30fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
31fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * A hierarchical state machine is a state machine which processes messages
32fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * and can have states arranged hierarchically. A state is a <code>HierarchicalState</code>
33fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * object and must implement <code>processMessage</code> and optionally <code>enter/exit/getName</code>.
34fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * The enter/exit methods are equivalent to the construction and destruction
35fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * in Object Oriented programming and are used to perform initialization and
36fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * cleanup of the state respectively. The <code>getName</code> method returns the
37fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * name of the state the default implementation returns the class name it may be
38fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * desirable to have this return the name of the state instance name instead.
39fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * In particular if a particular state class has multiple instances.
40fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
41fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * When a state machine is created <code>addState</code> is used to build the
42fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * hierarchy and <code>setInitialState</code> is used to identify which of these
43fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * is the initial state. After construction the programmer calls <code>start</code>
44fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * which initializes the state machine and calls <code>enter</code> for all of the initial
45fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * state's hierarchy, starting at its eldest parent. For example given the simple
46fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * state machine below after start is called mP1.enter will have been called and
47fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * then mS1.enter.
48fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville<code>
49fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mP1
50fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville       /   \
51fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville      mS2   mS1 ----> initial state
52fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville</code>
53fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * After the state machine is created and started, messages are sent to a state
54a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * machine using <code>sendMessage</code> and the messages are created using
55fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * <code>obtainMessage</code>. When the state machine receives a message the
56fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * current state's <code>processMessage</code> is invoked. In the above example
57fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * mS1.processMessage will be invoked first. The state may use <code>transitionTo</code>
58fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * to change the current state to a new state
59fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
60fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Each state in the state machine may have a zero or one parent states and if
61fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * a child state is unable to handle a message it may have the message processed
62a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * by its parent by returning false or NOT_HANDLED. If a message is never processed
63a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * <code>unhandledMessage</code> will be invoked to give one last chance for the state machine
64a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * to process the message.
65fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
66fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * When all processing is completed a state machine may choose to call
67fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * <code>transitionToHaltingState</code>. When the current <code>processingMessage</code>
68fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * returns the state machine will transfer to an internal <code>HaltingState</code>
69fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * and invoke <code>halting</code>. Any message subsequently received by the state
70fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * machine will cause <code>haltedProcessMessage</code> to be invoked.
71fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
721b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville * If it is desirable to completely stop the state machine call <code>quit</code>. This
731b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville * will exit the current state and its parent and then exit from the controlling thread
741b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville * and no further messages will be processed.
751b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville *
76fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * In addition to <code>processMessage</code> each <code>HierarchicalState</code> has
77fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * an <code>enter</code> method and <code>exit</exit> method which may be overridden.
78fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
79fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Since the states are arranged in a hierarchy transitioning to a new state
80fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * causes current states to be exited and new states to be entered. To determine
81fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * the list of states to be entered/exited the common parent closest to
82fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * the current state is found. We then exit from the current state and its
83fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * parent's up to but not including the common parent state and then enter all
84fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * of the new states below the common parent down to the destination state.
85fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * If there is no common parent all states are exited and then the new states
86fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * are entered.
87fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
88fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Two other methods that states can use are <code>deferMessage</code> and
89fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * <code>sendMessageAtFrontOfQueue</code>. The <code>sendMessageAtFrontOfQueue</code> sends
90fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * a message but places it on the front of the queue rather than the back. The
91fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * <code>deferMessage</code> causes the message to be saved on a list until a
92fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * transition is made to a new state. At which time all of the deferred messages
93fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * will be put on the front of the state machine queue with the oldest message
94fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * at the front. These will then be processed by the new current state before
95fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * any other messages that are on the queue or might be added later. Both of
96fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * these are protected and may only be invoked from within a state machine.
97fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
98a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * To illustrate some of these properties we'll use state machine with an 8
99fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * state hierarchy:
100fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville<code>
101fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville          mP0
102fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         /   \
103fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mP1   mS0
104fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville       /   \
105fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville      mS2   mS1
106fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     /  \    \
107fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    mS3  mS4  mS5  ---> initial state
108fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville</code>
109fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
110fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * After starting mS5 the list of active states is mP0, mP1, mS1 and mS5.
111fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * So the order of calling processMessage when a message is received is mS5,
112a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * mS1, mP1, mP0 assuming each processMessage indicates it can't handle this
113a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * message by returning false or NOT_HANDLED.
114fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
115fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Now assume mS5.processMessage receives a message it can handle, and during
116a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * the handling determines the machine should change states. It could call
117a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * transitionTo(mS4) and return true or HANDLED. Immediately after returning from
118fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * processMessage the state machine runtime will find the common parent,
119fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * which is mP1. It will then call mS5.exit, mS1.exit, mS2.enter and then
120fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * mS4.enter. The new list of active states is mP0, mP1, mS2 and mS4. So
121fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * when the next message is received mS4.processMessage will be invoked.
122fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
123a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * Now for some concrete examples, here is the canonical HelloWorld as an HSM.
124a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * It responds with "Hello World" being printed to the log for every message.
125fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville<code>
126fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savilleclass HelloWorld extends HierarchicalStateMachine {
127fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    Hsm1(String name) {
128fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        super(name);
129fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        addState(mState1);
130fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        setInitialState(mState1);
131fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
132fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
133fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static HelloWorld makeHelloWorld() {
134fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        HelloWorld hw = new HelloWorld("hw");
135fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        hw.start();
136fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return hw;
137fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
138fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
139fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    class State1 extends HierarchicalState {
1400d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public boolean processMessage(Message message) {
141fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "Hello World");
142a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville            return HANDLED;
143fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
144fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
145fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    State1 mState1 = new State1();
146fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville}
147fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
148fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savillevoid testHelloWorld() {
149fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    HelloWorld hw = makeHelloWorld();
150fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    hw.sendMessage(hw.obtainMessage());
151fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville}
152fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville</code>
153fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
154a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * A more interesting state machine is one with four states
155fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * with two independent parent states.
156fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville<code>
157fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mP1      mP2
158fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville       /   \
159fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville      mS2   mS1
160fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville</code>
161fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
162a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * Here is a description of this state machine using pseudo code.
163fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
164fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
165a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * state mP1 {
166a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      enter { log("mP1.enter"); }
167a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      exit { log("mP1.exit");  }
168a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      on msg {
169a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          CMD_2 {
170a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              send(CMD_3);
171a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              defer(msg);
172a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              transitonTo(mS2);
173a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              return HANDLED;
174a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          }
175a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          return NOT_HANDLED;
176a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      }
177fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * }
178fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
179a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * INITIAL
180a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * state mS1 parent mP1 {
181a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      enter { log("mS1.enter"); }
182a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      exit  { log("mS1.exit");  }
183a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      on msg {
184a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          CMD_1 {
185a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              transitionTo(mS1);
186a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              return HANDLED;
187a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          }
188a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          return NOT_HANDLED;
189a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      }
190a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * }
191fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
192a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * state mS2 parent mP1 {
193a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      enter { log("mS2.enter"); }
194a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      exit  { log("mS2.exit");  }
195a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      on msg {
196a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          CMD_2 {
197a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              send(CMD_4);
198a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              return HANDLED;
199a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          }
200a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          CMD_3 {
201a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              defer(msg);
202a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              transitionTo(mP2);
203a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              return HANDLED;
204a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          }
205a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          return NOT_HANDLED;
206a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      }
207a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * }
208fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
209a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * state mP2 {
210a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      enter {
211a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          log("mP2.enter");
212a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          send(CMD_5);
213a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      }
214a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      exit { log("mP2.exit"); }
215a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      on msg {
216a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          CMD_3, CMD_4 { return HANDLED; }
217a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          CMD_5 {
218a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              transitionTo(HaltingState);
219a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *              return HANDLED;
220a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          }
221a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *          return NOT_HANDLED;
222a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville *      }
223a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville * }
224fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
225fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * The implementation is below and also in HierarchicalStateMachineTest:
226fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville<code>
227fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savilleclass Hsm1 extends HierarchicalStateMachine {
228fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private static final String TAG = "hsm1";
229fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
230fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static final int CMD_1 = 1;
231fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static final int CMD_2 = 2;
232fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static final int CMD_3 = 3;
233fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static final int CMD_4 = 4;
234fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static final int CMD_5 = 5;
235fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
236fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static Hsm1 makeHsm1() {
237fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Log.d(TAG, "makeHsm1 E");
238fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Hsm1 sm = new Hsm1("hsm1");
239fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        sm.start();
240fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Log.d(TAG, "makeHsm1 X");
241fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return sm;
242fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
243fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
244fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    Hsm1(String name) {
245fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        super(name);
246fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Log.d(TAG, "ctor E");
247fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
248fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        // Add states, use indentation to show hierarchy
249fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        addState(mP1);
250fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            addState(mS1, mP1);
251fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            addState(mS2, mP1);
252fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        addState(mP2);
253fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
254fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        // Set the initial state
255fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        setInitialState(mS1);
256fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Log.d(TAG, "ctor X");
257fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
258fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
259fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    class P1 extends HierarchicalState {
2600d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public void enter() {
261fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mP1.enter");
262fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
2630d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public boolean processMessage(Message message) {
264fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            boolean retVal;
265fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mP1.processMessage what=" + message.what);
266fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            switch(message.what) {
267fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case CMD_2:
268fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                // CMD_2 will arrive in mS2 before CMD_3
269fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                sendMessage(obtainMessage(CMD_3));
270fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                deferMessage(message);
271fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                transitionTo(mS2);
272a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville                retVal = HANDLED;
273fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
274fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            default:
275fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                // Any message we don't understand in this state invokes unhandledMessage
276a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville                retVal = NOT_HANDLED;
277fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
278fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
279fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return retVal;
280fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
2810d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public void exit() {
282fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mP1.exit");
283fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
284fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
285fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
286fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    class S1 extends HierarchicalState {
2870d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public void enter() {
288fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mS1.enter");
289fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
2900d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public boolean processMessage(Message message) {
291fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "S1.processMessage what=" + message.what);
292fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (message.what == CMD_1) {
293fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                // Transition to ourself to show that enter/exit is called
294fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                transitionTo(mS1);
295a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville                return HANDLED;
296fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            } else {
297fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                // Let parent process all other messages
298a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville                return NOT_HANDLED;
299fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
300fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
3010d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public void exit() {
302fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mS1.exit");
303fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
304fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
305fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
306fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    class S2 extends HierarchicalState {
3070d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public void enter() {
308fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mS2.enter");
309fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
3100d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public boolean processMessage(Message message) {
311fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            boolean retVal;
312fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mS2.processMessage what=" + message.what);
313fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            switch(message.what) {
314fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case(CMD_2):
315fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                sendMessage(obtainMessage(CMD_4));
316a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville                retVal = HANDLED;
317fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
318fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case(CMD_3):
319fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                deferMessage(message);
320fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                transitionTo(mP2);
321a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville                retVal = HANDLED;
322fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
323fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            default:
324a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville                retVal = NOT_HANDLED;
325fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
326fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
327fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return retVal;
328fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
3290d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public void exit() {
330fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mS2.exit");
331fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
332fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
333fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
334fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    class P2 extends HierarchicalState {
3350d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public void enter() {
336fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mP2.enter");
337fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            sendMessage(obtainMessage(CMD_5));
338fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
3390d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public boolean processMessage(Message message) {
340fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "P2.processMessage what=" + message.what);
341fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            switch(message.what) {
342fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case(CMD_3):
343fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
344fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case(CMD_4):
345fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
346fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case(CMD_5):
347fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                transitionToHaltingState();
348fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
349fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
350a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville            return HANDLED;
351fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
3520d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato        &#64;Override public void exit() {
353fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mP2.exit");
354fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
355fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
356fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
3570d903bcd780a927b8f9cdc8e178afdf85858ba0aJoe Onorato    &#64;Override
358a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville    void halting() {
359fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Log.d(TAG, "halting");
360fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        synchronized (this) {
361fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            this.notifyAll();
362fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
363fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
364fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
365fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    P1 mP1 = new P1();
366fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    S1 mS1 = new S1();
367fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    S2 mS2 = new S2();
368fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    P2 mP2 = new P2();
369fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville}
370fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville</code>
371fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
372fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * If this is executed by sending two messages CMD_1 and CMD_2
373fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * (Note the synchronize is only needed because we use hsm.wait())
374fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
375fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Hsm1 hsm = makeHsm1();
376fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * synchronize(hsm) {
377fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      hsm.sendMessage(obtainMessage(hsm.CMD_1));
378fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      hsm.sendMessage(obtainMessage(hsm.CMD_2));
379fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      try {
380fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *           // wait for the messages to be handled
381fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *           hsm.wait();
382fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      } catch (InterruptedException e) {
383fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *           Log.e(TAG, "exception while waiting " + e.getMessage());
384fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      }
385fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * }
386fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
387fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
388fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * The output is:
389fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
390fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): makeHsm1 E
391fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): ctor E
392fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): ctor X
393fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP1.enter
394fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.enter
395fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): makeHsm1 X
396fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.processMessage what=1
397fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.exit
398fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.enter
399fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.processMessage what=2
400fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP1.processMessage what=2
401fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.exit
402fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS2.enter
403fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS2.processMessage what=2
404fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS2.processMessage what=3
405fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS2.exit
406fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP1.exit
407fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP2.enter
408fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP2.processMessage what=3
409fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP2.processMessage what=4
410fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP2.processMessage what=5
411fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP2.exit
412fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): halting
413fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
414fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville */
415fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savillepublic class HierarchicalStateMachine {
416fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
417fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private static final String TAG = "HierarchicalStateMachine";
418fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private String mName;
419fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
420a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville    /** Message.what value when quitting */
4211b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    public static final int HSM_QUIT_CMD = -1;
4221b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
423a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville    /** Message.what value when initializing */
424a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville    public static final int HSM_INIT_CMD = -1;
425a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville
426a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville    /**
427a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville     * Convenience constant that maybe returned by processMessage
428a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville     * to indicate the the message was processed and is not to be
429a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville     * processed by parent states
430a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville     */
431a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville    public static final boolean HANDLED = true;
432a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville
433a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville    /**
434a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville     * Convenience constant that maybe returned by processMessage
435a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville     * to indicate the the message was NOT processed and is to be
436a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville     * processed by parent states
437a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville     */
438a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville    public static final boolean NOT_HANDLED = false;
439a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville
440fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private static class HsmHandler extends Handler {
441fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
442fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The debug flag */
443fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private boolean mDbg = false;
444fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
4451b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /** The quit object */
4461b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private static final Object mQuitObj = new Object();
4471b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
448a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville        /** The initialization message */
449a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville        private static final Message mInitMsg = null;
450a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville
451a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville        /** The current message */
452a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville        private Message mMsg;
453a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville
454fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** A list of messages that this state machine has processed */
455fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private ProcessedMessages mProcessedMessages = new ProcessedMessages();
456fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
457fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** true if construction of the state machine has not been completed */
458fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private boolean mIsConstructionCompleted;
459fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
460fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** Stack used to manage the current hierarchy of states */
461fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private StateInfo mStateStack[];
462fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
463fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** Top of mStateStack */
464fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private int mStateStackTopIndex = -1;
465fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
466fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** A temporary stack used to manage the state stack */
467fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private StateInfo mTempStateStack[];
468fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
469fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The top of the mTempStateStack */
470fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private int mTempStateStackCount;
471fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
472fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** State used when state machine is halted */
473fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HaltingState mHaltingState = new HaltingState();
474fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
4751b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /** State used when state machine is quitting */
4761b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private QuittingState mQuittingState = new QuittingState();
4771b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
478fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** Reference to the HierarchicalStateMachine */
479fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HierarchicalStateMachine mHsm;
480fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
481fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
482fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Information about a state.
483fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Used to maintain the hierarchy.
484fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
485fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private class StateInfo {
486fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /** The state */
487fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            HierarchicalState state;
488fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
489fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /** The parent of this state, null if there is no parent */
490fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo parentStateInfo;
491fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
492fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /** True when the state has been entered and on the stack */
493fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            boolean active;
494fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
495fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
496fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Convert StateInfo to string
497fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
498fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            @Override
499fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            public String toString() {
500fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                return "state=" + state.getName() + ",active=" + active
501fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                        + ",parent=" + ((parentStateInfo == null) ?
502fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                                        "null" : parentStateInfo.state.getName());
503fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
504fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
505fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
506fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The map of all of the states in the state machine */
507fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HashMap<HierarchicalState, StateInfo> mStateInfo =
508fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            new HashMap<HierarchicalState, StateInfo>();
509fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
510fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The initial state that will process the first message */
511fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HierarchicalState mInitialState;
512fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
513fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The destination state when transitionTo has been invoked */
514fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HierarchicalState mDestState;
515fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
516fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The list of deferred messages */
517fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private ArrayList<Message> mDeferredMessages = new ArrayList<Message>();
518fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
519fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
520fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * State entered when transitionToHaltingState is called.
521fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
522fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private class HaltingState extends HierarchicalState {
523fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            @Override
524fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            public boolean processMessage(Message msg) {
525fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mHsm.haltedProcessMessage(msg);
526fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                return true;
527fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
528fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
529fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
530fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
5311b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville         * State entered when a valid quit message is handled.
5321b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville         */
5331b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private class QuittingState extends HierarchicalState {
5341b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            @Override
5351b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            public boolean processMessage(Message msg) {
536a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville                return NOT_HANDLED;
5371b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            }
5381b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        }
5391b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
5401b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /**
541fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Handle messages sent to the state machine by calling
542fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * the current state's processMessage. It also handles
543fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * the enter/exit calls and placing any deferred messages
544fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * back onto the queue when transitioning to a new state.
545fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
546fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override
547fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        public final void handleMessage(Message msg) {
548fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "handleMessage: E msg.what=" + msg.what);
549fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
550a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville            /** Save the current message */
551a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville            mMsg = msg;
552a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville
553fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
554fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Check that construction was completed
555fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
556fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (!mIsConstructionCompleted) {
557fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.e(TAG, "The start method not called, ignore msg: " + msg);
558fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                return;
559fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
560fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
561fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
562e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * Process the message abiding by the hierarchical semantics
563e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * and perform any requested transitions.
564fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
565fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            processMsg(msg);
566e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            performTransitions();
567fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
568e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            if (mDbg) Log.d(TAG, "handleMessage: X");
569e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville        }
570e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville
571e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville        /**
572e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville         * Do any transitions
573e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville         */
574e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville        private void performTransitions() {
575fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
576fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * If transitionTo has been called, exit and then enter
577e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * the appropriate states. We loop on this to allow
578e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * enter and exit methods to use transitionTo.
579fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
580e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            HierarchicalState destState = null;
581e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            while (mDestState != null) {
582fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "handleMessage: new destination call exit");
583fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
584fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                /**
585e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                 * Save mDestState locally and set to null
586e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                 * to know if enter/exit use transitionTo.
587e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                 */
588e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                destState = mDestState;
589e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                mDestState = null;
590e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville
591e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                /**
592fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * Determine the states to exit and enter and return the
593fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * common ancestor state of the enter/exit states. Then
594fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * invoke the exit methods then the enter methods.
595fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 */
596e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
597fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                invokeExitMethods(commonStateInfo);
598fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                int stateStackEnteringIndex = moveTempStateStackToStateStack();
599fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                invokeEnterMethods(stateStackEnteringIndex);
600fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
601fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
602fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                /**
603fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * Since we have transitioned to a new state we need to have
604fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * any deferred messages moved to the front of the message queue
605fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * so they will be processed before any other messages in the
606fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * message queue.
607fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 */
608fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                moveDeferredMessageAtFrontOfQueue();
609e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            }
610fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
611e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            /**
612e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * After processing all transitions check and
613e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * see if the last transition was to quit or halt.
614e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             */
615e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            if (destState != null) {
616e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                if (destState == mQuittingState) {
617e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                    /**
618e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     * We are quitting so ignore all messages.
619e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     */
6201b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    mHsm.quitting();
6211b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    if (mHsm.mHsmThread != null) {
6221b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                        // If we made the thread then quit looper
6231b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                        getLooper().quit();
6241b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    }
625e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                } else if (destState == mHaltingState) {
626e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                    /**
627e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     * Call halting() if we've transitioned to the halting
628e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     * state. All subsequent messages will be processed in
629e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     * in the halting state which invokes haltedProcessMessage(msg);
630e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     */
631fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    mHsm.halting();
632fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
633fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
634fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
635fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
636fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
637fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Complete the construction of the state machine.
638fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
639fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void completeConstruction() {
640fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "completeConstruction: E");
641fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
642fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
643fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Determine the maximum depth of the state hierarchy
644fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * so we can allocate the state stacks.
645fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
646fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int maxDepth = 0;
647fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (StateInfo si : mStateInfo.values()) {
648fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                int depth = 0;
649fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                for (StateInfo i = si; i != null; depth++) {
650fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    i = i.parentStateInfo;
651fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
652fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (maxDepth < depth) {
653fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    maxDepth = depth;
654fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
655fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
656fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "completeConstruction: maxDepth=" + maxDepth);
657fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
658fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mStateStack = new StateInfo[maxDepth];
659fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mTempStateStack = new StateInfo[maxDepth];
660fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            setupInitialStateStack();
661fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
662fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
663fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Construction is complete call all enter methods
664fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * starting at the first entry.
665fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
666fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mIsConstructionCompleted = true;
667a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville            mMsg = obtainMessage(HSM_INIT_CMD);
668fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            invokeEnterMethods(0);
669fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
670e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            /**
671e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * Perform any transitions requested by the enter methods
672e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             */
673e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            performTransitions();
674e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville
675fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "completeConstruction: X");
676fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
677fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
678fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
679fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Process the message. If the current state doesn't handle
680fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * it, call the states parent and so on. If it is never handled then
681fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * call the state machines unhandledMessage method.
682fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
683fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void processMsg(Message msg) {
684fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
685fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
686fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
687fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
688fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            while (!curStateInfo.state.processMessage(msg)) {
689fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                /**
690fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * Not processed
691fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 */
692fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curStateInfo = curStateInfo.parentStateInfo;
693fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (curStateInfo == null) {
694fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    /**
695fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                     * No parents left so it's not handled
696fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                     */
697fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    mHsm.unhandledMessage(msg);
6981b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    if (isQuit(msg)) {
6991b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                        transitionTo(mQuittingState);
7001b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    }
701fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    break;
702fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
703fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) {
704fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
705fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
706fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
707fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
708fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
709fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Record that we processed the message
710fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
711fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (curStateInfo != null) {
712fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                HierarchicalState orgState = mStateStack[mStateStackTopIndex].state;
713fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mProcessedMessages.add(msg, curStateInfo.state, orgState);
714fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            } else {
715fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mProcessedMessages.add(msg, null, null);
716fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
717fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
718fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
719fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
720fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Call the exit method for each state from the top of stack
721fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * up to the common ancestor state.
722fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
723fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void invokeExitMethods(StateInfo commonStateInfo) {
724fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            while ((mStateStackTopIndex >= 0) &&
725fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    (mStateStack[mStateStackTopIndex] != commonStateInfo)) {
726fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                HierarchicalState curState = mStateStack[mStateStackTopIndex].state;
727fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "invokeExitMethods: " + curState.getName());
728fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curState.exit();
729fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[mStateStackTopIndex].active = false;
730fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStackTopIndex -= 1;
731fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
732fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
733fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
734fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
735fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Invoke the enter method starting at the entering index to top of state stack
736fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
737fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void invokeEnterMethods(int stateStackEnteringIndex) {
738fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
739fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());
740fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[i].state.enter();
741fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[i].active = true;
742fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
743fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
744fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
745fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
746fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Move the deferred message to the front of the message queue.
747fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
748fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void moveDeferredMessageAtFrontOfQueue() {
749fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
750fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * The oldest messages on the deferred list must be at
751fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * the front of the queue so start at the back, which
752fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * as the most resent message and end with the oldest
753fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * messages at the front of the queue.
754fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
755fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (int i = mDeferredMessages.size() - 1; i >= 0; i-- ) {
756fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Message curMsg = mDeferredMessages.get(i);
757fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "moveDeferredMessageAtFrontOfQueue; what=" + curMsg.what);
758fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                sendMessageAtFrontOfQueue(curMsg);
759fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
760fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDeferredMessages.clear();
761fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
762fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
763fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
764fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Move the contents of the temporary stack to the state stack
765fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * reversing the order of the items on the temporary stack as
766fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * they are moved.
767fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
768fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return index into mStateState where entering needs to start
769fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
770fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final int moveTempStateStackToStateStack() {
771fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int startingIndex = mStateStackTopIndex + 1;
772fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int i = mTempStateStackCount - 1;
773fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int j = startingIndex;
774fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            while (i >= 0) {
775fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "moveTempStackToStateStack: i=" + i + ",j=" + j);
776fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[j] = mTempStateStack[i];
777fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                j += 1;
778fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                i -= 1;
779fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
780fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
781fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mStateStackTopIndex = j - 1;
782fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
783fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "moveTempStackToStateStack: X mStateStackTop="
784fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                      + mStateStackTopIndex + ",startingIndex=" + startingIndex
785fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                      + ",Top=" + mStateStack[mStateStackTopIndex].state.getName());
786fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
787fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return startingIndex;
788fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
789fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
790fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
791fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Setup the mTempStateStack with the states we are going to enter.
792fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
793fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * This is found by searching up the destState's ancestors for a
794fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * state that is already active i.e. StateInfo.active == true.
795fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * The destStae and all of its inactive parents will be on the
796fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * TempStateStack as the list of states to enter.
797fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
798fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return StateInfo of the common ancestor for the destState and
799fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * current state or null if there is no common parent.
800fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
801fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final StateInfo setupTempStateStackWithStatesToEnter(HierarchicalState destState) {
802fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
803fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Search up the parent list of the destination state for an active
804fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * state. Use a do while() loop as the destState must always be entered
805fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * even if it is active. This can happen if we are exiting/entering
806fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * the current state.
807fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
808fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mTempStateStackCount = 0;
809fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo curStateInfo = mStateInfo.get(destState);
810fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            do {
811fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mTempStateStack[mTempStateStackCount++] = curStateInfo;
812fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curStateInfo = curStateInfo.parentStateInfo;
813fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            } while ((curStateInfo != null) && !curStateInfo.active);
814fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
815fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
816fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "setupTempStateStackWithStatesToEnter: X mTempStateStackCount="
817fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                      + mTempStateStackCount + ",curStateInfo: " + curStateInfo);
818fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
819fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return curStateInfo;
820fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
821fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
822fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
823fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Initialize StateStack to mInitialState.
824fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
825fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setupInitialStateStack() {
826fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
827fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "setupInitialStateStack: E mInitialState="
828fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    + mInitialState.getName());
829fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
830fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
831fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo curStateInfo = mStateInfo.get(mInitialState);
832fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
833fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mTempStateStack[mTempStateStackCount] = curStateInfo;
834fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curStateInfo = curStateInfo.parentStateInfo;
835fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
836fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
837fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            // Empty the StateStack
838fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mStateStackTopIndex = -1;
839fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
840fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            moveTempStateStackToStateStack();
841fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
842fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
843fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
844a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville         * @return current message
845a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville         */
846a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville        private final Message getCurrentMessage() {
847a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville            return mMsg;
848a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville        }
849a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville
850a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville        /**
851fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return current state
852fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
853fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final HierarchicalState getCurrentState() {
854fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mStateStack[mStateStackTopIndex].state;
855fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
856fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
857fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
858fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Add a new state to the state machine. Bottom up addition
859fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * of states is allowed but the same state may only exist
860fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * in one hierarchy.
861fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
862fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param state the state to add
863fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param parent the parent of state
864fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return stateInfo for this state
865fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
866fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final StateInfo addState(HierarchicalState state, HierarchicalState parent) {
867fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
868fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "addStateInternal: E state=" + state.getName()
869fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                        + ",parent=" + ((parent == null) ? "" : parent.getName()));
870fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
871fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo parentStateInfo = null;
872fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (parent != null) {
873fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                parentStateInfo = mStateInfo.get(parent);
874fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (parentStateInfo == null) {
875fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    // Recursively add our parent as it's not been added yet.
876fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    parentStateInfo = addState(parent, null);
877fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
878fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
879fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo stateInfo = mStateInfo.get(state);
880fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (stateInfo == null) {
881fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                stateInfo = new StateInfo();
882fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateInfo.put(state, stateInfo);
883fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
884fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
885fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            // Validate that we aren't adding the same state in two different hierarchies.
886fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if ((stateInfo.parentStateInfo != null) &&
887fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    (stateInfo.parentStateInfo != parentStateInfo)) {
888fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    throw new RuntimeException("state already added");
889fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
890fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            stateInfo.state = state;
891fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            stateInfo.parentStateInfo = parentStateInfo;
892fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            stateInfo.active = false;
893fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo);
894fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return stateInfo;
895fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
896fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
897fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
898fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Constructor
899fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
900fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param looper for dispatching messages
901fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param hsm the hierarchical state machine
902fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
903fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HsmHandler(Looper looper, HierarchicalStateMachine hsm) {
904fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            super(looper);
905fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mHsm = hsm;
906fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
907fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            addState(mHaltingState, null);
9081b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            addState(mQuittingState, null);
909fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
910fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
911fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#setInitialState(HierarchicalState) */
912fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setInitialState(HierarchicalState initialState) {
913fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "setInitialState: initialState" + initialState.getName());
914fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mInitialState = initialState;
915fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
916fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
917fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#transitionTo(HierarchicalState) */
918fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void transitionTo(HierarchicalState destState) {
919fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + destState.getName());
920fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDestState = destState;
921fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
922fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
923fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#deferMessage(Message) */
924fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void deferMessage(Message msg) {
925fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "deferMessage: msg=" + msg.what);
926fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
927fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /* Copy the "msg" to "newMsg" as "msg" will be recycled */
928fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Message newMsg = obtainMessage();
929fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            newMsg.copyFrom(msg);
930fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
931fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDeferredMessages.add(newMsg);
932fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
933fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
9341b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /** @see HierarchicalStateMachine#deferMessage(Message) */
9351b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private final void quit() {
9361b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            if (mDbg) Log.d(TAG, "quit:");
9371b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            sendMessage(obtainMessage(HSM_QUIT_CMD, mQuitObj));
9381b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        }
9391b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
9401b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /** @see HierarchicalStateMachine#isQuit(Message) */
9411b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private final boolean isQuit(Message msg) {
9421b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            return (msg.what == HSM_QUIT_CMD) && (msg.obj == mQuitObj);
9431b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        }
9441b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
945fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#isDbg() */
946fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final boolean isDbg() {
947fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mDbg;
948fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
949fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
950fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#setDbg(boolean) */
951fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setDbg(boolean dbg) {
952fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDbg = dbg;
953fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
954fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
955fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#setProcessedMessagesSize(int) */
956fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setProcessedMessagesSize(int maxSize) {
957fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mProcessedMessages.setSize(maxSize);
958fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
959fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
960fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#getProcessedMessagesSize() */
961fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final int getProcessedMessagesSize() {
962fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mProcessedMessages.size();
963fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
964fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
965fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#getProcessedMessagesCount() */
966fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final int getProcessedMessagesCount() {
967fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mProcessedMessages.count();
968fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
969fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
970fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#getProcessedMessage(int) */
971fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final ProcessedMessages.Info getProcessedMessage(int index) {
972fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mProcessedMessages.get(index);
973fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
974fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
975fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
976fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
977fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private HsmHandler mHsmHandler;
978fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private HandlerThread mHsmThread;
979fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
980fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
981fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Initialize.
982fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
983fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param looper for this state machine
984fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param name of the state machine
985fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
986f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville    private void initStateMachine(String name, Looper looper) {
987fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mName = name;
988fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler = new HsmHandler(looper, this);
989fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
990fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
991fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
992fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Constructor creates an HSM with its own thread.
993fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
994fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param name of the state machine
995fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
996fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected HierarchicalStateMachine(String name) {
997fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmThread = new HandlerThread(name);
998fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmThread.start();
999fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Looper looper = mHsmThread.getLooper();
1000fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1001f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville        initStateMachine(name, looper);
1002fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1003fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1004fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1005fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Constructor creates an HSMStateMachine using the looper.
1006fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1007fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param name of the state machine
1008fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1009f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville    protected HierarchicalStateMachine(String name, Looper looper) {
1010f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville        initStateMachine(name, looper);
1011fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1012fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1013fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1014fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Add a new state to the state machine
1015fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param state the state to add
1016fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param parent the parent of state
1017fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1018fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void addState(HierarchicalState state, HierarchicalState parent) {
1019fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.addState(state, parent);
1020fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1021a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville
1022a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville    /**
1023a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville     * @return current message
1024a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville     */
1025a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville    protected final Message getCurrentMessage() {
1026a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville        return mHsmHandler.getCurrentMessage();
1027a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville    }
1028a4f3bec29c85ef9e0d07fdd551fe3c50f28b9adcWink Saville
1029fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1030fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return current state
1031fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1032fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final HierarchicalState getCurrentState() {
1033fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getCurrentState();
1034fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1035fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1036fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1037fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Add a new state to the state machine, parent will be null
1038fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param state to add
1039fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1040fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void addState(HierarchicalState state) {
1041fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.addState(state, null);
1042fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1043fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1044fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1045fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Set the initial state. This must be invoked before
1046fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * and messages are sent to the state machine.
1047fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1048fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param initialState is the state which will receive the first message.
1049fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1050fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void setInitialState(HierarchicalState initialState) {
1051fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.setInitialState(initialState);
1052fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1053fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1054fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1055fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * transition to destination state. Upon returning
1056fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * from processMessage the current state's exit will
1057fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * be executed and upon the next message arriving
1058fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * destState.enter will be invoked.
1059fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1060fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param destState will be the state that receives the next message.
1061fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1062fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void transitionTo(HierarchicalState destState) {
1063fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.transitionTo(destState);
1064fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1065fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1066fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1067fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * transition to halt state. Upon returning
1068fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * from processMessage we will exit all current
1069fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * states, execute the halting() method and then
1070fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * all subsequent messages haltedProcessMesage
1071fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * will be called.
1072fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1073fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void transitionToHaltingState() {
1074fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.transitionTo(mHsmHandler.mHaltingState);
1075fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1076fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1077fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1078fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Defer this message until next state transition.
1079fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Upon transitioning all deferred messages will be
1080fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * placed on the queue and reprocessed in the original
1081fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * order. (i.e. The next state the oldest messages will
1082fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * be processed first)
1083fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1084fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param msg is deferred until the next transition.
1085fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1086fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void deferMessage(Message msg) {
1087fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.deferMessage(msg);
1088fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1089fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1090fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1091fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1092fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Called when message wasn't handled
1093fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1094fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param msg that couldn't be handled.
1095fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1096fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected void unhandledMessage(Message msg) {
1097431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato        if (false) {
1098431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato            Log.e(TAG, mName + " - unhandledMessage: msg.what=" + msg.what);
1099431bb2269532f2514861b908d5fafda8fa64da79Joe Onorato        }
1100fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1101fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1102fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1103fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Called for any message that is received after
1104fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * transitionToHalting is called.
1105fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1106fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected void haltedProcessMessage(Message msg) {
1107fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1108fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1109fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1110fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Called after the message that called transitionToHalting
1111fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * is called and should be overridden by StateMachine's that
1112fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * call transitionToHalting.
1113fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1114fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected void halting() {
1115fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1116fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1117fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
11181b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * Called after the quitting message was NOT handled and
11191b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * just before the quit actually occurs.
11201b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     */
11211b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    protected void quitting() {
11221b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    }
11231b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
11241b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    /**
1125fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return the name
1126fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1127fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final String getName() {
1128fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mName;
1129fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1130fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1131fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1132fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Set size of messages to maintain and clears all current messages.
1133fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1134fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param maxSize number of messages to maintain at anyone time.
1135fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1136fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final void setProcessedMessagesSize(int maxSize) {
1137fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.setProcessedMessagesSize(maxSize);
1138fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1139fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1140fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1141fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return number of messages processed
1142fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1143fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final int getProcessedMessagesSize() {
1144fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getProcessedMessagesSize();
1145fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1146fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1147fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1148fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return the total number of messages processed
1149fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1150fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final int getProcessedMessagesCount() {
1151fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getProcessedMessagesCount();
1152fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1153fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1154fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1155fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return a processed message
1156fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1157fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final ProcessedMessages.Info getProcessedMessage(int index) {
1158fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getProcessedMessage(index);
1159fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1160fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1161fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1162fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return Handler
1163fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1164fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Handler getHandler() {
1165fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler;
1166fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1167fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1168fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1169fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Get a message and set Message.target = this.
1170fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1171fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return message
1172fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1173fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Message obtainMessage()
1174fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    {
1175fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return Message.obtain(mHsmHandler);
1176fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1177fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1178fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1179fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Get a message and set Message.target = this and what
1180fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1181fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param what is the assigned to Message.what.
1182fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return message
1183fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1184fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Message obtainMessage(int what) {
1185fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return Message.obtain(mHsmHandler, what);
1186fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1187fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1188fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1189fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Get a message and set Message.target = this,
1190fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * what and obj.
1191fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1192fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param what is the assigned to Message.what.
1193fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param obj is assigned to Message.obj.
1194fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return message
1195fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1196fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Message obtainMessage(int what, Object obj)
1197fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    {
1198fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return Message.obtain(mHsmHandler, what, obj);
1199fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1200fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
120191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
120291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine.
120391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
120491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessage(int what) {
120591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessage(obtainMessage(what));
120691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
120791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
120891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
120991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine.
121091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
121191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessage(int what, Object obj) {
121291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessage(obtainMessage(what,obj));
121391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
121491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
1215fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1216fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Enqueue a message to this state machine.
1217fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1218fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final void sendMessage(Message msg) {
1219fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.sendMessage(msg);
1220fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1221fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1222fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1223fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Enqueue a message to this state machine after a delay.
1224fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
122591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessageDelayed(int what, long delayMillis) {
122691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
122791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
122891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
122991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
123091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine after a delay.
123191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
123291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
123391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
123491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
123591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
123691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
123791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine after a delay.
123891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
1239fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final void sendMessageDelayed(Message msg, long delayMillis) {
1240fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.sendMessageDelayed(msg, delayMillis);
1241fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1242fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1243fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1244fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Enqueue a message to the front of the queue for this state machine.
1245fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Protected, may only be called by instances of HierarchicalStateMachine.
1246fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
124791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    protected final void sendMessageAtFrontOfQueue(int what, Object obj) {
124891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
124991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
125091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
125191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
125291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to the front of the queue for this state machine.
125391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Protected, may only be called by instances of HierarchicalStateMachine.
125491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
125591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    protected final void sendMessageAtFrontOfQueue(int what) {
125691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
125791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
125891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
125991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
126091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to the front of the queue for this state machine.
126191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Protected, may only be called by instances of HierarchicalStateMachine.
126291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
1263fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void sendMessageAtFrontOfQueue(Message msg) {
1264fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.sendMessageAtFrontOfQueue(msg);
1265fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1266fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1267fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
12681b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * Conditionally quit the looper and stop execution.
12691b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     *
12701b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * This sends the HSM_QUIT_MSG to the state machine and
12711b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * if not handled by any state's processMessage then the
12721b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * state machine will be stopped and no further messages
12731b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * will be processed.
12741b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     */
12751b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    public final void quit() {
12761b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        mHsmHandler.quit();
12771b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    }
12781b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
12791b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    /**
12801b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * @return ture if msg is quit
12811b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     */
12821b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    protected final boolean isQuit(Message msg) {
12831b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        return mHsmHandler.isQuit(msg);
12841b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    }
12851b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
12861b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    /**
1287fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return if debugging is enabled
1288fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1289fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public boolean isDbg() {
1290fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.isDbg();
1291fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1292fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1293fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1294fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Set debug enable/disabled.
1295fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1296fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param dbg is true to enable debugging.
1297fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1298fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public void setDbg(boolean dbg) {
1299fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.setDbg(dbg);
1300fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1301fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1302fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1303fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Start the state machine.
1304fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1305fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public void start() {
1306fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** Send the complete construction message */
1307fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.completeConstruction();
1308fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1309fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville}
1310