1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi.util; 18 19 import android.os.Message; 20 21 import com.android.internal.util.State; 22 import com.android.internal.util.StateMachine; 23 24 /** 25 * A generic WaitingState which will defer all messages. 26 * 27 * Note: if the state machine implements local transitions as opposed to external transitions 28 * (see https://en.wikipedia.org/wiki/UML_state_machine#Local_versus_external_transitions for a 29 * description) then this state can be added under the state which it is supposed to be blocking - 30 * it will prevent triggering local exit() and enter() methods on that state. However, the Android 31 * state machine does a mix of local and external transitions. Therefore, if the class which is 32 * being blocked has an enter() and/or exit() methods then modify the state machine structure: 33 * - Create a new container state which will have the enter() and exit() methods 34 * - Add both the original state (now without the enter() and exit() methods) and the waiting state 35 * to the container. 36 */ 37 public class WaitingState extends State { 38 private final StateMachine mParentStateMachine; 39 40 // message.what and message.getData() entries to try to guarantee no overlap with any containing 41 // state 42 private static final int MESSAGE_TYPE_TRANSITION = 0xFFFFFF; 43 private static final String MESSAGE_BUNDLE_KEY_UNIQUE_ID = "__waiting_state_unique_key"; 44 WaitingState(StateMachine parentStateMachine)45 public WaitingState(StateMachine parentStateMachine) { 46 mParentStateMachine = parentStateMachine; 47 } 48 49 @Override processMessage(Message message)50 public boolean processMessage(Message message) { 51 if (message.what == MESSAGE_TYPE_TRANSITION && message.getData().getBoolean( 52 MESSAGE_BUNDLE_KEY_UNIQUE_ID, false)) { 53 mParentStateMachine.transitionTo((State) message.obj); 54 } else { 55 mParentStateMachine.deferMessage(message); 56 } 57 return HANDLED; 58 } 59 60 /** 61 * Trigger a transition to another state. 62 * 63 * Note: has to be done as a message processing operation for the StateMachine to accept it 64 * and trigger state transition, deferred message processing. 65 */ sendTransitionStateCommand(State destState)66 public void sendTransitionStateCommand(State destState) { 67 Message message = mParentStateMachine.obtainMessage(MESSAGE_TYPE_TRANSITION, destState); 68 message.getData().putBoolean(MESSAGE_BUNDLE_KEY_UNIQUE_ID, true); 69 mParentStateMachine.sendMessage(message); 70 } 71 } 72