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