17f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie/*
27f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie * Copyright (C) 2011 The Android Open Source Project
37f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *
47f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie * Licensed under the Apache License, Version 2.0 (the "License");
57f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie * you may not use this file except in compliance with the License.
67f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie * You may obtain a copy of the License at
77f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *
87f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *      http://www.apache.org/licenses/LICENSE-2.0
97f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *
107f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie * Unless required by applicable law or agreed to in writing, software
117f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie * distributed under the License is distributed on an "AS IS" BASIS,
127f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie * See the License for the specific language governing permissions and
147f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie * limitations under the License.
157f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie */
167f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
177f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xiepackage android.server;
187f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
197f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport android.bluetooth.BluetoothAdapter;
20ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganeshimport android.bluetooth.IBluetoothStateChangeCallback;
217f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport android.content.ContentResolver;
227f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport android.content.Context;
237f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport android.content.Intent;
247f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport android.os.Binder;
257f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport android.os.Message;
26ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganeshimport android.os.RemoteException;
277f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport android.provider.Settings;
287f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport android.util.Log;
297f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
307f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport com.android.internal.util.IState;
317f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport com.android.internal.util.State;
327f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport com.android.internal.util.StateMachine;
337f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
347f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xieimport java.io.PrintWriter;
357f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
367f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie/**
377f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie * Bluetooth Adapter StateMachine
387f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie * All the states are at the same level, ie, no hierarchy.
39ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh *                         (BluetootOn)<----------------------<-
40ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh *                           |    ^    -------------------->-  |
41ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh *                           |    |                         |  |
4214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie *                 TURN_OFF  |    | SCAN_MODE_CHANGED    m1 |  | USER_TURN_ON
43ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh *         AIRPLANE_MODE_ON  |    |                         |  |
44ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh *                           V    |                         |  |
45ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh *                         (Switching)                   (PerProcessState)
46ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh *                           |    ^                         |  |
4714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie *     POWER_STATE_CHANGED & |    | TURN_ON(_CONTINUE)      |  |
48ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh * ALL_DEVICES_DISCONNECTED  |    |                     m2  |  |
4914e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie *                           V    |------------------------<   | SCAN_MODE_CHANGED
509a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie *                          (HotOff)-------------------------->- PER_PROCESS_TURN_ON
517f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *                           /    ^
527f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *                          /     |  SERVICE_RECORD_LOADED
537f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *                         |      |
547f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *              TURN_COLD  |   (Warmup)
557f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *                         \      ^
567f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *                          \     |  TURN_HOT/TURN_ON
577f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *                           |    |  AIRPLANE_MODE_OFF(when Bluetooth was on before)
587f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *                           V    |
597f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *                           (PowerOff)   <----- initial state
607f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie *
61ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh * Legend:
629a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie * m1 = TURN_HOT
63ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh * m2 = Transition to HotOff when number of process wanting BT on is 0.
6414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie *      POWER_STATE_CHANGED will make the transition.
657f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie */
667f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xiefinal class BluetoothAdapterStateMachine extends StateMachine {
677f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private static final String TAG = "BluetoothAdapterStateMachine";
687f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private static final boolean DBG = false;
697f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
707f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // Message(what) to take an action
717f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    //
727f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // We get this message when user tries to turn on BT
73ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    static final int USER_TURN_ON = 1;
747f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // We get this message when user tries to turn off BT
75ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    static final int USER_TURN_OFF = 2;
769a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie    // Per process enable / disable messages
779a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie    static final int PER_PROCESS_TURN_ON = 3;
789a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie    static final int PER_PROCESS_TURN_OFF = 4;
797f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
809de1feb673499519cb380a142ba1e453109480bdMatthew Xie    // Turn on Bluetooth Module, Load firmware, and do all the preparation
819de1feb673499519cb380a142ba1e453109480bdMatthew Xie    // needed to get the Bluetooth Module ready but keep it not discoverable
829de1feb673499519cb380a142ba1e453109480bdMatthew Xie    // and not connectable. This way the Bluetooth Module can be quickly
839de1feb673499519cb380a142ba1e453109480bdMatthew Xie    // switched on if needed
849de1feb673499519cb380a142ba1e453109480bdMatthew Xie    static final int TURN_HOT = 5;
859de1feb673499519cb380a142ba1e453109480bdMatthew Xie
867f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // Message(what) to report a event that the state machine need to respond to
877f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    //
887f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // Event indicates sevice records have been loaded
89ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    static final int SERVICE_RECORD_LOADED = 51;
907f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // Event indicates all the remote Bluetooth devices has been disconnected
91ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    static final int ALL_DEVICES_DISCONNECTED = 52;
9214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    // Event indicates the Bluetooth scan mode has changed
9314e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    static final int SCAN_MODE_CHANGED = 53;
9414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    // Event indicates the powered state has changed
9514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    static final int POWER_STATE_CHANGED = 54;
967f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // Event indicates airplane mode is turned on
97ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    static final int AIRPLANE_MODE_ON = 55;
987f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // Event indicates airplane mode is turned off
99ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    static final int AIRPLANE_MODE_OFF = 56;
1007f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
1017f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // private internal messages
1027f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    //
1037f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // USER_TURN_ON is changed to TURN_ON_CONTINUE after we broadcast the
1047f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // state change intent so that we will not broadcast the intent again in
1057f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // other state
1069de1feb673499519cb380a142ba1e453109480bdMatthew Xie    private static final int TURN_ON_CONTINUE = 101;
1077f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // Unload firmware, turning off Bluetooth module power
1089de1feb673499519cb380a142ba1e453109480bdMatthew Xie    private static final int TURN_COLD = 102;
1099a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie    // Device disconnecting timeout happens
1109de1feb673499519cb380a142ba1e453109480bdMatthew Xie    private static final int DEVICES_DISCONNECT_TIMEOUT = 103;
11114e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    // Prepare Bluetooth timeout happens
1129de1feb673499519cb380a142ba1e453109480bdMatthew Xie    private static final int PREPARE_BLUETOOTH_TIMEOUT = 104;
113694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie    // Bluetooth Powerdown timeout happens
1149de1feb673499519cb380a142ba1e453109480bdMatthew Xie    private static final int POWER_DOWN_TIMEOUT = 105;
1157f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
1167f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private Context mContext;
1177f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private BluetoothService mBluetoothService;
1187f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private BluetoothEventLoop mEventLoop;
1197f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
1207f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private BluetoothOn mBluetoothOn;
1217f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private Switching mSwitching;
1227f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private HotOff mHotOff;
1237f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private WarmUp mWarmUp;
1247f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private PowerOff mPowerOff;
125ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    private PerProcessState mPerProcessState;
1267f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
1277f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    // this is the BluetoothAdapter state that reported externally
1287f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private int mPublicState;
1297f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
1309a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie    // timeout value waiting for all the devices to be disconnected
1319a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie    private static final int DEVICES_DISCONNECT_TIMEOUT_TIME = 3000;
1329a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie
13325c4e2a8032c38f6336f7f49e464c95c7b8798f2Matthew Xie    private static final int PREPARE_BLUETOOTH_TIMEOUT_TIME = 10000;
13414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie
135694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie    private static final int POWER_DOWN_TIMEOUT_TIME = 5000;
136694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie
1377f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    BluetoothAdapterStateMachine(Context context, BluetoothService bluetoothService,
1387f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                                 BluetoothAdapter bluetoothAdapter) {
1397f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        super(TAG);
1407f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mContext = context;
1417f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mBluetoothService = bluetoothService;
1427f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mEventLoop = new BluetoothEventLoop(context, bluetoothAdapter, bluetoothService, this);
1437f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
1447f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mBluetoothOn = new BluetoothOn();
1457f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mSwitching = new Switching();
1467f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mHotOff = new HotOff();
1477f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mWarmUp = new WarmUp();
1487f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mPowerOff = new PowerOff();
149ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        mPerProcessState = new PerProcessState();
1507f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
1517f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        addState(mBluetoothOn);
1527f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        addState(mSwitching);
1537f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        addState(mHotOff);
1547f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        addState(mWarmUp);
1557f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        addState(mPowerOff);
156ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        addState(mPerProcessState);
157ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1587f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        setInitialState(mPowerOff);
1597f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mPublicState = BluetoothAdapter.STATE_OFF;
1607f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
1617f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
1627f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /**
1637f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * Bluetooth module's power is off, firmware is not loaded.
1647f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     */
1657f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private class PowerOff extends State {
1667f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        @Override
1677f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        public void enter() {
1688594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie            if (DBG) log("Enter PowerOff: " + getCurrentMessage().what);
1697f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
1707f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        @Override
1717f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        public boolean processMessage(Message message) {
17214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            log("PowerOff process message: " + message.what);
1737f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
1747f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            boolean retValue = HANDLED;
1757f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            switch(message.what) {
1767f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case USER_TURN_ON:
1777f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    // starts turning on BT module, broadcast this out
1787f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    broadcastState(BluetoothAdapter.STATE_TURNING_ON);
179a6ba6fd4bb931ba7c1cbda6adc8452609ea80dacMatthew Xie                    transitionTo(mWarmUp);
1807f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    if (prepareBluetooth()) {
1817f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        // this is user request, save the setting
1827f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        if ((Boolean) message.obj) {
183ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                            persistSwitchSetting(true);
1847f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        }
1857f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        // We will continue turn the BT on all the way to the BluetoothOn state
1867f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        deferMessage(obtainMessage(TURN_ON_CONTINUE));
1877f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    } else {
1887f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        Log.e(TAG, "failed to prepare bluetooth, abort turning on");
1897f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        transitionTo(mPowerOff);
1907f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        broadcastState(BluetoothAdapter.STATE_OFF);
1917f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    }
1927f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
1937f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case TURN_HOT:
1947f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    if (prepareBluetooth()) {
1957f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        transitionTo(mWarmUp);
1967f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    }
1977f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
1987f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case AIRPLANE_MODE_OFF:
1997f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    if (getBluetoothPersistedSetting()) {
2007f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        // starts turning on BT module, broadcast this out
2017f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        broadcastState(BluetoothAdapter.STATE_TURNING_ON);
202a6ba6fd4bb931ba7c1cbda6adc8452609ea80dacMatthew Xie                        transitionTo(mWarmUp);
2037f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        if (prepareBluetooth()) {
2047f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                            // We will continue turn the BT on all the way to the BluetoothOn state
2057f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                            deferMessage(obtainMessage(TURN_ON_CONTINUE));
2067f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                            transitionTo(mWarmUp);
2077f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        } else {
2087f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                            Log.e(TAG, "failed to prepare bluetooth, abort turning on");
2097f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                            transitionTo(mPowerOff);
2107f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                            broadcastState(BluetoothAdapter.STATE_OFF);
2117f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        }
212ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    } else if (mContext.getResources().getBoolean
213ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                            (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
214ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        sendMessage(TURN_HOT);
2157f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    }
2167f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
217ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case PER_PROCESS_TURN_ON:
218ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    if (prepareBluetooth()) {
219ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        transitionTo(mWarmUp);
220ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    }
221ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    deferMessage(obtainMessage(PER_PROCESS_TURN_ON));
222ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
223ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case PER_PROCESS_TURN_OFF:
224ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    perProcessCallback(false, (IBluetoothStateChangeCallback) message.obj);
225ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
2269a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                case USER_TURN_OFF:
2279a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    Log.w(TAG, "PowerOff received: " + message.what);
2289a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                case AIRPLANE_MODE_ON: // ignore
2297f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
2307f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                default:
2317f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    return NOT_HANDLED;
2327f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            }
2337f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            return retValue;
2347f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
2357f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
2367f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        /**
2377f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie         * Turn on Bluetooth Module, Load firmware, and do all the preparation
2387f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie         * needed to get the Bluetooth Module ready but keep it not discoverable
2397f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie         * and not connectable.
2407f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie         * The last step of this method sets up the local service record DB.
2417f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie         * There will be a event reporting the status of the SDP setup.
2427f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie         */
2437f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        private boolean prepareBluetooth() {
2447f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            if (mBluetoothService.enableNative() != 0) {
2457f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                return false;
2467f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            }
2477f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
2487f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            // try to start event loop, give 2 attempts
2497f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            int retryCount = 2;
2507f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            boolean eventLoopStarted = false;
2517f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            while ((retryCount-- > 0) && !eventLoopStarted) {
2527f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                mEventLoop.start();
2537f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                // it may take a moment for the other thread to do its
2547f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                // thing.  Check periodically for a while.
2557f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                int pollCount = 5;
2567f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                while ((pollCount-- > 0) && !eventLoopStarted) {
2577f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    if (mEventLoop.isEventLoopRunning()) {
2587f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        eventLoopStarted = true;
2597f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        break;
2607f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    }
2617f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    try {
2627f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        Thread.sleep(100);
2637f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    } catch (InterruptedException e) {
26414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        log("prepareBluetooth sleep interrupted: " + pollCount);
2657f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        break;
2667f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    }
2677f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                }
2687f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            }
2697f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
2707f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            if (!eventLoopStarted) {
2717f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                mBluetoothService.disableNative();
2727f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                return false;
2737f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            }
2747f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
2757f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            // get BluetoothService ready
2767f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            if (!mBluetoothService.prepareBluetooth()) {
2777f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                mEventLoop.stop();
2787f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                mBluetoothService.disableNative();
2797f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                return false;
2807f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            }
2817f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
28214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            sendMessageDelayed(PREPARE_BLUETOOTH_TIMEOUT, PREPARE_BLUETOOTH_TIMEOUT_TIME);
2837f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            return true;
2847f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
2857f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
2867f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
2877f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /**
2887f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * Turning on Bluetooth module's power, loading firmware, starting
2897f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * event loop thread to listen on Bluetooth module event changes.
2907f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     */
2917f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private class WarmUp extends State {
2927f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
2937f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        @Override
2947f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        public void enter() {
2958594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie            if (DBG) log("Enter WarmUp: " + getCurrentMessage().what);
2967f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
2977f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
2987f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        @Override
2997f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        public boolean processMessage(Message message) {
30014e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            log("WarmUp process message: " + message.what);
3017f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
3027f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            boolean retValue = HANDLED;
3037f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            switch(message.what) {
3047f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case SERVICE_RECORD_LOADED:
30514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    removeMessages(PREPARE_BLUETOOTH_TIMEOUT);
3067f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    transitionTo(mHotOff);
3077f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
30814e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                case PREPARE_BLUETOOTH_TIMEOUT:
30914e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    Log.e(TAG, "Bluetooth adapter SDP failed to load");
31014e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    shutoffBluetooth();
31114e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    transitionTo(mPowerOff);
31214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    broadcastState(BluetoothAdapter.STATE_OFF);
31314e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    break;
3147f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case USER_TURN_ON: // handle this at HotOff state
3157f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case TURN_ON_CONTINUE: // Once in HotOff state, continue turn bluetooth
3167f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                                       // on to the BluetoothOn state
3177f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case AIRPLANE_MODE_ON:
3187f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case AIRPLANE_MODE_OFF:
319ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case PER_PROCESS_TURN_ON:
320ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case PER_PROCESS_TURN_OFF:
3217f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    deferMessage(message);
3227f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
3239a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                case USER_TURN_OFF:
3249a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    Log.w(TAG, "WarmUp received: " + message.what);
3257f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
3267f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                default:
3277f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    return NOT_HANDLED;
3287f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            }
3297f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            return retValue;
3307f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
3317f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
3327f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
3337f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
3347f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /**
3357f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * Bluetooth Module has powered, firmware loaded, event loop started,
3367f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * SDP loaded, but the modules stays non-discoverable and
3377f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * non-connectable.
3387f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     */
3397f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private class HotOff extends State {
3407f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        @Override
3417f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        public void enter() {
3428594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie            if (DBG) log("Enter HotOff: " + getCurrentMessage().what);
3437f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
3447f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
3457f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        @Override
3467f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        public boolean processMessage(Message message) {
34714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            log("HotOff process message: " + message.what);
3487f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
3497f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            boolean retValue = HANDLED;
3507f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            switch(message.what) {
3517f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case USER_TURN_ON:
3522d789e58a8d2665b980fa952ba233cdde40f0157Matthew Xie                    broadcastState(BluetoothAdapter.STATE_TURNING_ON);
3537f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    if ((Boolean) message.obj) {
354ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        persistSwitchSetting(true);
3557f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    }
3567f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    // let it fall to TURN_ON_CONTINUE:
357ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    //$FALL-THROUGH$
3587f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case TURN_ON_CONTINUE:
3597f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    mBluetoothService.switchConnectable(true);
3607f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    transitionTo(mSwitching);
3617f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
3627f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case AIRPLANE_MODE_ON:
3637f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case TURN_COLD:
36414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    shutoffBluetooth();
3657f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    transitionTo(mPowerOff);
3667f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    broadcastState(BluetoothAdapter.STATE_OFF);
3677f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
3687f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case AIRPLANE_MODE_OFF:
3697f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    if (getBluetoothPersistedSetting()) {
370a6ba6fd4bb931ba7c1cbda6adc8452609ea80dacMatthew Xie                        broadcastState(BluetoothAdapter.STATE_TURNING_ON);
3717f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        transitionTo(mSwitching);
372ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        mBluetoothService.switchConnectable(true);
3737f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    }
3747f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
375ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case PER_PROCESS_TURN_ON:
376ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    transitionTo(mPerProcessState);
377ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
378ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    // Resend the PER_PROCESS_TURN_ON message so that the callback
379ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    // can be sent through.
380ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    deferMessage(message);
381ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
382ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    mBluetoothService.switchConnectable(true);
383ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
384ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case PER_PROCESS_TURN_OFF:
385ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
386ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
3879a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                case USER_TURN_OFF: // ignore
3889a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    break;
389694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                case POWER_STATE_CHANGED:
390694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    if ((Boolean) message.obj) {
391694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        recoverStateMachine(TURN_HOT, null);
392694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    }
393694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    break;
3947f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                default:
3957f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    return NOT_HANDLED;
3967f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            }
3977f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            return retValue;
3987f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
3997f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
4007f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
4017f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
4027f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private class Switching extends State {
4037f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
4047f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        @Override
4057f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        public void enter() {
4068594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie            if (DBG) log("Enter Switching: " + getCurrentMessage().what);
4077f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
4087f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        @Override
4097f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        public boolean processMessage(Message message) {
41014e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            log("Switching process message: " + message.what);
4117f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
4127f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            boolean retValue = HANDLED;
4137f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            switch(message.what) {
41414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                case SCAN_MODE_CHANGED:
41514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    // This event matches mBluetoothService.switchConnectable action
41614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    if (mPublicState == BluetoothAdapter.STATE_TURNING_ON) {
41714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        // set pairable if it's not
41814e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        mBluetoothService.setPairable();
41914e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        mBluetoothService.initBluetoothAfterTurningOn();
42014e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        transitionTo(mBluetoothOn);
42114e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        broadcastState(BluetoothAdapter.STATE_ON);
42214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        // run bluetooth now that it's turned on
42314e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        // Note runBluetooth should be called only in adapter STATE_ON
42414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        mBluetoothService.runBluetooth();
42514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    }
4267f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
42714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                case POWER_STATE_CHANGED:
428694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    removeMessages(POWER_DOWN_TIMEOUT);
42914e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    if (!((Boolean) message.obj)) {
430694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        if (mPublicState == BluetoothAdapter.STATE_TURNING_OFF) {
431694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                            transitionTo(mHotOff);
432694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                            finishSwitchingOff();
433dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie                            if (!mContext.getResources().getBoolean
434dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie                            (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
435dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie                                deferMessage(obtainMessage(TURN_COLD));
436dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie                            }
437694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        }
438694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    } else {
439694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        if (mPublicState != BluetoothAdapter.STATE_TURNING_ON) {
440694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                            if (mContext.getResources().getBoolean
441694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                            (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
442694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                                recoverStateMachine(TURN_HOT, null);
443694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                            } else {
444694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                                recoverStateMachine(TURN_COLD, null);
445694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                            }
446694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        }
4477f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    }
4487f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
4497f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case ALL_DEVICES_DISCONNECTED:
4509a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    removeMessages(DEVICES_DISCONNECT_TIMEOUT);
45114e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    mBluetoothService.switchConnectable(false);
452694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
4537f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
4549a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                case DEVICES_DISCONNECT_TIMEOUT:
4559a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    sendMessage(ALL_DEVICES_DISCONNECTED);
4569a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    // reset the hardware for error recovery
4579a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    Log.e(TAG, "Devices failed to disconnect, reseting...");
4589a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    deferMessage(obtainMessage(TURN_COLD));
4599a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    if (mContext.getResources().getBoolean
4609a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                        (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
4619a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                        deferMessage(obtainMessage(TURN_HOT));
4629a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    }
4639a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    break;
464694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                case POWER_DOWN_TIMEOUT:
465694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    transitionTo(mHotOff);
466694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    finishSwitchingOff();
467694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    // reset the hardware for error recovery
468694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    Log.e(TAG, "Devices failed to power down, reseting...");
469694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    deferMessage(obtainMessage(TURN_COLD));
470694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    if (mContext.getResources().getBoolean
471694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
472694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        deferMessage(obtainMessage(TURN_HOT));
473694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    }
474694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    break;
4757f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case USER_TURN_ON:
4767f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case AIRPLANE_MODE_OFF:
4777f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case AIRPLANE_MODE_ON:
478ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case PER_PROCESS_TURN_ON:
479ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case PER_PROCESS_TURN_OFF:
4807f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case USER_TURN_OFF:
4817f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    deferMessage(message);
4827f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
483ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
4847f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                default:
4857f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    return NOT_HANDLED;
4867f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            }
4877f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            return retValue;
4887f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
4897f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
4907f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
4917f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private class BluetoothOn extends State {
4927f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
4937f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        @Override
4947f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        public void enter() {
4958594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie            if (DBG) log("Enter BluetoothOn: " + getCurrentMessage().what);
4967f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
4977f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        @Override
4987f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        public boolean processMessage(Message message) {
49914e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            log("BluetoothOn process message: " + message.what);
5007f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
5017f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            boolean retValue = HANDLED;
5027f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            switch(message.what) {
5037f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case USER_TURN_OFF:
5047f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    if ((Boolean) message.obj) {
505ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        persistSwitchSetting(false);
506ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    }
507ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
508ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    if (mBluetoothService.isDiscovering()) {
509ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        mBluetoothService.cancelDiscovery();
510ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    }
511ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    if (!mBluetoothService.isApplicationStateChangeTrackerEmpty()) {
512ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        transitionTo(mPerProcessState);
5139a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                        deferMessage(obtainMessage(TURN_HOT));
514ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        break;
5157f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    }
516ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    //$FALL-THROUGH$ to AIRPLANE_MODE_ON
5177f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                case AIRPLANE_MODE_ON:
5187f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    broadcastState(BluetoothAdapter.STATE_TURNING_OFF);
519a6ba6fd4bb931ba7c1cbda6adc8452609ea80dacMatthew Xie                    transitionTo(mSwitching);
52014e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    if (mBluetoothService.getAdapterConnectionState() !=
52114e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        BluetoothAdapter.STATE_DISCONNECTED) {
52214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        mBluetoothService.disconnectDevices();
52314e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        sendMessageDelayed(DEVICES_DISCONNECT_TIMEOUT,
52414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                                           DEVICES_DISCONNECT_TIMEOUT_TIME);
52514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    } else {
52614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        mBluetoothService.switchConnectable(false);
527694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
52814e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    }
529ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
5307f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    // we turn all the way to PowerOff with AIRPLANE_MODE_ON
531f3171fb60c840a9bc0220fad651338346dddfff7Matthew Xie                    if (message.what == AIRPLANE_MODE_ON || mBluetoothService.isAirplaneModeOn()) {
532ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        // We inform all the per process callbacks
533ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        allProcessesCallback(false);
5347f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                        deferMessage(obtainMessage(AIRPLANE_MODE_ON));
5357f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    }
5367f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
5379a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                case AIRPLANE_MODE_OFF:
5389a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                case USER_TURN_ON:
5399a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    Log.w(TAG, "BluetoothOn received: " + message.what);
5407f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    break;
541ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case PER_PROCESS_TURN_ON:
542ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    perProcessCallback(true, (IBluetoothStateChangeCallback)message.obj);
543ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
544ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case PER_PROCESS_TURN_OFF:
545ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
546ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
547694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                case POWER_STATE_CHANGED:
548694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    if ((Boolean) message.obj) {
549694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        // reset the state machine and send it TURN_ON_CONTINUE message
550694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        recoverStateMachine(USER_TURN_ON, false);
551694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    }
552694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    break;
5537f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                default:
5547f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    return NOT_HANDLED;
5557f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            }
5567f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            return retValue;
5577f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
5587f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
5597f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
5607f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
561ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
562ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    private class PerProcessState extends State {
563ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        IBluetoothStateChangeCallback mCallback = null;
56414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        boolean isTurningOn = false;
565ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
566ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        @Override
567ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        public void enter() {
56814e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            int what = getCurrentMessage().what;
56914e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            if (DBG) log("Enter PerProcessState: " + what);
57014e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie
57114e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            if (what == PER_PROCESS_TURN_ON) {
57214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                isTurningOn = true;
573694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie            } else if (what == USER_TURN_OFF) {
57414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                isTurningOn = false;
57514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            } else {
57614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                Log.e(TAG, "enter PerProcessState: wrong msg: " + what);
57714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            }
578ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        }
579ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
580ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        @Override
581ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        public boolean processMessage(Message message) {
58214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            log("PerProcessState process message: " + message.what);
583ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
584ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            boolean retValue = HANDLED;
585ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            switch (message.what) {
586ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case PER_PROCESS_TURN_ON:
587ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    mCallback = (IBluetoothStateChangeCallback)getCurrentMessage().obj;
588ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
589ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    // If this is not the first application call the callback.
590ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    if (mBluetoothService.getNumberOfApplicationStateChangeTrackers() > 1) {
591ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        perProcessCallback(true, mCallback);
592ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    }
593ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
59414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                case SCAN_MODE_CHANGED:
59514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    if (isTurningOn) {
59614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        perProcessCallback(true, mCallback);
59714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        isTurningOn = false;
59814e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    }
59914e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    break;
60014e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                case POWER_STATE_CHANGED:
601694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    removeMessages(POWER_DOWN_TIMEOUT);
60214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    if (!((Boolean) message.obj)) {
60314e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        transitionTo(mHotOff);
60414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        if (!mContext.getResources().getBoolean
60514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                            (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
60614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                            deferMessage(obtainMessage(TURN_COLD));
60714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                        }
608694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    } else {
609694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        if (!isTurningOn) {
610694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                            recoverStateMachine(TURN_COLD, null);
611694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                            for (IBluetoothStateChangeCallback c:
612694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                                     mBluetoothService.getApplicationStateChangeCallbacks()) {
613694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                                perProcessCallback(false, c);
614694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                                deferMessage(obtainMessage(PER_PROCESS_TURN_ON, c));
615694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                            }
616694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        }
617694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    }
618694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    break;
619694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                case POWER_DOWN_TIMEOUT:
620694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    transitionTo(mHotOff);
621694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    Log.e(TAG, "Power-down timed out, resetting...");
622694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    deferMessage(obtainMessage(TURN_COLD));
623694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    if (mContext.getResources().getBoolean
624694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
625694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        deferMessage(obtainMessage(TURN_HOT));
62614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                    }
627ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
628ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case USER_TURN_ON:
629ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    broadcastState(BluetoothAdapter.STATE_TURNING_ON);
630ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    persistSwitchSetting(true);
6318594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie                    mBluetoothService.initBluetoothAfterTurningOn();
632ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    transitionTo(mBluetoothOn);
633ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    broadcastState(BluetoothAdapter.STATE_ON);
6348594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie                    // run bluetooth now that it's turned on
6358594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie                    mBluetoothService.runBluetooth();
636ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
6379a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                case TURN_HOT:
638ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    broadcastState(BluetoothAdapter.STATE_TURNING_OFF);
639ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    if (mBluetoothService.getAdapterConnectionState() !=
640ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        BluetoothAdapter.STATE_DISCONNECTED) {
641ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        mBluetoothService.disconnectDevices();
6429a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                        sendMessageDelayed(DEVICES_DISCONNECT_TIMEOUT,
6439a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                                           DEVICES_DISCONNECT_TIMEOUT_TIME);
644ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        break;
645ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    }
646ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    //$FALL-THROUGH$ all devices are already disconnected
647ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case ALL_DEVICES_DISCONNECTED:
6489a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    removeMessages(DEVICES_DISCONNECT_TIMEOUT);
649dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie                    finishSwitchingOff();
650ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
6519a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                case DEVICES_DISCONNECT_TIMEOUT:
652dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie                    finishSwitchingOff();
6539a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    Log.e(TAG, "Devices fail to disconnect, reseting...");
6549a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    transitionTo(mHotOff);
6559a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    deferMessage(obtainMessage(TURN_COLD));
6569a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    for (IBluetoothStateChangeCallback c:
6579a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                             mBluetoothService.getApplicationStateChangeCallbacks()) {
6589a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                        perProcessCallback(false, c);
6599a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                        deferMessage(obtainMessage(PER_PROCESS_TURN_ON, c));
6609a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    }
6619a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    break;
6629a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                case PER_PROCESS_TURN_OFF:
663ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
664ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    if (mBluetoothService.isApplicationStateChangeTrackerEmpty()) {
665ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                        mBluetoothService.switchConnectable(false);
666694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                        sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
667ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    }
668ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
669ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                case AIRPLANE_MODE_ON:
670ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    mBluetoothService.switchConnectable(false);
671694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie                    sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
672ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    allProcessesCallback(false);
673ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    // we turn all the way to PowerOff with AIRPLANE_MODE_ON
674ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    deferMessage(obtainMessage(AIRPLANE_MODE_ON));
675ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    break;
6769a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                case USER_TURN_OFF:
6779a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    Log.w(TAG, "PerProcessState received: " + message.what);
6789a943a64202aba8f885b2c736183bf53276a23dfMatthew Xie                    break;
679ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                default:
680ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    return NOT_HANDLED;
681ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            }
682ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            return retValue;
683ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        }
684ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    }
685ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
686dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie    private void finishSwitchingOff() {
687dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie        mBluetoothService.finishDisable();
688dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie        broadcastState(BluetoothAdapter.STATE_OFF);
689dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie        mBluetoothService.cleanupAfterFinishDisable();
690dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie    }
691dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie
69214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    private void shutoffBluetooth() {
69314e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        mBluetoothService.shutoffBluetooth();
69414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        mEventLoop.stop();
69514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        mBluetoothService.cleanNativeAfterShutoffBluetooth();
69614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    }
697ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
698ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    private void perProcessCallback(boolean on, IBluetoothStateChangeCallback c) {
699ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        if (c == null) return;
700ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
701ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        try {
702ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            c.onBluetoothStateChange(on);
703ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        } catch (RemoteException e) {}
704ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    }
705ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
706ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    private void allProcessesCallback(boolean on) {
707ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        for (IBluetoothStateChangeCallback c:
708ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh             mBluetoothService.getApplicationStateChangeCallbacks()) {
709ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            perProcessCallback(on, c);
710ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        }
711ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        if (!on) {
712ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            mBluetoothService.clearApplicationStateChangeTracker();
713ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        }
714ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    }
715ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
7167f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /**
7177f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * Return the public BluetoothAdapter state
7187f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     */
7197f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    int getBluetoothAdapterState() {
7207f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        return mPublicState;
7217f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
7227f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
7237f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    BluetoothEventLoop getBluetoothEventLoop() {
7247f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        return mEventLoop;
7257f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
7267f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
7277f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private void persistSwitchSetting(boolean setOn) {
7287f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        long origCallerIdentityToken = Binder.clearCallingIdentity();
7297f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        Settings.Secure.putInt(mContext.getContentResolver(),
7307f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                               Settings.Secure.BLUETOOTH_ON,
7317f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                               setOn ? 1 : 0);
7327f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        Binder.restoreCallingIdentity(origCallerIdentityToken);
7337f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
7347f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
7357f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private boolean getBluetoothPersistedSetting() {
7367f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        ContentResolver contentResolver = mContext.getContentResolver();
7377f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        return (Settings.Secure.getInt(contentResolver,
7387f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                                       Settings.Secure.BLUETOOTH_ON, 0) > 0);
7397f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
7407f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
7417f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private void broadcastState(int newState) {
7427f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
743ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        log("Bluetooth state " + mPublicState + " -> " + newState);
7447f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        if (mPublicState == newState) {
7457f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            return;
7467f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
7477f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
7487f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
7497f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mPublicState);
7507f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
7517f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
7527f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mPublicState = newState;
7537f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
7547f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM);
7557f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
7567f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
757694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie    /**
758694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie     * bluetoothd has crashed and recovered, the adapter state machine has to
759694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie     * reset itself and try to return to previous state
760694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie     */
761694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie    private void recoverStateMachine(int what, Object obj) {
762694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie        Log.e(TAG, "Get unexpected power on event, reset with: " + what);
763694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie        transitionTo(mHotOff);
764694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie        deferMessage(obtainMessage(TURN_COLD));
765694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie        deferMessage(obtainMessage(what, obj));
766694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie    }
767694c0b833b4235b396ec1b798610d617d0ec7b5cMatthew Xie
7687f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private void dump(PrintWriter pw) {
7697f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        IState currentState = getCurrentState();
7707f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        if (currentState == mPowerOff) {
7717f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            pw.println("Bluetooth OFF - power down\n");
7727f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        } else if (currentState == mWarmUp) {
7737f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            pw.println("Bluetooth OFF - warm up\n");
7747f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        } else if (currentState == mHotOff) {
7757f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            pw.println("Bluetooth OFF - hot but off\n");
7767f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        } else if (currentState == mSwitching) {
7777f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            pw.println("Bluetooth Switching\n");
7787f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        } else if (currentState == mBluetoothOn) {
7797f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            pw.println("Bluetooth ON\n");
7807f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        } else {
7817f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            pw.println("ERROR: Bluetooth UNKNOWN STATE ");
7827f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
7837f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
7847f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
7857f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private static void log(String msg) {
7867f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        Log.d(TAG, msg);
7877f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
7887f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie}
789