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            /**
577e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * Process the message abiding by the hierarchical semantics
578e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * and perform any requested transitions.
579fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
580fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            processMsg(msg);
581e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            performTransitions();
582fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
583e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            if (mDbg) Log.d(TAG, "handleMessage: X");
584e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville        }
585e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville
586e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville        /**
587e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville         * Do any transitions
588e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville         */
589e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville        private void performTransitions() {
590fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
591fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * If transitionTo has been called, exit and then enter
592e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * the appropriate states. We loop on this to allow
593e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * enter and exit methods to use transitionTo.
594fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
595e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            HierarchicalState destState = null;
596e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            while (mDestState != null) {
597fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "handleMessage: new destination call exit");
598fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
599fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                /**
600e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                 * Save mDestState locally and set to null
601e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                 * to know if enter/exit use transitionTo.
602e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                 */
603e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                destState = mDestState;
604e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                mDestState = null;
605e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville
606e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                /**
607fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * Determine the states to exit and enter and return the
608fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * common ancestor state of the enter/exit states. Then
609fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * invoke the exit methods then the enter methods.
610fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 */
611e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
612fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                invokeExitMethods(commonStateInfo);
613fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                int stateStackEnteringIndex = moveTempStateStackToStateStack();
614fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                invokeEnterMethods(stateStackEnteringIndex);
615fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
616fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
617fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                /**
618fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * Since we have transitioned to a new state we need to have
619fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * any deferred messages moved to the front of the message queue
620fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * so they will be processed before any other messages in the
621fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * message queue.
622fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 */
623fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                moveDeferredMessageAtFrontOfQueue();
624e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            }
625fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
626e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            /**
627e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * After processing all transitions check and
628e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * see if the last transition was to quit or halt.
629e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             */
630e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            if (destState != null) {
631e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                if (destState == mQuittingState) {
632e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                    /**
633e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     * We are quitting so ignore all messages.
634e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     */
6351b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    mHsm.quitting();
6361b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    if (mHsm.mHsmThread != null) {
6371b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                        // If we made the thread then quit looper
6381b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                        getLooper().quit();
6391b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    }
640e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                } else if (destState == mHaltingState) {
641e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                    /**
642e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     * Call halting() if we've transitioned to the halting
643e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     * state. All subsequent messages will be processed in
644e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     * in the halting state which invokes haltedProcessMessage(msg);
645e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville                     */
646fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    mHsm.halting();
647fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
648fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
649fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
650fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
651fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
652fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Complete the construction of the state machine.
653fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
654fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void completeConstruction() {
655fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "completeConstruction: E");
656fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
657fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
658fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Determine the maximum depth of the state hierarchy
659fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * so we can allocate the state stacks.
660fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
661fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int maxDepth = 0;
662fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (StateInfo si : mStateInfo.values()) {
663fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                int depth = 0;
664fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                for (StateInfo i = si; i != null; depth++) {
665fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    i = i.parentStateInfo;
666fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
667fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (maxDepth < depth) {
668fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    maxDepth = depth;
669fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
670fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
671fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "completeConstruction: maxDepth=" + maxDepth);
672fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
673fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mStateStack = new StateInfo[maxDepth];
674fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mTempStateStack = new StateInfo[maxDepth];
675fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            setupInitialStateStack();
676fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
677fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
678fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Construction is complete call all enter methods
679fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * starting at the first entry.
680fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
681fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mIsConstructionCompleted = true;
682fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            invokeEnterMethods(0);
683fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
684e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            /**
685e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             * Perform any transitions requested by the enter methods
686e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville             */
687e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville            performTransitions();
688e7be6a85da5be32348f4e83ede195477a7ec1790Wink Saville
689fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "completeConstruction: X");
690fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
691fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
692fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
693fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Process the message. If the current state doesn't handle
694fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * it, call the states parent and so on. If it is never handled then
695fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * call the state machines unhandledMessage method.
696fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
697fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void processMsg(Message msg) {
698fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
699fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
700fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
701fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
702fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            while (!curStateInfo.state.processMessage(msg)) {
703fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                /**
704fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 * Not processed
705fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                 */
706fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curStateInfo = curStateInfo.parentStateInfo;
707fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (curStateInfo == null) {
708fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    /**
709fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                     * No parents left so it's not handled
710fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                     */
711fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    mHsm.unhandledMessage(msg);
7121b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    if (isQuit(msg)) {
7131b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                        transitionTo(mQuittingState);
7141b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville                    }
715fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    break;
716fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
717fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) {
718fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
719fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
720fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
721fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
722fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
723fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Record that we processed the message
724fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
725fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (curStateInfo != null) {
726fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                HierarchicalState orgState = mStateStack[mStateStackTopIndex].state;
727fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mProcessedMessages.add(msg, curStateInfo.state, orgState);
728fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            } else {
729fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mProcessedMessages.add(msg, null, null);
730fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
731fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
732fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
733fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
734fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Call the exit method for each state from the top of stack
735fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * up to the common ancestor state.
736fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
737fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void invokeExitMethods(StateInfo commonStateInfo) {
738fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            while ((mStateStackTopIndex >= 0) &&
739fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    (mStateStack[mStateStackTopIndex] != commonStateInfo)) {
740fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                HierarchicalState curState = mStateStack[mStateStackTopIndex].state;
741fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "invokeExitMethods: " + curState.getName());
742fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curState.exit();
743fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[mStateStackTopIndex].active = false;
744fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStackTopIndex -= 1;
745fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
746fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
747fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
748fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
749fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Invoke the enter method starting at the entering index to top of state stack
750fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
751fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void invokeEnterMethods(int stateStackEnteringIndex) {
752fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
753fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());
754fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[i].state.enter();
755fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[i].active = true;
756fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
757fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
758fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
759fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
760fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Move the deferred message to the front of the message queue.
761fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
762fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void moveDeferredMessageAtFrontOfQueue() {
763fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
764fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * The oldest messages on the deferred list must be at
765fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * the front of the queue so start at the back, which
766fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * as the most resent message and end with the oldest
767fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * messages at the front of the queue.
768fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
769fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (int i = mDeferredMessages.size() - 1; i >= 0; i-- ) {
770fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Message curMsg = mDeferredMessages.get(i);
771fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "moveDeferredMessageAtFrontOfQueue; what=" + curMsg.what);
772fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                sendMessageAtFrontOfQueue(curMsg);
773fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
774fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDeferredMessages.clear();
775fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
776fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
777fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
778fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Move the contents of the temporary stack to the state stack
779fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * reversing the order of the items on the temporary stack as
780fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * they are moved.
781fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
782fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return index into mStateState where entering needs to start
783fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
784fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final int moveTempStateStackToStateStack() {
785fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int startingIndex = mStateStackTopIndex + 1;
786fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int i = mTempStateStackCount - 1;
787fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            int j = startingIndex;
788fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            while (i >= 0) {
789fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (mDbg) Log.d(TAG, "moveTempStackToStateStack: i=" + i + ",j=" + j);
790fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateStack[j] = mTempStateStack[i];
791fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                j += 1;
792fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                i -= 1;
793fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
794fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
795fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mStateStackTopIndex = j - 1;
796fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
797fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "moveTempStackToStateStack: X mStateStackTop="
798fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                      + mStateStackTopIndex + ",startingIndex=" + startingIndex
799fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                      + ",Top=" + mStateStack[mStateStackTopIndex].state.getName());
800fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
801fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return startingIndex;
802fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
803fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
804fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
805fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Setup the mTempStateStack with the states we are going to enter.
806fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
807fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * This is found by searching up the destState's ancestors for a
808fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * state that is already active i.e. StateInfo.active == true.
809fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * The destStae and all of its inactive parents will be on the
810fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * TempStateStack as the list of states to enter.
811fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
812fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return StateInfo of the common ancestor for the destState and
813fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * current state or null if there is no common parent.
814fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
815fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final StateInfo setupTempStateStackWithStatesToEnter(HierarchicalState destState) {
816fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /**
817fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * Search up the parent list of the destination state for an active
818fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * state. Use a do while() loop as the destState must always be entered
819fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * even if it is active. This can happen if we are exiting/entering
820fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             * the current state.
821fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville             */
822fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mTempStateStackCount = 0;
823fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo curStateInfo = mStateInfo.get(destState);
824fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            do {
825fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mTempStateStack[mTempStateStackCount++] = curStateInfo;
826fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curStateInfo = curStateInfo.parentStateInfo;
827fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            } while ((curStateInfo != null) && !curStateInfo.active);
828fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
829fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
830fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "setupTempStateStackWithStatesToEnter: X mTempStateStackCount="
831fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                      + mTempStateStackCount + ",curStateInfo: " + curStateInfo);
832fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
833fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return curStateInfo;
834fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
835fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
836fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
837fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Initialize StateStack to mInitialState.
838fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
839fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setupInitialStateStack() {
840fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
841fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "setupInitialStateStack: E mInitialState="
842fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    + mInitialState.getName());
843fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
844fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
845fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo curStateInfo = mStateInfo.get(mInitialState);
846fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
847fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mTempStateStack[mTempStateStackCount] = curStateInfo;
848fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                curStateInfo = curStateInfo.parentStateInfo;
849fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
850fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
851fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            // Empty the StateStack
852fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mStateStackTopIndex = -1;
853fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
854fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            moveTempStateStackToStateStack();
855fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
856fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
857fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
858fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return current state
859fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
860fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final HierarchicalState getCurrentState() {
861fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mStateStack[mStateStackTopIndex].state;
862fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
863fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
864fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
865fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Add a new state to the state machine. Bottom up addition
866fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * of states is allowed but the same state may only exist
867fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * in one hierarchy.
868fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
869fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param state the state to add
870fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param parent the parent of state
871fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @return stateInfo for this state
872fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
873fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final StateInfo addState(HierarchicalState state, HierarchicalState parent) {
874fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) {
875fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                Log.d(TAG, "addStateInternal: E state=" + state.getName()
876fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                        + ",parent=" + ((parent == null) ? "" : parent.getName()));
877fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
878fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo parentStateInfo = null;
879fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (parent != null) {
880fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                parentStateInfo = mStateInfo.get(parent);
881fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                if (parentStateInfo == null) {
882fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    // Recursively add our parent as it's not been added yet.
883fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    parentStateInfo = addState(parent, null);
884fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                }
885fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
886fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            StateInfo stateInfo = mStateInfo.get(state);
887fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (stateInfo == null) {
888fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                stateInfo = new StateInfo();
889fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                mStateInfo.put(state, stateInfo);
890fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
891fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
892fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            // Validate that we aren't adding the same state in two different hierarchies.
893fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if ((stateInfo.parentStateInfo != null) &&
894fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    (stateInfo.parentStateInfo != parentStateInfo)) {
895fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville                    throw new RuntimeException("state already added");
896fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            }
897fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            stateInfo.state = state;
898fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            stateInfo.parentStateInfo = parentStateInfo;
899fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            stateInfo.active = false;
900fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo);
901fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return stateInfo;
902fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
903fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
904fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /**
905fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * Constructor
906fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         *
907fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param looper for dispatching messages
908fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         * @param hsm the hierarchical state machine
909fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville         */
910fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private HsmHandler(Looper looper, HierarchicalStateMachine hsm) {
911fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            super(looper);
912fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mHsm = hsm;
913fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
914fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            addState(mHaltingState, null);
9151b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            addState(mQuittingState, null);
916fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
917fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
918fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#setInitialState(HierarchicalState) */
919fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setInitialState(HierarchicalState initialState) {
920fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "setInitialState: initialState" + initialState.getName());
921fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mInitialState = initialState;
922fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
923fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
924fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#transitionTo(HierarchicalState) */
925fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void transitionTo(HierarchicalState destState) {
926fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + destState.getName());
927fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDestState = destState;
928fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
929fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
930fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#deferMessage(Message) */
931fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void deferMessage(Message msg) {
932fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            if (mDbg) Log.d(TAG, "deferMessage: msg=" + msg.what);
933fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
934fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            /* Copy the "msg" to "newMsg" as "msg" will be recycled */
935fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            Message newMsg = obtainMessage();
936fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            newMsg.copyFrom(msg);
937fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
938fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDeferredMessages.add(newMsg);
939fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
940fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
9411b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /** @see HierarchicalStateMachine#deferMessage(Message) */
9421b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private final void quit() {
9431b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            if (mDbg) Log.d(TAG, "quit:");
9441b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            sendMessage(obtainMessage(HSM_QUIT_CMD, mQuitObj));
9451b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        }
9461b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
9471b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        /** @see HierarchicalStateMachine#isQuit(Message) */
9481b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        private final boolean isQuit(Message msg) {
9491b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville            return (msg.what == HSM_QUIT_CMD) && (msg.obj == mQuitObj);
9501b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        }
9511b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
952fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#isDbg() */
953fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final boolean isDbg() {
954fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mDbg;
955fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
956fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
957fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#setDbg(boolean) */
958fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setDbg(boolean dbg) {
959fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mDbg = dbg;
960fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
961fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
962fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#setProcessedMessagesSize(int) */
963fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final void setProcessedMessagesSize(int maxSize) {
964fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            mProcessedMessages.setSize(maxSize);
965fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
966fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
967fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#getProcessedMessagesSize() */
968fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final int getProcessedMessagesSize() {
969fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mProcessedMessages.size();
970fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
971fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
972fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#getProcessedMessagesCount() */
973fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final int getProcessedMessagesCount() {
974fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mProcessedMessages.count();
975fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
976fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
977fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** @see HierarchicalStateMachine#getProcessedMessage(int) */
978fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        private final ProcessedMessages.Info getProcessedMessage(int index) {
979fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville            return mProcessedMessages.get(index);
980fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        }
981fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
982fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
983fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
984fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private HsmHandler mHsmHandler;
985fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    private HandlerThread mHsmThread;
986fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
987fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
988fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Initialize.
989fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
990fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param looper for this state machine
991fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param name of the state machine
992fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
993f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville    private void initStateMachine(String name, Looper looper) {
994fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mName = name;
995fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler = new HsmHandler(looper, this);
996fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
997fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
998fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
999fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Constructor creates an HSM with its own thread.
1000fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1001fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param name of the state machine
1002fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1003fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected HierarchicalStateMachine(String name) {
1004fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmThread = new HandlerThread(name);
1005fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmThread.start();
1006fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        Looper looper = mHsmThread.getLooper();
1007fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1008f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville        initStateMachine(name, looper);
1009fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1010fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1011fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1012fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Constructor creates an HSMStateMachine using the looper.
1013fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1014fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param name of the state machine
1015fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1016f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville    protected HierarchicalStateMachine(String name, Looper looper) {
1017f0f566ec4607376583e59964a6a8a6dcb0265c20Wink Saville        initStateMachine(name, looper);
1018fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1019fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1020fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1021fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Add a new state to the state machine
1022fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param state the state to add
1023fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param parent the parent of state
1024fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1025fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void addState(HierarchicalState state, HierarchicalState parent) {
1026fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.addState(state, parent);
1027fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1028fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1029fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return current state
1030fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1031fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final HierarchicalState getCurrentState() {
1032fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getCurrentState();
1033fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1034fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1035fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1036fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1037fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Add a new state to the state machine, parent will be null
1038fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param state to add
1039fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1040fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void addState(HierarchicalState state) {
1041fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.addState(state, null);
1042fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1043fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1044fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1045fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Set the initial state. This must be invoked before
1046fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * and messages are sent to the state machine.
1047fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1048fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param initialState is the state which will receive the first message.
1049fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1050fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void setInitialState(HierarchicalState initialState) {
1051fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.setInitialState(initialState);
1052fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1053fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1054fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1055fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * transition to destination state. Upon returning
1056fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * from processMessage the current state's exit will
1057fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * be executed and upon the next message arriving
1058fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * destState.enter will be invoked.
1059fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1060fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param destState will be the state that receives the next message.
1061fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1062fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void transitionTo(HierarchicalState destState) {
1063fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.transitionTo(destState);
1064fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1065fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1066fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1067fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * transition to halt state. Upon returning
1068fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * from processMessage we will exit all current
1069fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * states, execute the halting() method and then
1070fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * all subsequent messages haltedProcessMesage
1071fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * will be called.
1072fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1073fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void transitionToHaltingState() {
1074fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.transitionTo(mHsmHandler.mHaltingState);
1075fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1076fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1077fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1078fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Defer this message until next state transition.
1079fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Upon transitioning all deferred messages will be
1080fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * placed on the queue and reprocessed in the original
1081fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * order. (i.e. The next state the oldest messages will
1082fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * be processed first)
1083fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1084fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param msg is deferred until the next transition.
1085fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1086fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void deferMessage(Message msg) {
1087fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.deferMessage(msg);
1088fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1089fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1090fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1091fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1092fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Called when message wasn't handled
1093fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1094fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param msg that couldn't be handled.
1095fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1096fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected void unhandledMessage(Message msg) {
10972a091d7aa0c174986387e5d56bf97a87fe075bdbRobert Greenwalt        Log.e(TAG, mName + " - unhandledMessage: msg.what=" + msg.what);
1098fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1099fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1100fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1101fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Called for any message that is received after
1102fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * transitionToHalting is called.
1103fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1104fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected void haltedProcessMessage(Message msg) {
1105fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1106fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1107fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1108fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Called after the message that called transitionToHalting
1109fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * is called and should be overridden by StateMachine's that
1110fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * call transitionToHalting.
1111fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1112fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected void halting() {
1113fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1114fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1115fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
11161b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * Called after the quitting message was NOT handled and
11171b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * just before the quit actually occurs.
11181b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     */
11191b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    protected void quitting() {
11201b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    }
11211b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
11221b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    /**
1123fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return the name
1124fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1125fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final String getName() {
1126fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mName;
1127fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1128fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1129fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1130fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Set size of messages to maintain and clears all current messages.
1131fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1132fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param maxSize number of messages to maintain at anyone time.
1133fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1134fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final void setProcessedMessagesSize(int maxSize) {
1135fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.setProcessedMessagesSize(maxSize);
1136fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1137fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1138fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1139fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return number of messages processed
1140fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1141fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final int getProcessedMessagesSize() {
1142fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getProcessedMessagesSize();
1143fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1144fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1145fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1146fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return the total number of messages processed
1147fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1148fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final int getProcessedMessagesCount() {
1149fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getProcessedMessagesCount();
1150fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1151fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1152fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1153fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return a processed message
1154fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1155fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final ProcessedMessages.Info getProcessedMessage(int index) {
1156fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.getProcessedMessage(index);
1157fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1158fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1159fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1160fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return Handler
1161fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1162fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Handler getHandler() {
1163fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler;
1164fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1165fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1166fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1167fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Get a message and set Message.target = this.
1168fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1169fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return message
1170fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1171fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Message obtainMessage()
1172fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    {
1173fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return Message.obtain(mHsmHandler);
1174fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1175fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1176fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1177fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Get a message and set Message.target = this and what
1178fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1179fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param what is the assigned to Message.what.
1180fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return message
1181fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1182fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Message obtainMessage(int what) {
1183fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return Message.obtain(mHsmHandler, what);
1184fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1185fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1186fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1187fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Get a message and set Message.target = this,
1188fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * what and obj.
1189fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1190fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param what is the assigned to Message.what.
1191fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param obj is assigned to Message.obj.
1192fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return message
1193fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1194fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final Message obtainMessage(int what, Object obj)
1195fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    {
1196fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return Message.obtain(mHsmHandler, what, obj);
1197fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1198fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
119991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
120091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine.
120191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
120291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessage(int what) {
120391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessage(obtainMessage(what));
120491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
120591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
120691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
120791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine.
120891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
120991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessage(int what, Object obj) {
121091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessage(obtainMessage(what,obj));
121191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
121291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
1213fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1214fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Enqueue a message to this state machine.
1215fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1216fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final void sendMessage(Message msg) {
1217fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.sendMessage(msg);
1218fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1219fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1220fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1221fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Enqueue a message to this state machine after a delay.
1222fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
122391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessageDelayed(int what, long delayMillis) {
122491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
122591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
122691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
122791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
122891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine after a delay.
122991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
123091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
123191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
123291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
123391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
123491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
123591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to this state machine after a delay.
123691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
1237fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public final void sendMessageDelayed(Message msg, long delayMillis) {
1238fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.sendMessageDelayed(msg, delayMillis);
1239fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1240fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1241fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1242fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Enqueue a message to the front of the queue for this state machine.
1243fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Protected, may only be called by instances of HierarchicalStateMachine.
1244fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
124591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    protected final void sendMessageAtFrontOfQueue(int what, Object obj) {
124691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
124791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
124891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
124991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
125091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to the front of the queue for this state machine.
125191fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Protected, may only be called by instances of HierarchicalStateMachine.
125291fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
125391fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    protected final void sendMessageAtFrontOfQueue(int what) {
125491fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville        mHsmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
125591fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    }
125691fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville
125791fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville    /**
125891fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Enqueue a message to the front of the queue for this state machine.
125991fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     * Protected, may only be called by instances of HierarchicalStateMachine.
126091fbd56757751a7aca8ef2b4d936e587509e6eefWink Saville     */
1261fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    protected final void sendMessageAtFrontOfQueue(Message msg) {
1262fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.sendMessageAtFrontOfQueue(msg);
1263fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1264fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1265fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
12661b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * Conditionally quit the looper and stop execution.
12671b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     *
12681b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * This sends the HSM_QUIT_MSG to the state machine and
12691b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * if not handled by any state's processMessage then the
12701b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * state machine will be stopped and no further messages
12711b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * will be processed.
12721b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     */
12731b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    public final void quit() {
12741b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        mHsmHandler.quit();
12751b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    }
12761b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
12771b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    /**
12781b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     * @return ture if msg is quit
12791b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville     */
12801b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    protected final boolean isQuit(Message msg) {
12811b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville        return mHsmHandler.isQuit(msg);
12821b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    }
12831b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville
12841b8b98b3db5dcf0b01d1a632aafea076cc91f5a4Wink Saville    /**
1285fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @return if debugging is enabled
1286fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1287fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public boolean isDbg() {
1288fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        return mHsmHandler.isDbg();
1289fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1290fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1291fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1292fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Set debug enable/disabled.
1293fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     *
1294fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * @param dbg is true to enable debugging.
1295fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1296fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public void setDbg(boolean dbg) {
1297fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.setDbg(dbg);
1298fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1299fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville
1300fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    /**
1301fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     * Start the state machine.
1302fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville     */
1303fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    public void start() {
1304fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        /** Send the complete construction message */
1305fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville        mHsmHandler.completeConstruction();
1306fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville    }
1307fc5b4802a544b6ca304aa7e58a26018ef714d233Wink Saville}
1308