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