1a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu/* 2a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * Copyright (C) 2014 The Android Open Source Project 3a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * 4a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * in compliance with the License. You may obtain a copy of the License at 6a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * 7a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * http://www.apache.org/licenses/LICENSE-2.0 8a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * 9a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * Unless required by applicable law or agreed to in writing, software distributed under the License 10a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * or implied. See the License for the specific language governing permissions and limitations under 12a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * the License. 13a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 14a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gupackage android.support.v17.leanback.util; 15a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 168e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikasimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 178e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas 18c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo; 1989097f67f988ebba714a95e10369665280db0c27Dake Guimport android.util.Log; 20c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette 21a5a85434f936023043f074fb86eaa6d48f7f6411Dake Guimport java.util.ArrayList; 22a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 23a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu/** 2489097f67f988ebba714a95e10369665280db0c27Dake Gu * State: each State has incoming Transitions and outgoing Transitions. 2589097f67f988ebba714a95e10369665280db0c27Dake Gu * When {@link State#mBranchStart} is true, all the outgoing Transitions may be triggered, when 2689097f67f988ebba714a95e10369665280db0c27Dake Gu * {@link State#mBranchStart} is false, only first outgoing Transition will be triggered. 2789097f67f988ebba714a95e10369665280db0c27Dake Gu * When {@link State#mBranchEnd} is true, all the incoming Transitions must be triggered for the 2889097f67f988ebba714a95e10369665280db0c27Dake Gu * State to run. When {@link State#mBranchEnd} is false, only need one incoming Transition triggered 2989097f67f988ebba714a95e10369665280db0c27Dake Gu * for the State to run. 3089097f67f988ebba714a95e10369665280db0c27Dake Gu * Transition: three types: 3189097f67f988ebba714a95e10369665280db0c27Dake Gu * 1. Event based transition, transition will be triggered when {@link #fireEvent(Event)} is called. 3289097f67f988ebba714a95e10369665280db0c27Dake Gu * 2. Auto transition, transition will be triggered when {@link Transition#mFromState} is executed. 3389097f67f988ebba714a95e10369665280db0c27Dake Gu * 3. Condiitonal Auto transition, transition will be triggered when {@link Transition#mFromState} 3489097f67f988ebba714a95e10369665280db0c27Dake Gu * is executed and {@link Transition#mCondition} passes. 35a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * @hide 36a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 378e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas@RestrictTo(LIBRARY_GROUP) 38a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gupublic final class StateMachine { 39a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 4089097f67f988ebba714a95e10369665280db0c27Dake Gu static boolean DEBUG = false; 4189097f67f988ebba714a95e10369665280db0c27Dake Gu static final String TAG = "StateMachine"; 4289097f67f988ebba714a95e10369665280db0c27Dake Gu 43a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu /** 44a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * No request on the State 45a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 46a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu public static final int STATUS_ZERO = 0; 4789097f67f988ebba714a95e10369665280db0c27Dake Gu 48a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu /** 4989097f67f988ebba714a95e10369665280db0c27Dake Gu * Has been executed 50a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 51a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu public static final int STATUS_INVOKED = 1; 5289097f67f988ebba714a95e10369665280db0c27Dake Gu 53a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu /** 5489097f67f988ebba714a95e10369665280db0c27Dake Gu * Used in Transition 55a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 5689097f67f988ebba714a95e10369665280db0c27Dake Gu public static class Event { 5789097f67f988ebba714a95e10369665280db0c27Dake Gu final String mName; 58a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 5989097f67f988ebba714a95e10369665280db0c27Dake Gu public Event(String name) { 6089097f67f988ebba714a95e10369665280db0c27Dake Gu mName = name; 6189097f67f988ebba714a95e10369665280db0c27Dake Gu } 6289097f67f988ebba714a95e10369665280db0c27Dake Gu } 6389097f67f988ebba714a95e10369665280db0c27Dake Gu 6489097f67f988ebba714a95e10369665280db0c27Dake Gu /** 6589097f67f988ebba714a95e10369665280db0c27Dake Gu * Used in transition 6689097f67f988ebba714a95e10369665280db0c27Dake Gu */ 6789097f67f988ebba714a95e10369665280db0c27Dake Gu public static class Condition { 6889097f67f988ebba714a95e10369665280db0c27Dake Gu final String mName; 69a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 7089097f67f988ebba714a95e10369665280db0c27Dake Gu public Condition(String name) { 7189097f67f988ebba714a95e10369665280db0c27Dake Gu mName = name; 7289097f67f988ebba714a95e10369665280db0c27Dake Gu } 73a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 74a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu /** 7589097f67f988ebba714a95e10369665280db0c27Dake Gu * @return True if can proceed and mark the transition INVOKED 76a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 7789097f67f988ebba714a95e10369665280db0c27Dake Gu public boolean canProceed() { 7889097f67f988ebba714a95e10369665280db0c27Dake Gu return true; 7989097f67f988ebba714a95e10369665280db0c27Dake Gu } 8089097f67f988ebba714a95e10369665280db0c27Dake Gu } 8189097f67f988ebba714a95e10369665280db0c27Dake Gu 8289097f67f988ebba714a95e10369665280db0c27Dake Gu static class Transition { 8389097f67f988ebba714a95e10369665280db0c27Dake Gu final State mFromState; 8489097f67f988ebba714a95e10369665280db0c27Dake Gu final State mToState; 8589097f67f988ebba714a95e10369665280db0c27Dake Gu final Event mEvent; 8689097f67f988ebba714a95e10369665280db0c27Dake Gu final Condition mCondition; 8789097f67f988ebba714a95e10369665280db0c27Dake Gu int mState = STATUS_ZERO; 8889097f67f988ebba714a95e10369665280db0c27Dake Gu 8989097f67f988ebba714a95e10369665280db0c27Dake Gu Transition(State fromState, State toState, Event event) { 9089097f67f988ebba714a95e10369665280db0c27Dake Gu if (event == null) { 9189097f67f988ebba714a95e10369665280db0c27Dake Gu throw new IllegalArgumentException(); 9289097f67f988ebba714a95e10369665280db0c27Dake Gu } 9389097f67f988ebba714a95e10369665280db0c27Dake Gu mFromState = fromState; 9489097f67f988ebba714a95e10369665280db0c27Dake Gu mToState = toState; 9589097f67f988ebba714a95e10369665280db0c27Dake Gu mEvent = event; 9689097f67f988ebba714a95e10369665280db0c27Dake Gu mCondition = null; 9789097f67f988ebba714a95e10369665280db0c27Dake Gu } 9889097f67f988ebba714a95e10369665280db0c27Dake Gu 9989097f67f988ebba714a95e10369665280db0c27Dake Gu Transition(State fromState, State toState) { 10089097f67f988ebba714a95e10369665280db0c27Dake Gu mFromState = fromState; 10189097f67f988ebba714a95e10369665280db0c27Dake Gu mToState = toState; 10289097f67f988ebba714a95e10369665280db0c27Dake Gu mEvent = null; 10389097f67f988ebba714a95e10369665280db0c27Dake Gu mCondition = null; 10489097f67f988ebba714a95e10369665280db0c27Dake Gu } 10589097f67f988ebba714a95e10369665280db0c27Dake Gu 10689097f67f988ebba714a95e10369665280db0c27Dake Gu Transition(State fromState, State toState, Condition condition) { 10789097f67f988ebba714a95e10369665280db0c27Dake Gu if (condition == null) { 10889097f67f988ebba714a95e10369665280db0c27Dake Gu throw new IllegalArgumentException(); 10989097f67f988ebba714a95e10369665280db0c27Dake Gu } 11089097f67f988ebba714a95e10369665280db0c27Dake Gu mFromState = fromState; 11189097f67f988ebba714a95e10369665280db0c27Dake Gu mToState = toState; 11289097f67f988ebba714a95e10369665280db0c27Dake Gu mEvent = null; 11389097f67f988ebba714a95e10369665280db0c27Dake Gu mCondition = condition; 11489097f67f988ebba714a95e10369665280db0c27Dake Gu } 11589097f67f988ebba714a95e10369665280db0c27Dake Gu 11689097f67f988ebba714a95e10369665280db0c27Dake Gu @Override 11789097f67f988ebba714a95e10369665280db0c27Dake Gu public String toString() { 11889097f67f988ebba714a95e10369665280db0c27Dake Gu String signalName; 11989097f67f988ebba714a95e10369665280db0c27Dake Gu if (mEvent != null) { 12089097f67f988ebba714a95e10369665280db0c27Dake Gu signalName = mEvent.mName; 12189097f67f988ebba714a95e10369665280db0c27Dake Gu } else if (mCondition != null) { 12289097f67f988ebba714a95e10369665280db0c27Dake Gu signalName = mCondition.mName; 12389097f67f988ebba714a95e10369665280db0c27Dake Gu } else { 12489097f67f988ebba714a95e10369665280db0c27Dake Gu signalName = "auto"; 12589097f67f988ebba714a95e10369665280db0c27Dake Gu } 12689097f67f988ebba714a95e10369665280db0c27Dake Gu return "[" + mFromState.mName + " -> " + mToState.mName + " <" 12789097f67f988ebba714a95e10369665280db0c27Dake Gu + signalName + ">]"; 12889097f67f988ebba714a95e10369665280db0c27Dake Gu } 12989097f67f988ebba714a95e10369665280db0c27Dake Gu } 13089097f67f988ebba714a95e10369665280db0c27Dake Gu 13189097f67f988ebba714a95e10369665280db0c27Dake Gu /** 13289097f67f988ebba714a95e10369665280db0c27Dake Gu * @see StateMachine 13389097f67f988ebba714a95e10369665280db0c27Dake Gu */ 13489097f67f988ebba714a95e10369665280db0c27Dake Gu public static class State { 13589097f67f988ebba714a95e10369665280db0c27Dake Gu 13689097f67f988ebba714a95e10369665280db0c27Dake Gu final String mName; 13789097f67f988ebba714a95e10369665280db0c27Dake Gu final boolean mBranchStart; 13889097f67f988ebba714a95e10369665280db0c27Dake Gu final boolean mBranchEnd; 13989097f67f988ebba714a95e10369665280db0c27Dake Gu int mStatus = STATUS_ZERO; 14089097f67f988ebba714a95e10369665280db0c27Dake Gu int mInvokedOutTransitions = 0; 14189097f67f988ebba714a95e10369665280db0c27Dake Gu ArrayList<Transition> mIncomings; 14289097f67f988ebba714a95e10369665280db0c27Dake Gu ArrayList<Transition> mOutgoings; 14389097f67f988ebba714a95e10369665280db0c27Dake Gu 14489097f67f988ebba714a95e10369665280db0c27Dake Gu @Override 14589097f67f988ebba714a95e10369665280db0c27Dake Gu public String toString() { 14689097f67f988ebba714a95e10369665280db0c27Dake Gu return "[" + mName + " " + mStatus + "]"; 147a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 148a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 149a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu /** 15089097f67f988ebba714a95e10369665280db0c27Dake Gu * Create a State which is not branch start and a branch end. 151a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 15289097f67f988ebba714a95e10369665280db0c27Dake Gu public State(String name) { 15389097f67f988ebba714a95e10369665280db0c27Dake Gu this(name, false, true); 154a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 155a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 156a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu /** 15789097f67f988ebba714a95e10369665280db0c27Dake Gu * Create a State 15889097f67f988ebba714a95e10369665280db0c27Dake Gu * @param branchStart True if can run all out going transitions or false execute the first 15989097f67f988ebba714a95e10369665280db0c27Dake Gu * out going transition. 16089097f67f988ebba714a95e10369665280db0c27Dake Gu * @param branchEnd True if wait all incoming transitions executed or false 16189097f67f988ebba714a95e10369665280db0c27Dake Gu * only need one of the transition executed. 162a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 16389097f67f988ebba714a95e10369665280db0c27Dake Gu public State(String name, boolean branchStart, boolean branchEnd) { 16489097f67f988ebba714a95e10369665280db0c27Dake Gu mName = name; 16589097f67f988ebba714a95e10369665280db0c27Dake Gu mBranchStart = branchStart; 16689097f67f988ebba714a95e10369665280db0c27Dake Gu mBranchEnd = branchEnd; 16789097f67f988ebba714a95e10369665280db0c27Dake Gu } 16889097f67f988ebba714a95e10369665280db0c27Dake Gu 16989097f67f988ebba714a95e10369665280db0c27Dake Gu void addIncoming(Transition t) { 17089097f67f988ebba714a95e10369665280db0c27Dake Gu if (mIncomings == null) { 17189097f67f988ebba714a95e10369665280db0c27Dake Gu mIncomings = new ArrayList(); 172a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 17389097f67f988ebba714a95e10369665280db0c27Dake Gu mIncomings.add(t); 17489097f67f988ebba714a95e10369665280db0c27Dake Gu } 17589097f67f988ebba714a95e10369665280db0c27Dake Gu 17689097f67f988ebba714a95e10369665280db0c27Dake Gu void addOutgoing(Transition t) { 17789097f67f988ebba714a95e10369665280db0c27Dake Gu if (mOutgoings == null) { 17889097f67f988ebba714a95e10369665280db0c27Dake Gu mOutgoings = new ArrayList(); 17989097f67f988ebba714a95e10369665280db0c27Dake Gu } 18089097f67f988ebba714a95e10369665280db0c27Dake Gu mOutgoings.add(t); 18189097f67f988ebba714a95e10369665280db0c27Dake Gu } 18289097f67f988ebba714a95e10369665280db0c27Dake Gu 18389097f67f988ebba714a95e10369665280db0c27Dake Gu /** 18489097f67f988ebba714a95e10369665280db0c27Dake Gu * Run State, Subclass may override. 18589097f67f988ebba714a95e10369665280db0c27Dake Gu */ 18689097f67f988ebba714a95e10369665280db0c27Dake Gu public void run() { 187a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 188a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 18989097f67f988ebba714a95e10369665280db0c27Dake Gu final boolean checkPreCondition() { 19089097f67f988ebba714a95e10369665280db0c27Dake Gu if (mIncomings == null) { 19189097f67f988ebba714a95e10369665280db0c27Dake Gu return true; 192a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 19389097f67f988ebba714a95e10369665280db0c27Dake Gu if (mBranchEnd) { 19489097f67f988ebba714a95e10369665280db0c27Dake Gu for (Transition t: mIncomings) { 19589097f67f988ebba714a95e10369665280db0c27Dake Gu if (t.mState != STATUS_INVOKED) { 19689097f67f988ebba714a95e10369665280db0c27Dake Gu return false; 19789097f67f988ebba714a95e10369665280db0c27Dake Gu } 19889097f67f988ebba714a95e10369665280db0c27Dake Gu } 19989097f67f988ebba714a95e10369665280db0c27Dake Gu return true; 20089097f67f988ebba714a95e10369665280db0c27Dake Gu } else { 20189097f67f988ebba714a95e10369665280db0c27Dake Gu for (Transition t: mIncomings) { 20289097f67f988ebba714a95e10369665280db0c27Dake Gu if (t.mState == STATUS_INVOKED) { 20389097f67f988ebba714a95e10369665280db0c27Dake Gu return true; 20489097f67f988ebba714a95e10369665280db0c27Dake Gu } 20589097f67f988ebba714a95e10369665280db0c27Dake Gu } 20689097f67f988ebba714a95e10369665280db0c27Dake Gu return false; 207a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 208a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 209a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 21089097f67f988ebba714a95e10369665280db0c27Dake Gu /** 21189097f67f988ebba714a95e10369665280db0c27Dake Gu * @return True if the State has been executed. 21289097f67f988ebba714a95e10369665280db0c27Dake Gu */ 21389097f67f988ebba714a95e10369665280db0c27Dake Gu final boolean runIfNeeded() { 21489097f67f988ebba714a95e10369665280db0c27Dake Gu if (mStatus != STATUS_INVOKED) { 21589097f67f988ebba714a95e10369665280db0c27Dake Gu if (checkPreCondition()) { 21689097f67f988ebba714a95e10369665280db0c27Dake Gu if (DEBUG) { 21789097f67f988ebba714a95e10369665280db0c27Dake Gu Log.d(TAG, "execute " + this); 21889097f67f988ebba714a95e10369665280db0c27Dake Gu } 21989097f67f988ebba714a95e10369665280db0c27Dake Gu mStatus = STATUS_INVOKED; 22089097f67f988ebba714a95e10369665280db0c27Dake Gu run(); 22189097f67f988ebba714a95e10369665280db0c27Dake Gu signalAutoTransitionsAfterRun(); 22289097f67f988ebba714a95e10369665280db0c27Dake Gu return true; 22389097f67f988ebba714a95e10369665280db0c27Dake Gu } 224a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 22589097f67f988ebba714a95e10369665280db0c27Dake Gu return false; 226a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 227a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 22889097f67f988ebba714a95e10369665280db0c27Dake Gu final void signalAutoTransitionsAfterRun() { 22989097f67f988ebba714a95e10369665280db0c27Dake Gu if (mOutgoings != null) { 23089097f67f988ebba714a95e10369665280db0c27Dake Gu for (Transition t: mOutgoings) { 23189097f67f988ebba714a95e10369665280db0c27Dake Gu if (t.mEvent == null) { 23289097f67f988ebba714a95e10369665280db0c27Dake Gu if (t.mCondition == null || t.mCondition.canProceed()) { 23389097f67f988ebba714a95e10369665280db0c27Dake Gu if (DEBUG) { 23489097f67f988ebba714a95e10369665280db0c27Dake Gu Log.d(TAG, "signal " + t); 23589097f67f988ebba714a95e10369665280db0c27Dake Gu } 23689097f67f988ebba714a95e10369665280db0c27Dake Gu mInvokedOutTransitions++; 23789097f67f988ebba714a95e10369665280db0c27Dake Gu t.mState = STATUS_INVOKED; 23889097f67f988ebba714a95e10369665280db0c27Dake Gu if (!mBranchStart) { 23989097f67f988ebba714a95e10369665280db0c27Dake Gu break; 24089097f67f988ebba714a95e10369665280db0c27Dake Gu } 24189097f67f988ebba714a95e10369665280db0c27Dake Gu } 24289097f67f988ebba714a95e10369665280db0c27Dake Gu } 24389097f67f988ebba714a95e10369665280db0c27Dake Gu } 24489097f67f988ebba714a95e10369665280db0c27Dake Gu } 245a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 246a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 247a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu /** 24889097f67f988ebba714a95e10369665280db0c27Dake Gu * Get status, return one of {@link #STATUS_ZERO}, {@link #STATUS_INVOKED}. 249a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * @return Status of the State. 250a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 251a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu public final int getStatus() { 252a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu return mStatus; 253a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 254a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 255a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 25689097f67f988ebba714a95e10369665280db0c27Dake Gu final ArrayList<State> mStates = new ArrayList<State>(); 25789097f67f988ebba714a95e10369665280db0c27Dake Gu final ArrayList<State> mFinishedStates = new ArrayList(); 25889097f67f988ebba714a95e10369665280db0c27Dake Gu final ArrayList<State> mUnfinishedStates = new ArrayList(); 25989097f67f988ebba714a95e10369665280db0c27Dake Gu 26089097f67f988ebba714a95e10369665280db0c27Dake Gu public StateMachine() { 26189097f67f988ebba714a95e10369665280db0c27Dake Gu } 262a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 263a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu /** 264a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * Add a State to StateMachine, ignore if it is already added. 265a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu * @param state The state to add. 266a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 267a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu public void addState(State state) { 26889097f67f988ebba714a95e10369665280db0c27Dake Gu if (!mStates.contains(state)) { 26989097f67f988ebba714a95e10369665280db0c27Dake Gu mStates.add(state); 270a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 271a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 272a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 273a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu /** 27489097f67f988ebba714a95e10369665280db0c27Dake Gu * Add event-triggered transition between two states. 27589097f67f988ebba714a95e10369665280db0c27Dake Gu * @param fromState The from state. 27689097f67f988ebba714a95e10369665280db0c27Dake Gu * @param toState The to state. 27789097f67f988ebba714a95e10369665280db0c27Dake Gu * @param event The event that needed to perform the transition. 278a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 27989097f67f988ebba714a95e10369665280db0c27Dake Gu public void addTransition(State fromState, State toState, Event event) { 28089097f67f988ebba714a95e10369665280db0c27Dake Gu Transition transition = new Transition(fromState, toState, event); 28189097f67f988ebba714a95e10369665280db0c27Dake Gu toState.addIncoming(transition); 28289097f67f988ebba714a95e10369665280db0c27Dake Gu fromState.addOutgoing(transition); 283a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 284a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 28589097f67f988ebba714a95e10369665280db0c27Dake Gu /** 28689097f67f988ebba714a95e10369665280db0c27Dake Gu * Add a conditional auto transition between two states. 28789097f67f988ebba714a95e10369665280db0c27Dake Gu * @param fromState The from state. 28889097f67f988ebba714a95e10369665280db0c27Dake Gu * @param toState The to state. 28989097f67f988ebba714a95e10369665280db0c27Dake Gu */ 29089097f67f988ebba714a95e10369665280db0c27Dake Gu public void addTransition(State fromState, State toState, Condition condition) { 29189097f67f988ebba714a95e10369665280db0c27Dake Gu Transition transition = new Transition(fromState, toState, condition); 29289097f67f988ebba714a95e10369665280db0c27Dake Gu toState.addIncoming(transition); 29389097f67f988ebba714a95e10369665280db0c27Dake Gu fromState.addOutgoing(transition); 294a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 295a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 29689097f67f988ebba714a95e10369665280db0c27Dake Gu /** 29789097f67f988ebba714a95e10369665280db0c27Dake Gu * Add an auto transition between two states. 29889097f67f988ebba714a95e10369665280db0c27Dake Gu * @param fromState The from state to add. 29989097f67f988ebba714a95e10369665280db0c27Dake Gu * @param toState The to state to add. 30089097f67f988ebba714a95e10369665280db0c27Dake Gu */ 30189097f67f988ebba714a95e10369665280db0c27Dake Gu public void addTransition(State fromState, State toState) { 30289097f67f988ebba714a95e10369665280db0c27Dake Gu Transition transition = new Transition(fromState, toState); 30389097f67f988ebba714a95e10369665280db0c27Dake Gu toState.addIncoming(transition); 30489097f67f988ebba714a95e10369665280db0c27Dake Gu fromState.addOutgoing(transition); 305a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 306a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 30789097f67f988ebba714a95e10369665280db0c27Dake Gu /** 30889097f67f988ebba714a95e10369665280db0c27Dake Gu * Start the state machine. 30989097f67f988ebba714a95e10369665280db0c27Dake Gu */ 31089097f67f988ebba714a95e10369665280db0c27Dake Gu public void start() { 31189097f67f988ebba714a95e10369665280db0c27Dake Gu if (DEBUG) { 31289097f67f988ebba714a95e10369665280db0c27Dake Gu Log.d(TAG, "start"); 313a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 31489097f67f988ebba714a95e10369665280db0c27Dake Gu mUnfinishedStates.addAll(mStates); 31589097f67f988ebba714a95e10369665280db0c27Dake Gu runUnfinishedStates(); 316a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 317a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 31889097f67f988ebba714a95e10369665280db0c27Dake Gu void runUnfinishedStates() { 31989097f67f988ebba714a95e10369665280db0c27Dake Gu boolean changed; 32089097f67f988ebba714a95e10369665280db0c27Dake Gu do { 32189097f67f988ebba714a95e10369665280db0c27Dake Gu changed = false; 32289097f67f988ebba714a95e10369665280db0c27Dake Gu for (int i = mUnfinishedStates.size() - 1; i >= 0; i--) { 32389097f67f988ebba714a95e10369665280db0c27Dake Gu State state = mUnfinishedStates.get(i); 32489097f67f988ebba714a95e10369665280db0c27Dake Gu if (state.runIfNeeded()) { 32589097f67f988ebba714a95e10369665280db0c27Dake Gu mUnfinishedStates.remove(i); 32689097f67f988ebba714a95e10369665280db0c27Dake Gu mFinishedStates.add(state); 32789097f67f988ebba714a95e10369665280db0c27Dake Gu changed = true; 32889097f67f988ebba714a95e10369665280db0c27Dake Gu } 32989097f67f988ebba714a95e10369665280db0c27Dake Gu } 33089097f67f988ebba714a95e10369665280db0c27Dake Gu } while (changed); 331a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 332a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 333a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu /** 33489097f67f988ebba714a95e10369665280db0c27Dake Gu * Find outgoing Transitions of invoked State whose Event matches, mark the Transition invoked. 335a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu */ 33689097f67f988ebba714a95e10369665280db0c27Dake Gu public void fireEvent(Event event) { 33789097f67f988ebba714a95e10369665280db0c27Dake Gu for (int i = 0; i < mFinishedStates.size(); i++) { 33889097f67f988ebba714a95e10369665280db0c27Dake Gu State state = mFinishedStates.get(i); 33989097f67f988ebba714a95e10369665280db0c27Dake Gu if (state.mOutgoings != null) { 34089097f67f988ebba714a95e10369665280db0c27Dake Gu if (!state.mBranchStart && state.mInvokedOutTransitions > 0) { 34189097f67f988ebba714a95e10369665280db0c27Dake Gu continue; 34289097f67f988ebba714a95e10369665280db0c27Dake Gu } 34389097f67f988ebba714a95e10369665280db0c27Dake Gu for (Transition t : state.mOutgoings) { 34489097f67f988ebba714a95e10369665280db0c27Dake Gu if (t.mState != STATUS_INVOKED && t.mEvent == event) { 34589097f67f988ebba714a95e10369665280db0c27Dake Gu if (DEBUG) { 34689097f67f988ebba714a95e10369665280db0c27Dake Gu Log.d(TAG, "signal " + t); 34789097f67f988ebba714a95e10369665280db0c27Dake Gu } 34889097f67f988ebba714a95e10369665280db0c27Dake Gu t.mState = STATUS_INVOKED; 34989097f67f988ebba714a95e10369665280db0c27Dake Gu state.mInvokedOutTransitions++; 35089097f67f988ebba714a95e10369665280db0c27Dake Gu if (!state.mBranchStart) { 35189097f67f988ebba714a95e10369665280db0c27Dake Gu break; 35289097f67f988ebba714a95e10369665280db0c27Dake Gu } 35389097f67f988ebba714a95e10369665280db0c27Dake Gu } 35489097f67f988ebba714a95e10369665280db0c27Dake Gu } 355a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 356a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 35789097f67f988ebba714a95e10369665280db0c27Dake Gu runUnfinishedStates(); 35889097f67f988ebba714a95e10369665280db0c27Dake Gu } 359a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu 36089097f67f988ebba714a95e10369665280db0c27Dake Gu /** 36189097f67f988ebba714a95e10369665280db0c27Dake Gu * Reset status to orignal status 36289097f67f988ebba714a95e10369665280db0c27Dake Gu */ 36389097f67f988ebba714a95e10369665280db0c27Dake Gu public void reset() { 36489097f67f988ebba714a95e10369665280db0c27Dake Gu if (DEBUG) { 36589097f67f988ebba714a95e10369665280db0c27Dake Gu Log.d(TAG, "reset"); 36689097f67f988ebba714a95e10369665280db0c27Dake Gu } 36789097f67f988ebba714a95e10369665280db0c27Dake Gu mUnfinishedStates.clear(); 36889097f67f988ebba714a95e10369665280db0c27Dake Gu mFinishedStates.clear(); 36989097f67f988ebba714a95e10369665280db0c27Dake Gu for (State state: mStates) { 37089097f67f988ebba714a95e10369665280db0c27Dake Gu state.mStatus = STATUS_ZERO; 37189097f67f988ebba714a95e10369665280db0c27Dake Gu state.mInvokedOutTransitions = 0; 37289097f67f988ebba714a95e10369665280db0c27Dake Gu if (state.mOutgoings != null) { 37389097f67f988ebba714a95e10369665280db0c27Dake Gu for (Transition t: state.mOutgoings) { 37489097f67f988ebba714a95e10369665280db0c27Dake Gu t.mState = STATUS_ZERO; 375a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 376a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 377a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 378a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu } 379a5a85434f936023043f074fb86eaa6d48f7f6411Dake Gu} 380