HierarchicalStateMachine.java revision 91fbd56757751a7aca8ef2b4d936e587509e6eef
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
54fc5b4802a544b6ca304aa7e58a26018ef714d233Wink 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
62fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * by its parent by returning false. If a message is never processed <code>unhandledMessage</code>
63fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * will be invoked to give one last chance for the state machine to process
64fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * 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 *
98fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * To illustrate some of these properties we'll use state machine with 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,
112fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * mS1, mP1, mP0 assuming each processMessage  indicates it can't handle this
113fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * message by returning false.
114fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
115fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Now assume mS5.processMessage receives a message it can handle, and during
116fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * the handling determines the machine should changes states. It would call
117fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * transitionTo(mS4) and return true. 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 *
123fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * To assist in describing an HSM a simple grammar has been created which
124fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * is informally defined here and a formal EBNF description is at the end
125fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * of the class comment.
126fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
127fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * An HSM starts with the name and includes a set of hierarchical states.
128fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * A state is preceeded by one or more plus signs (+), to indicate its
129fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * depth and a hash (#) if its the initial state. Child states follow their
130fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * parents and have one more plus sign then their parent. Inside a state
131fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * are a series of messages, the actions they perform and if the processing
132fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * is complete ends with a period (.). If processing isn't complete and
133fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * the parent should process the message it ends with a caret (^). The
134fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * actions include send a message ($MESSAGE), defer a message (%MESSAGE),
135fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * transition to a new state (>MESSAGE) and an if statement
136fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * (if ( expression ) { list of actions }.)
137fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
138fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * The Hsm HelloWorld could documented as:
139fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
140fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * HelloWorld {
141fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   + # mState1.
142fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * }
143fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
144fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * and interpreted as HSM HelloWorld:
145fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
146fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * mState1 a root state (single +) and initial state (#) which
147fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * processes all messages completely, the period (.).
148fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
149fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * The implementation is:
150fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville<code>
151fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savilleclass HelloWorld extends HierarchicalStateMachine {
152fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    Hsm1(String name) {
153fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        super(name);
154fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        addState(mState1);
155fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        setInitialState(mState1);
156fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
157fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
158fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static HelloWorld makeHelloWorld() {
159fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        HelloWorld hw = new HelloWorld("hw");
160fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        hw.start();
161fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return hw;
162fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
163fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
164fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    class State1 extends HierarchicalState {
165fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public boolean processMessage(Message message) {
166fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "Hello World");
167fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return true;
168fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
169fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
170fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    State1 mState1 = new State1();
171fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville}
172fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
173fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savillevoid testHelloWorld() {
174fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    HelloWorld hw = makeHelloWorld();
175fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    hw.sendMessage(hw.obtainMessage());
176fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville}
177fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville</code>
178fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
179fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * A more interesting state machine is one of four states
180fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * with two independent parent states.
181fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville<code>
182fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mP1      mP2
183fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville       /   \
184fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville      mS2   mS1
185fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville</code>
186fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
187fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * documented as:
188fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
189fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Hsm1 {
190fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   + mP1 {
191fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *       CMD_2 {
192fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *          $CMD_3
193fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *          %CMD_2
194fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *          >mS2
195fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *       }.
196fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *     }
197fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   ++ # mS1 { CMD_1{ >mS1 }^ }
198fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   ++   mS2 {
199fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *            CMD_2{$CMD_4}.
200fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *            CMD_3{%CMD_3 ; >mP2}.
201fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *     }
202fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
203fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   + mP2 e($CMD_5) {
204fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *            CMD_3, CMD_4.
205fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *            CMD_5{>HALT}.
206fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *     }
207fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * }
208fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
209fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * and interpreted as HierarchicalStateMachine Hsm1:
210fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
211fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * mP1 a root state.
212fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      processes message CMD_2 which sends CMD_3, defers CMD_2, and transitions to mS2
213fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
214fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * mS1 a child of mP1 is the initial state:
215fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      processes message CMD_1 which transitions to itself and returns false to let mP1 handle it.
216fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
217fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * mS2 a child of mP1:
218fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      processes message CMD_2 which send CMD_4
219fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      processes message CMD_3 which defers CMD_3 and transitions to mP2
220fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
221fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * mP2 a root state.
222fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      on enter it sends CMD_5
223fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      processes message CMD_3
224fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      processes message CMD_4
225fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      processes message CMD_5 which transitions to halt state
226fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
227fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * The implementation is below and also in HierarchicalStateMachineTest:
228fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville<code>
229fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savilleclass Hsm1 extends HierarchicalStateMachine {
230fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private static final String TAG = "hsm1";
231fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
232fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static final int CMD_1 = 1;
233fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static final int CMD_2 = 2;
234fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static final int CMD_3 = 3;
235fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static final int CMD_4 = 4;
236fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static final int CMD_5 = 5;
237fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
238fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public static Hsm1 makeHsm1() {
239fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Log.d(TAG, "makeHsm1 E");
240fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Hsm1 sm = new Hsm1("hsm1");
241fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        sm.start();
242fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Log.d(TAG, "makeHsm1 X");
243fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return sm;
244fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
245fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
246fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    Hsm1(String name) {
247fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        super(name);
248fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Log.d(TAG, "ctor E");
249fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
250fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        // Add states, use indentation to show hierarchy
251fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        addState(mP1);
252fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            addState(mS1, mP1);
253fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            addState(mS2, mP1);
254fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        addState(mP2);
255fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
256fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        // Set the initial state
257fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        setInitialState(mS1);
258fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Log.d(TAG, "ctor X");
259fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
260fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
261fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    class P1 extends HierarchicalState {
262fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public void enter() {
263fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mP1.enter");
264fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
265fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public boolean processMessage(Message message) {
266fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            boolean retVal;
267fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mP1.processMessage what=" + message.what);
268fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            switch(message.what) {
269fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case CMD_2:
270fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                // CMD_2 will arrive in mS2 before CMD_3
271fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                sendMessage(obtainMessage(CMD_3));
272fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                deferMessage(message);
273fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                transitionTo(mS2);
274fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                retVal = true;
275fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
276fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            default:
277fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                // Any message we don't understand in this state invokes unhandledMessage
278fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                retVal = false;
279fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
280fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
281fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return retVal;
282fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
283fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public void exit() {
284fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mP1.exit");
285fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
286fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
287fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
288fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    class S1 extends HierarchicalState {
289fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public void enter() {
290fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mS1.enter");
291fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
292fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public boolean processMessage(Message message) {
293fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "S1.processMessage what=" + message.what);
294fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (message.what == CMD_1) {
295fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                // Transition to ourself to show that enter/exit is called
296fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                transitionTo(mS1);
297fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                return true;
298fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            } else {
299fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                // Let parent process all other messages
300fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                return false;
301fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
302fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
303fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public void exit() {
304fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mS1.exit");
305fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
306fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
307fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
308fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    class S2 extends HierarchicalState {
309fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public void enter() {
310fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mS2.enter");
311fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
312fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public boolean processMessage(Message message) {
313fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            boolean retVal;
314fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mS2.processMessage what=" + message.what);
315fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            switch(message.what) {
316fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case(CMD_2):
317fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                sendMessage(obtainMessage(CMD_4));
318fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                retVal = true;
319fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
320fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case(CMD_3):
321fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                deferMessage(message);
322fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                transitionTo(mP2);
323fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                retVal = true;
324fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
325fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            default:
326fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                retVal = false;
327fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
328fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
329fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return retVal;
330fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
331fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public void exit() {
332fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mS2.exit");
333fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
334fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
335fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
336fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    class P2 extends HierarchicalState {
337fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public void enter() {
338fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mP2.enter");
339fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            sendMessage(obtainMessage(CMD_5));
340fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
341fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public boolean processMessage(Message message) {
342fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "P2.processMessage what=" + message.what);
343fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            switch(message.what) {
344fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case(CMD_3):
345fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
346fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case(CMD_4):
347fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
348fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            case(CMD_5):
349fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                transitionToHaltingState();
350fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                break;
351fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
352fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return true;
353fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
354fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override public void exit() {
355fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Log.d(TAG, "mP2.exit");
356fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
357fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
358fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
359fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    @Override
360fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected void halting() {
361fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Log.d(TAG, "halting");
362fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        synchronized (this) {
363fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            this.notifyAll();
364fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
365fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
366fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
367fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    P1 mP1 = new P1();
368fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    S1 mS1 = new S1();
369fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    S2 mS2 = new S2();
370fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    P2 mP2 = new P2();
371fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville}
372fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville</code>
373fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
374fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * If this is executed by sending two messages CMD_1 and CMD_2
375fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * (Note the synchronize is only needed because we use hsm.wait())
376fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
377fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Hsm1 hsm = makeHsm1();
378fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * synchronize(hsm) {
379fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      hsm.sendMessage(obtainMessage(hsm.CMD_1));
380fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      hsm.sendMessage(obtainMessage(hsm.CMD_2));
381fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      try {
382fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *           // wait for the messages to be handled
383fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *           hsm.wait();
384fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      } catch (InterruptedException e) {
385fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *           Log.e(TAG, "exception while waiting " + e.getMessage());
386fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *      }
387fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * }
388fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
389fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
390fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * The output is:
391fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
392fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): makeHsm1 E
393fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): ctor E
394fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): ctor X
395fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP1.enter
396fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.enter
397fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): makeHsm1 X
398fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.processMessage what=1
399fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.exit
400fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.enter
401fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.processMessage what=2
402fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP1.processMessage what=2
403fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS1.exit
404fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS2.enter
405fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS2.processMessage what=2
406fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS2.processMessage what=3
407fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mS2.exit
408fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP1.exit
409fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP2.enter
410fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP2.processMessage what=3
411fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP2.processMessage what=4
412fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP2.processMessage what=5
413fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): mP2.exit
414fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * D/hsm1    ( 1999): halting
415fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
416fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Here is the HSM a BNF grammar, this is a first stab at creating an
417fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * HSM description language, suggestions corrections or alternatives
418fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * would be much appreciated.
419fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
420fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Legend:
421fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   {}  ::= zero or more
422fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   {}+ ::= one or more
423fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   []  ::= zero or one
424fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   ()  ::= define a group with "or" semantics.
425fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
426fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * HSM EBNF:
427fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   HSM = HSM_NAME "{" { STATE }+ "}" ;
428fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   HSM_NAME = alpha_numeric_name ;
4291b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville *   STATE = INTRODUCE_STATE [ ENTER | [ ENTER EXIT ] "{" [ MESSAGES ] "}" [ EXIT ] ;
430fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   INTRODUCE_STATE = { STATE_DEPTH }+ [ INITIAL_STATE_INDICATOR ] STATE_NAME ;
431fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   STATE_DEPTH = "+" ;
432fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   INITIAL_STATE_INDICATOR = "#"
433fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   ENTER = "e(" SEND_ACTION | TRANSITION_ACTION | HALT_ACTION ")" ;
434fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   MESSAGES = { MSG_LIST MESSAGE_ACTIONS } ;
4351b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville *   MSG_LIST = { MSG_NAME { "," MSG_NAME } };
436fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   EXIT = "x(" SEND_ACTION | TRANSITION_ACTION | HALT_ACTION ")" ;
437fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   PROCESS_COMPLETION = PROCESS_IN_PARENT_OR_COMPLETE | PROCESS_COMPLETE ;
438fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   SEND_ACTION = "$" MSG_NAME ;
439fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   DEFER_ACTION = "%" MSG_NAME ;
440fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   TRANSITION_ACTION = ">" STATE_NAME ;
441fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   HALT_ACTION = ">" HALT ;
442fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   MESSAGE_ACTIONS = { "{" ACTION_LIST "}" } [ PROCESS_COMPLETION ] ;
443fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   ACTION_LIST = ACTION { (";" | "\n") ACTION } ;
444fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   ACTION = IF_ACTION | SEND_ACTION | DEFER_ACTION | TRANSITION_ACTION | HALT_ACTION ;
445fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   IF_ACTION = "if(" boolean_expression ")" "{" ACTION_LIST "}"
446fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   PROCESS_IN_PARENT_OR_COMPLETE = "^" ;
447fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   PROCESS_COMPLETE = "." ;
448fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   STATE_NAME = alpha_numeric_name ;
449fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   MSG_NAME = alpha_numeric_name | ALL_OTHER_MESSAGES ;
450fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   ALL_OTHER_MESSAGES = "*" ;
451fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   EXP = boolean_expression ;
452fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *
453fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville * Idioms:
454fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville *   * { %* }. ::= All other messages will be deferred.
455fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville */
456fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Savillepublic class HierarchicalStateMachine {
457fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
458fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private static final String TAG = "HierarchicalStateMachine";
459fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private String mName;
460fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
4611b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    public static final int HSM_QUIT_CMD = -1;
4621b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
463fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private static class HsmHandler extends Handler {
464fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
465fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The debug flag */
466fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private boolean mDbg = false;
467fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
4681b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /** The quit object */
4691b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private static final Object mQuitObj = new Object();
4701b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
471fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** A list of messages that this state machine has processed */
472fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private ProcessedMessages mProcessedMessages = new ProcessedMessages();
473fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
474fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** true if construction of the state machine has not been completed */
475fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private boolean mIsConstructionCompleted;
476fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
477fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** Stack used to manage the current hierarchy of states */
478fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private StateInfo mStateStack[];
479fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
480fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** Top of mStateStack */
481fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private int mStateStackTopIndex = -1;
482fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
483fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** A temporary stack used to manage the state stack */
484fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private StateInfo mTempStateStack[];
485fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
486fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The top of the mTempStateStack */
487fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private int mTempStateStackCount;
488fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
489fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** State used when state machine is halted */
490fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HaltingState mHaltingState = new HaltingState();
491fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
4921b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /** State used when state machine is quitting */
4931b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private QuittingState mQuittingState = new QuittingState();
4941b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
495fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** Reference to the HierarchicalStateMachine */
496fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HierarchicalStateMachine mHsm;
497fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
498fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
499fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Information about a state.
500fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Used to maintain the hierarchy.
501fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
502fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private class StateInfo {
503fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /** The state */
504fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            HierarchicalState state;
505fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
506fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /** The parent of this state, null if there is no parent */
507fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo parentStateInfo;
508fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
509fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /** True when the state has been entered and on the stack */
510fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            boolean active;
511fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
512fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
513fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Convert StateInfo to string
514fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
515fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            @Override
516fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            public String toString() {
517fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                return "state=" + state.getName() + ",active=" + active
518fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                        + ",parent=" + ((parentStateInfo == null) ?
519fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                                        "null" : parentStateInfo.state.getName());
520fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
521fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
522fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
523fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The map of all of the states in the state machine */
524fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HashMap<HierarchicalState, StateInfo> mStateInfo =
525fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            new HashMap<HierarchicalState, StateInfo>();
526fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
527fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The initial state that will process the first message */
528fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HierarchicalState mInitialState;
529fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
530fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The destination state when transitionTo has been invoked */
531fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HierarchicalState mDestState;
532fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
533fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** The list of deferred messages */
534fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private ArrayList<Message> mDeferredMessages = new ArrayList<Message>();
535fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
536fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
537fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * State entered when transitionToHaltingState is called.
538fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
539fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private class HaltingState extends HierarchicalState {
540fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            @Override
541fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            public boolean processMessage(Message msg) {
542fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mHsm.haltedProcessMessage(msg);
543fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                return true;
544fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
545fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
546fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
547fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
5481b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville         * State entered when a valid quit message is handled.
5491b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville         */
5501b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private class QuittingState extends HierarchicalState {
5511b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            @Override
5521b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            public boolean processMessage(Message msg) {
553f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville                // Ignore
554f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville                return false;
5551b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            }
5561b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        }
5571b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
5581b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /**
559fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Handle messages sent to the state machine by calling
560fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * the current state's processMessage. It also handles
561fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * the enter/exit calls and placing any deferred messages
562fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * back onto the queue when transitioning to a new state.
563fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
564fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        @Override
565fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        public final void handleMessage(Message msg) {
566fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "handleMessage: E msg.what=" + msg.what);
567fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
568fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
569fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Check that construction was completed
570fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
571fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (!mIsConstructionCompleted) {
572fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.e(TAG, "The start method not called, ignore msg: " + msg);
573fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                return;
574fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
575fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
576fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
577fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Process the message abiding by the hierarchical semantics.
578fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
579fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            processMsg(msg);
580fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
581fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
582fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * If transitionTo has been called, exit and then enter
583fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * the appropriate states.
584fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
585fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDestState != null) {
586fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "handleMessage: new destination call exit");
587fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
588fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                /**
589fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * Determine the states to exit and enter and return the
590fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * common ancestor state of the enter/exit states. Then
591fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * invoke the exit methods then the enter methods.
592fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 */
593fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(mDestState);
594fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                invokeExitMethods(commonStateInfo);
595fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                int stateStackEnteringIndex = moveTempStateStackToStateStack();
596fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                invokeEnterMethods(stateStackEnteringIndex);
597fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
598fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
599fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                /**
600fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * Since we have transitioned to a new state we need to have
601fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * any deferred messages moved to the front of the message queue
602fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * so they will be processed before any other messages in the
603fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * message queue.
604fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 */
605fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                moveDeferredMessageAtFrontOfQueue();
606fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
607fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                /**
608fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * Call halting() if we've transitioned to the halting
609fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * state. All subsequent messages will be processed in
610fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * in the halting state which invokes haltedProcessMessage(msg);
611fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 */
6121b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                if (mDestState == mQuittingState) {
6131b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    mHsm.quitting();
6141b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    if (mHsm.mHsmThread != null) {
6151b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                        // If we made the thread then quit looper
6161b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                        getLooper().quit();
6171b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    }
6181b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                } else if (mDestState == mHaltingState) {
619fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    mHsm.halting();
620fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
621fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mDestState = null;
622fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
623fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
624fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "handleMessage: X");
625fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
626fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
627fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
628fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Complete the construction of the state machine.
629fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
630fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void completeConstruction() {
631fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "completeConstruction: E");
632fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
633fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
634fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Determine the maximum depth of the state hierarchy
635fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * so we can allocate the state stacks.
636fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
637fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int maxDepth = 0;
638fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (StateInfo si : mStateInfo.values()) {
639fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                int depth = 0;
640fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                for (StateInfo i = si; i != null; depth++) {
641fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    i = i.parentStateInfo;
642fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
643fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (maxDepth < depth) {
644fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    maxDepth = depth;
645fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
646fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
647fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "completeConstruction: maxDepth=" + maxDepth);
648fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
649fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mStateStack = new StateInfo[maxDepth];
650fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mTempStateStack = new StateInfo[maxDepth];
651fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            setupInitialStateStack();
652fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
653fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
654fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Construction is complete call all enter methods
655fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * starting at the first entry.
656fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
657fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mIsConstructionCompleted = true;
658fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            invokeEnterMethods(0);
659fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
660fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "completeConstruction: X");
661fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
662fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
663fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
664fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Process the message. If the current state doesn't handle
665fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * it, call the states parent and so on. If it is never handled then
666fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * call the state machines unhandledMessage method.
667fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
668fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void processMsg(Message msg) {
669fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
670fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
671fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
672fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
673fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            while (!curStateInfo.state.processMessage(msg)) {
674fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                /**
675fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * Not processed
676fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 */
677fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curStateInfo = curStateInfo.parentStateInfo;
678fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (curStateInfo == null) {
679fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    /**
680fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                     * No parents left so it's not handled
681fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                     */
682fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    mHsm.unhandledMessage(msg);
6831b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    if (isQuit(msg)) {
6841b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                        transitionTo(mQuittingState);
6851b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    }
686fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    break;
687fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
688fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) {
689fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
690fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
691fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
692fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
693fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
694fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Record that we processed the message
695fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
696fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (curStateInfo != null) {
697fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                HierarchicalState orgState = mStateStack[mStateStackTopIndex].state;
698fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mProcessedMessages.add(msg, curStateInfo.state, orgState);
699fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            } else {
700fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mProcessedMessages.add(msg, null, null);
701fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
702fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
703fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
704fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
705fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Call the exit method for each state from the top of stack
706fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * up to the common ancestor state.
707fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
708fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void invokeExitMethods(StateInfo commonStateInfo) {
709fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            while ((mStateStackTopIndex >= 0) &&
710fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    (mStateStack[mStateStackTopIndex] != commonStateInfo)) {
711fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                HierarchicalState curState = mStateStack[mStateStackTopIndex].state;
712fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "invokeExitMethods: " + curState.getName());
713fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curState.exit();
714fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[mStateStackTopIndex].active = false;
715fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStackTopIndex -= 1;
716fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
717fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
718fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
719fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
720fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Invoke the enter method starting at the entering index to top of state stack
721fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
722fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void invokeEnterMethods(int stateStackEnteringIndex) {
723fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
724fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());
725fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[i].state.enter();
726fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[i].active = true;
727fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
728fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
729fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
730fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
731fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Move the deferred message to the front of the message queue.
732fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
733fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void moveDeferredMessageAtFrontOfQueue() {
734fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
735fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * The oldest messages on the deferred list must be at
736fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * the front of the queue so start at the back, which
737fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * as the most resent message and end with the oldest
738fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * messages at the front of the queue.
739fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
740fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (int i = mDeferredMessages.size() - 1; i >= 0; i-- ) {
741fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Message curMsg = mDeferredMessages.get(i);
742fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "moveDeferredMessageAtFrontOfQueue; what=" + curMsg.what);
743fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                sendMessageAtFrontOfQueue(curMsg);
744fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
745fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDeferredMessages.clear();
746fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
747fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
748fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
749fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Move the contents of the temporary stack to the state stack
750fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * reversing the order of the items on the temporary stack as
751fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * they are moved.
752fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
753fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return index into mStateState where entering needs to start
754fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
755fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final int moveTempStateStackToStateStack() {
756fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int startingIndex = mStateStackTopIndex + 1;
757fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int i = mTempStateStackCount - 1;
758fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int j = startingIndex;
759fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            while (i >= 0) {
760fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "moveTempStackToStateStack: i=" + i + ",j=" + j);
761fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[j] = mTempStateStack[i];
762fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                j += 1;
763fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                i -= 1;
764fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
765fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
766fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mStateStackTopIndex = j - 1;
767fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
768fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "moveTempStackToStateStack: X mStateStackTop="
769fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                      + mStateStackTopIndex + ",startingIndex=" + startingIndex
770fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                      + ",Top=" + mStateStack[mStateStackTopIndex].state.getName());
771fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
772fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return startingIndex;
773fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
774fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
775fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
776fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Setup the mTempStateStack with the states we are going to enter.
777fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
778fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * This is found by searching up the destState's ancestors for a
779fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * state that is already active i.e. StateInfo.active == true.
780fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * The destStae and all of its inactive parents will be on the
781fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * TempStateStack as the list of states to enter.
782fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
783fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return StateInfo of the common ancestor for the destState and
784fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * current state or null if there is no common parent.
785fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
786fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final StateInfo setupTempStateStackWithStatesToEnter(HierarchicalState destState) {
787fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
788fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Search up the parent list of the destination state for an active
789fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * state. Use a do while() loop as the destState must always be entered
790fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * even if it is active. This can happen if we are exiting/entering
791fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * the current state.
792fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
793fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mTempStateStackCount = 0;
794fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo curStateInfo = mStateInfo.get(destState);
795fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            do {
796fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mTempStateStack[mTempStateStackCount++] = curStateInfo;
797fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curStateInfo = curStateInfo.parentStateInfo;
798fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            } while ((curStateInfo != null) && !curStateInfo.active);
799fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
800fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
801fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "setupTempStateStackWithStatesToEnter: X mTempStateStackCount="
802fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                      + mTempStateStackCount + ",curStateInfo: " + curStateInfo);
803fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
804fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return curStateInfo;
805fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
806fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
807fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
808fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Initialize StateStack to mInitialState.
809fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
810fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setupInitialStateStack() {
811fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
812fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "setupInitialStateStack: E mInitialState="
813fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    + mInitialState.getName());
814fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
815fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
816fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo curStateInfo = mStateInfo.get(mInitialState);
817fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
818fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mTempStateStack[mTempStateStackCount] = curStateInfo;
819fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curStateInfo = curStateInfo.parentStateInfo;
820fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
821fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
822fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            // Empty the StateStack
823fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mStateStackTopIndex = -1;
824fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
825fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            moveTempStateStackToStateStack();
826fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
827fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
828fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
829fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return current state
830fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
831fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final HierarchicalState getCurrentState() {
832fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mStateStack[mStateStackTopIndex].state;
833fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
834fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
835fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
836fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Add a new state to the state machine. Bottom up addition
837fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * of states is allowed but the same state may only exist
838fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * in one hierarchy.
839fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
840fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param state the state to add
841fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param parent the parent of state
842fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return stateInfo for this state
843fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
844fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final StateInfo addState(HierarchicalState state, HierarchicalState parent) {
845fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
846fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "addStateInternal: E state=" + state.getName()
847fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                        + ",parent=" + ((parent == null) ? "" : parent.getName()));
848fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
849fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo parentStateInfo = null;
850fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (parent != null) {
851fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                parentStateInfo = mStateInfo.get(parent);
852fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (parentStateInfo == null) {
853fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    // Recursively add our parent as it's not been added yet.
854fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    parentStateInfo = addState(parent, null);
855fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
856fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
857fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo stateInfo = mStateInfo.get(state);
858fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (stateInfo == null) {
859fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                stateInfo = new StateInfo();
860fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateInfo.put(state, stateInfo);
861fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
862fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
863fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            // Validate that we aren't adding the same state in two different hierarchies.
864fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if ((stateInfo.parentStateInfo != null) &&
865fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    (stateInfo.parentStateInfo != parentStateInfo)) {
866fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    throw new RuntimeException("state already added");
867fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
868fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            stateInfo.state = state;
869fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            stateInfo.parentStateInfo = parentStateInfo;
870fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            stateInfo.active = false;
871fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo);
872fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return stateInfo;
873fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
874fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
875fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
876fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Constructor
877fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
878fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param looper for dispatching messages
879fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param hsm the hierarchical state machine
880fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
881fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HsmHandler(Looper looper, HierarchicalStateMachine hsm) {
882fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            super(looper);
883fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mHsm = hsm;
884fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
885fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            addState(mHaltingState, null);
8861b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            addState(mQuittingState, null);
887fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
888fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
889fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#setInitialState(HierarchicalState) */
890fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setInitialState(HierarchicalState initialState) {
891fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "setInitialState: initialState" + initialState.getName());
892fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mInitialState = initialState;
893fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
894fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
895fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#transitionTo(HierarchicalState) */
896fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void transitionTo(HierarchicalState destState) {
897fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + destState.getName());
898fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDestState = destState;
899fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
900fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
901fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#deferMessage(Message) */
902fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void deferMessage(Message msg) {
903fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "deferMessage: msg=" + msg.what);
904fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
905fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /* Copy the "msg" to "newMsg" as "msg" will be recycled */
906fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Message newMsg = obtainMessage();
907fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            newMsg.copyFrom(msg);
908fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
909fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDeferredMessages.add(newMsg);
910fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
911fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
9121b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /** @see HierarchicalStateMachine#deferMessage(Message) */
9131b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private final void quit() {
9141b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            if (mDbg) Log.d(TAG, "quit:");
9151b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            sendMessage(obtainMessage(HSM_QUIT_CMD, mQuitObj));
9161b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        }
9171b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
9181b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /** @see HierarchicalStateMachine#isQuit(Message) */
9191b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private final boolean isQuit(Message msg) {
9201b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            return (msg.what == HSM_QUIT_CMD) && (msg.obj == mQuitObj);
9211b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        }
9221b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
923fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#isDbg() */
924fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final boolean isDbg() {
925fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mDbg;
926fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
927fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
928fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#setDbg(boolean) */
929fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setDbg(boolean dbg) {
930fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDbg = dbg;
931fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
932fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
933fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#setProcessedMessagesSize(int) */
934fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setProcessedMessagesSize(int maxSize) {
935fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mProcessedMessages.setSize(maxSize);
936fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
937fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
938fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#getProcessedMessagesSize() */
939fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final int getProcessedMessagesSize() {
940fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mProcessedMessages.size();
941fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
942fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
943fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#getProcessedMessagesCount() */
944fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final int getProcessedMessagesCount() {
945fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mProcessedMessages.count();
946fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
947fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
948fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#getProcessedMessage(int) */
949fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final ProcessedMessages.Info getProcessedMessage(int index) {
950fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mProcessedMessages.get(index);
951fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
952fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
953fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
954fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
955fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private HsmHandler mHsmHandler;
956fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private HandlerThread mHsmThread;
957fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
958fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
959fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Initialize.
960fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
961fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param looper for this state machine
962fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param name of the state machine
963fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
964f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville    private void initStateMachine(String name, Looper looper) {
965fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mName = name;
966fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler = new HsmHandler(looper, this);
967fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
968fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
969fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
970fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Constructor creates an HSM with its own thread.
971fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
972fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param name of the state machine
973fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
974fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected HierarchicalStateMachine(String name) {
975fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmThread = new HandlerThread(name);
976fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmThread.start();
977fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Looper looper = mHsmThread.getLooper();
978fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
979f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville        initStateMachine(name, looper);
980fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
981fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
982fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
983fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Constructor creates an HSMStateMachine using the looper.
984fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
985fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param name of the state machine
986fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
987f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville    protected HierarchicalStateMachine(String name, Looper looper) {
988f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville        initStateMachine(name, looper);
989fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
990fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
991fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
992fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Add a new state to the state machine
993fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param state the state to add
994fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param parent the parent of state
995fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
996fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void addState(HierarchicalState state, HierarchicalState parent) {
997fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.addState(state, parent);
998fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
999fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1000fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return current state
1001fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1002fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final HierarchicalState getCurrentState() {
1003fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getCurrentState();
1004fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1005fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1006fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1007fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1008fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Add a new state to the state machine, parent will be null
1009fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param state to add
1010fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1011fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void addState(HierarchicalState state) {
1012fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.addState(state, null);
1013fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1014fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1015fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1016fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Set the initial state. This must be invoked before
1017fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * and messages are sent to the state machine.
1018fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1019fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param initialState is the state which will receive the first message.
1020fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1021fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void setInitialState(HierarchicalState initialState) {
1022fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.setInitialState(initialState);
1023fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1024fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1025fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1026fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * transition to destination state. Upon returning
1027fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * from processMessage the current state's exit will
1028fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * be executed and upon the next message arriving
1029fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * destState.enter will be invoked.
1030fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1031fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param destState will be the state that receives the next message.
1032fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1033fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void transitionTo(HierarchicalState destState) {
1034fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.transitionTo(destState);
1035fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1036fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1037fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1038fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * transition to halt state. Upon returning
1039fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * from processMessage we will exit all current
1040fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * states, execute the halting() method and then
1041fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * all subsequent messages haltedProcessMesage
1042fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * will be called.
1043fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1044fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void transitionToHaltingState() {
1045fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.transitionTo(mHsmHandler.mHaltingState);
1046fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1047fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1048fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1049fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Defer this message until next state transition.
1050fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Upon transitioning all deferred messages will be
1051fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * placed on the queue and reprocessed in the original
1052fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * order. (i.e. The next state the oldest messages will
1053fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * be processed first)
1054fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1055fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param msg is deferred until the next transition.
1056fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1057fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void deferMessage(Message msg) {
1058fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.deferMessage(msg);
1059fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1060fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1061fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1062fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1063fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Called when message wasn't handled
1064fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1065fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param msg that couldn't be handled.
1066fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1067fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected void unhandledMessage(Message msg) {
10682a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        Log.e(TAG, mName + " - unhandledMessage: msg.what=" + msg.what);
1069fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1070fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1071fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1072fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Called for any message that is received after
1073fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * transitionToHalting is called.
1074fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1075fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected void haltedProcessMessage(Message msg) {
1076fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1077fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1078fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1079fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Called after the message that called transitionToHalting
1080fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * is called and should be overridden by StateMachine's that
1081fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * call transitionToHalting.
1082fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1083fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected void halting() {
1084fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1085fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1086fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
10871b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * Called after the quitting message was NOT handled and
10881b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * just before the quit actually occurs.
10891b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     */
10901b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    protected void quitting() {
10911b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    }
10921b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
10931b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    /**
1094fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return the name
1095fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1096fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final String getName() {
1097fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mName;
1098fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1099fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1100fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1101fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Set size of messages to maintain and clears all current messages.
1102fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1103fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param maxSize number of messages to maintain at anyone time.
1104fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1105fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final void setProcessedMessagesSize(int maxSize) {
1106fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.setProcessedMessagesSize(maxSize);
1107fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1108fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1109fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1110fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return number of messages processed
1111fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1112fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final int getProcessedMessagesSize() {
1113fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getProcessedMessagesSize();
1114fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1115fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1116fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1117fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return the total number of messages processed
1118fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1119fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final int getProcessedMessagesCount() {
1120fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getProcessedMessagesCount();
1121fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1122fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1123fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1124fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return a processed message
1125fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1126fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final ProcessedMessages.Info getProcessedMessage(int index) {
1127fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getProcessedMessage(index);
1128fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1129fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1130fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1131fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return Handler
1132fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1133fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Handler getHandler() {
1134fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler;
1135fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1136fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1137fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1138fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Get a message and set Message.target = this.
1139fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1140fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return message
1141fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1142fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Message obtainMessage()
1143fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    {
1144fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return Message.obtain(mHsmHandler);
1145fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1146fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1147fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1148fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Get a message and set Message.target = this and what
1149fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1150fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param what is the assigned to Message.what.
1151fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return message
1152fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1153fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Message obtainMessage(int what) {
1154fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return Message.obtain(mHsmHandler, what);
1155fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1156fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1157fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1158fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Get a message and set Message.target = this,
1159fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * what and obj.
1160fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1161fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param what is the assigned to Message.what.
1162fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param obj is assigned to Message.obj.
1163fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return message
1164fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1165fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Message obtainMessage(int what, Object obj)
1166fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    {
1167fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return Message.obtain(mHsmHandler, what, obj);
1168fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1169fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
117091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
117191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
117291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine.
117391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
117491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessage(int what) {
117591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessage(obtainMessage(what));
117691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
117791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
117891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
117991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine.
118091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
118191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessage(int what, Object obj) {
118291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessage(obtainMessage(what,obj));
118391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
118491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
1185fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1186fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Enqueue a message to this state machine.
1187fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1188fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final void sendMessage(Message msg) {
1189fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.sendMessage(msg);
1190fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1191fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1192fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1193fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Enqueue a message to this state machine after a delay.
1194fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
119591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessageDelayed(int what, long delayMillis) {
119691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
119791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
119891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
119991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
120091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine after a delay.
120191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
120291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
120391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
120491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
120591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
120691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
120791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine after a delay.
120891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
1209fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final void sendMessageDelayed(Message msg, long delayMillis) {
1210fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.sendMessageDelayed(msg, delayMillis);
1211fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1212fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1213fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1214fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Enqueue a message to the front of the queue for this state machine.
1215fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Protected, may only be called by instances of HierarchicalStateMachine.
1216fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
121791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    protected final void sendMessageAtFrontOfQueue(int what, Object obj) {
121891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
121991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
122091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
122191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
122291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to the front of the queue for this state machine.
122391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Protected, may only be called by instances of HierarchicalStateMachine.
122491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
122591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    protected final void sendMessageAtFrontOfQueue(int what) {
122691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
122791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
122891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
122991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
123091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to the front of the queue for this state machine.
123191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Protected, may only be called by instances of HierarchicalStateMachine.
123291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
1233fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void sendMessageAtFrontOfQueue(Message msg) {
1234fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.sendMessageAtFrontOfQueue(msg);
1235fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1236fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1237fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
12381b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * Conditionally quit the looper and stop execution.
12391b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     *
12401b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * This sends the HSM_QUIT_MSG to the state machine and
12411b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * if not handled by any state's processMessage then the
12421b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * state machine will be stopped and no further messages
12431b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * will be processed.
12441b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     */
12451b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    public final void quit() {
12461b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        mHsmHandler.quit();
12471b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    }
12481b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
12491b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    /**
12501b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * @return ture if msg is quit
12511b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     */
12521b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    protected final boolean isQuit(Message msg) {
12531b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        return mHsmHandler.isQuit(msg);
12541b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    }
12551b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
12561b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    /**
1257fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return if debugging is enabled
1258fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1259fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public boolean isDbg() {
1260fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.isDbg();
1261fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1262fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1263fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1264fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Set debug enable/disabled.
1265fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1266fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param dbg is true to enable debugging.
1267fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1268fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public void setDbg(boolean dbg) {
1269fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.setDbg(dbg);
1270fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1271fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1272fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1273fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Start the state machine.
1274fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1275fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public void start() {
1276fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** Send the complete construction message */
1277fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.completeConstruction();
1278fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1279fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville}
1280