Loading Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,7 @@ LOCAL_SRC_FILES += \ core/java/android/bluetooth/IBluetoothHeadset.aidl \ core/java/android/bluetooth/IBluetoothHealthCallback.aidl \ core/java/android/bluetooth/IBluetoothPbap.aidl \ core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \ core/java/android/content/IClipboard.aidl \ core/java/android/content/IContentService.aidl \ core/java/android/content/IIntentReceiver.aidl \ Loading core/java/android/bluetooth/BluetoothAdapter.java +63 −0 Original line number Diff line number Diff line Loading @@ -1143,6 +1143,69 @@ public final class BluetoothAdapter { } } /** * Enable control of the Bluetooth Adapter for a single application. * * <p>Some applications need to use Bluetooth for short periods of time to * transfer data but don't want all the associated implications like * automatic connection to headsets etc. * * <p> Multiple applications can call this. This is reference counted and * Bluetooth disabled only when no one else is using it. There will be no UI * shown to the user while bluetooth is being enabled. Any user action will * override this call. For example, if user wants Bluetooth on and the last * user of this API wanted to disable Bluetooth, Bluetooth will not be * turned off. * * <p> This API is only meant to be used by internal applications. Third * party applications but use {@link #enable} and {@link #disable} APIs. * * <p> If this API returns true, it means the callback will be called. * The callback will be called with the current state of Bluetooth. * If the state is not what was requested, an internal error would be the * reason. * * @param on True for on, false for off. * @param callback The callback to notify changes to the state. * @hide */ public boolean changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback) { if (callback == null) return false; try { return mService.changeApplicationBluetoothState(on, new StateChangeCallbackWrapper(callback), new Binder()); } catch (RemoteException e) { Log.e(TAG, "changeBluetoothState", e); } return false; } /** * @hide */ public interface BluetoothStateChangeCallback { public void onBluetoothStateChange(boolean on); } /** * @hide */ public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub { private BluetoothStateChangeCallback mCallback; StateChangeCallbackWrapper(BluetoothStateChangeCallback callback) { mCallback = callback; } @Override public void onBluetoothStateChange(boolean on) { mCallback.onBluetoothStateChange(on); } } private Set<BluetoothDevice> toDeviceSet(String[] addresses) { Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length); for (int i = 0; i < addresses.length; i++) { Loading core/java/android/bluetooth/IBluetooth.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.bluetooth; import android.bluetooth.IBluetoothCallback; import android.bluetooth.IBluetoothStateChangeCallback; import android.bluetooth.IBluetoothHealthCallback; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHealthAppConfiguration; Loading Loading @@ -52,6 +53,9 @@ interface IBluetooth byte[] readOutOfBandData(); int getAdapterConnectionState(); boolean changeApplicationBluetoothState(boolean on, in IBluetoothStateChangeCallback callback, in IBinder b); boolean createBond(in String address); boolean createBondOutOfBand(in String address, in byte[] hash, in byte[] randomizer); Loading core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl 0 → 100644 +27 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.bluetooth; /** * System private API for Bluetooth state change callback. * * {@hide} */ interface IBluetoothStateChangeCallback { void onBluetoothStateChange(boolean on); } core/java/android/server/BluetoothAdapterStateMachine.java +187 −47 Original line number Diff line number Diff line Loading @@ -17,11 +17,13 @@ package android.server; import android.bluetooth.BluetoothAdapter; import android.bluetooth.IBluetoothStateChangeCallback; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Message; import android.os.RemoteException; import android.provider.Settings; import android.util.Log; Loading @@ -34,17 +36,18 @@ import java.io.PrintWriter; /** * Bluetooth Adapter StateMachine * All the states are at the same level, ie, no hierarchy. * (BluetootOn) * | ^ * TURN_OFF | | BECOME_PAIRABLE * AIRPLANE_MODE_ON | | * V | * (Switching) * | ^ * BECOME_NON_PAIRABLE& | | TURN_ON(_CONTINUE)/TURN_ON_FOR_PRIVILEGED * ALL_DEVICES_DISCONNECTED | | * V | * (HotOff) * (BluetootOn)<----------------------<- * | ^ -------------------->- | * | | | | * TURN_OFF | | BECAME_PAIRABLE m1 | | USER_TURN_ON * AIRPLANE_MODE_ON | | | | * V | | | * (Switching) (PerProcessState) * | ^ | | * BECAME_NON_PAIRABLE& | | TURN_ON(_CONTINUE) | | * ALL_DEVICES_DISCONNECTED | | m2 | | * V |------------------------< | BECAME_PAIRABLE * (HotOff)---------------------------- PER_PROCESS_TURN_ON * / ^ * / | SERVICE_RECORD_LOADED * | | Loading @@ -55,6 +58,10 @@ import java.io.PrintWriter; * V | * (PowerOff) <----- initial state * * Legend: * m1 = USER_TURN_OFF * m2 = Transition to HotOff when number of process wanting BT on is 0. * BECAME_NON_PAIRABLE will make the transition. */ final class BluetoothAdapterStateMachine extends StateMachine { private static final String TAG = "BluetoothAdapterStateMachine"; Loading @@ -63,24 +70,24 @@ final class BluetoothAdapterStateMachine extends StateMachine { // Message(what) to take an action // // We get this message when user tries to turn on BT public static final int USER_TURN_ON = 1; static final int USER_TURN_ON = 1; // We get this message when user tries to turn off BT public static final int USER_TURN_OFF = 2; static final int USER_TURN_OFF = 2; // Message(what) to report a event that the state machine need to respond to // // Event indicates sevice records have been loaded public static final int SERVICE_RECORD_LOADED = 51; static final int SERVICE_RECORD_LOADED = 51; // Event indicates all the remote Bluetooth devices has been disconnected public static final int ALL_DEVICES_DISCONNECTED = 52; static final int ALL_DEVICES_DISCONNECTED = 52; // Event indicates the Bluetooth is connectable public static final int BECOME_PAIRABLE = 53; static final int BECAME_PAIRABLE = 53; // Event indicates the Bluetooth is non-connectable. public static final int BECOME_NON_PAIRABLE = 54; static final int BECAME_NON_PAIRABLE = 54; // Event indicates airplane mode is turned on public static final int AIRPLANE_MODE_ON = 55; static final int AIRPLANE_MODE_ON = 55; // Event indicates airplane mode is turned off public static final int AIRPLANE_MODE_OFF = 56; static final int AIRPLANE_MODE_OFF = 56; // private internal messages // Loading @@ -95,8 +102,9 @@ final class BluetoothAdapterStateMachine extends StateMachine { private static final int TURN_ON_CONTINUE = 102; // Unload firmware, turning off Bluetooth module power private static final int TURN_COLD = 103; // For NFC, turn on bluetooth for certain process private static final int TURN_ON_FOR_PRIVILEGED = 104; // Per process enable / disable messages static final int PER_PROCESS_TURN_ON = 104; static final int PER_PROCESS_TURN_OFF = 105; private Context mContext; private BluetoothService mBluetoothService; Loading @@ -107,6 +115,7 @@ final class BluetoothAdapterStateMachine extends StateMachine { private HotOff mHotOff; private WarmUp mWarmUp; private PowerOff mPowerOff; private PerProcessState mPerProcessState; // this is the BluetoothAdapter state that reported externally private int mPublicState; Loading @@ -123,12 +132,15 @@ final class BluetoothAdapterStateMachine extends StateMachine { mHotOff = new HotOff(); mWarmUp = new WarmUp(); mPowerOff = new PowerOff(); mPerProcessState = new PerProcessState(); addState(mBluetoothOn); addState(mSwitching); addState(mHotOff); addState(mWarmUp); addState(mPowerOff); addState(mPerProcessState); setInitialState(mPowerOff); mPublicState = BluetoothAdapter.STATE_OFF; Loading @@ -142,12 +154,9 @@ final class BluetoothAdapterStateMachine extends StateMachine { * Bluetooth module's power is off, firmware is not loaded. */ private class PowerOff extends State { private boolean mPersistSwitchOn = false; @Override public void enter() { if (DBG) log("Enter PowerOff: " + mPersistSwitchOn); mPersistSwitchOn = false; if (DBG) log("Enter PowerOff: "); } @Override public boolean processMessage(Message message) { Loading @@ -162,7 +171,7 @@ final class BluetoothAdapterStateMachine extends StateMachine { if (prepareBluetooth()) { // this is user request, save the setting if ((Boolean) message.obj) { mPersistSwitchOn = true; persistSwitchSetting(true); } // We will continue turn the BT on all the way to the BluetoothOn state deferMessage(obtainMessage(TURN_ON_CONTINUE)); Loading Loading @@ -191,9 +200,21 @@ final class BluetoothAdapterStateMachine extends StateMachine { transitionTo(mPowerOff); broadcastState(BluetoothAdapter.STATE_OFF); } } else if (mContext.getResources().getBoolean (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) { sendMessage(TURN_HOT); } break; case AIRPLANE_MODE_ON: // ignore case PER_PROCESS_TURN_ON: if (prepareBluetooth()) { transitionTo(mWarmUp); } deferMessage(obtainMessage(PER_PROCESS_TURN_ON)); break; case PER_PROCESS_TURN_OFF: perProcessCallback(false, (IBluetoothStateChangeCallback) message.obj); break; case AIRPLANE_MODE_ON: case USER_TURN_OFF: // ignore break; default: Loading Loading @@ -276,6 +297,8 @@ final class BluetoothAdapterStateMachine extends StateMachine { // on to the BluetoothOn state case AIRPLANE_MODE_ON: case AIRPLANE_MODE_OFF: case PER_PROCESS_TURN_ON: case PER_PROCESS_TURN_OFF: deferMessage(message); break; case USER_TURN_OFF: // ignore Loading @@ -294,12 +317,9 @@ final class BluetoothAdapterStateMachine extends StateMachine { * non-connectable. */ private class HotOff extends State { private boolean mPersistSwitchOn = false; @Override public void enter() { if (DBG) log("Enter HotOff: " + mPersistSwitchOn); mPersistSwitchOn = false; if (DBG) log("Enter HotOff:"); } @Override Loading @@ -310,9 +330,10 @@ final class BluetoothAdapterStateMachine extends StateMachine { switch(message.what) { case USER_TURN_ON: if ((Boolean) message.obj) { mPersistSwitchOn = true; persistSwitchSetting(true); } // let it fall to TURN_ON_CONTINUE: //$FALL-THROUGH$ case TURN_ON_CONTINUE: mBluetoothService.switchConnectable(true); transitionTo(mSwitching); Loading @@ -328,13 +349,25 @@ final class BluetoothAdapterStateMachine extends StateMachine { break; case AIRPLANE_MODE_OFF: if (getBluetoothPersistedSetting()) { mBluetoothService.switchConnectable(true); transitionTo(mSwitching); mBluetoothService.switchConnectable(true); broadcastState(BluetoothAdapter.STATE_TURNING_ON); } break; case USER_TURN_OFF: // ignore break; case PER_PROCESS_TURN_ON: transitionTo(mPerProcessState); // Resend the PER_PROCESS_TURN_ON message so that the callback // can be sent through. deferMessage(message); mBluetoothService.switchConnectable(true); break; case PER_PROCESS_TURN_OFF: perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj); break; default: return NOT_HANDLED; } Loading @@ -356,11 +389,7 @@ final class BluetoothAdapterStateMachine extends StateMachine { boolean retValue = HANDLED; switch(message.what) { case BECOME_PAIRABLE: if (mPowerOff.mPersistSwitchOn || mHotOff.mPersistSwitchOn) { persistSwitchSetting(true); mPowerOff.mPersistSwitchOn = mHotOff.mPersistSwitchOn = false; } case BECAME_PAIRABLE: String[] propVal = {"Pairable", mBluetoothService.getProperty("Pairable")}; mEventLoop.onPropertyChanged(propVal); Loading @@ -369,7 +398,7 @@ final class BluetoothAdapterStateMachine extends StateMachine { transitionTo(mBluetoothOn); broadcastState(BluetoothAdapter.STATE_ON); break; case BECOME_NON_PAIRABLE: case BECAME_NON_PAIRABLE: if (mBluetoothService.getAdapterConnectionState() == BluetoothAdapter.STATE_DISCONNECTED) { transitionTo(mHotOff); Loading @@ -385,9 +414,12 @@ final class BluetoothAdapterStateMachine extends StateMachine { case USER_TURN_ON: case AIRPLANE_MODE_OFF: case AIRPLANE_MODE_ON: case PER_PROCESS_TURN_ON: case PER_PROCESS_TURN_OFF: case USER_TURN_OFF: deferMessage(message); break; default: return NOT_HANDLED; } Loading @@ -395,10 +427,6 @@ final class BluetoothAdapterStateMachine extends StateMachine { } private void finishSwitchingOff() { if (mBluetoothOn.mPersistBluetoothOff) { persistSwitchSetting(false); mBluetoothOn.mPersistBluetoothOff = false; } mBluetoothService.finishDisable(); if (mContext.getResources().getBoolean (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) { Loading @@ -415,7 +443,6 @@ final class BluetoothAdapterStateMachine extends StateMachine { @Override public void enter() { if (DBG) log("Enter BluetoothOn: " + mPersistBluetoothOff); mPersistBluetoothOff = false; } @Override public boolean processMessage(Message message) { Loading @@ -425,28 +452,141 @@ final class BluetoothAdapterStateMachine extends StateMachine { switch(message.what) { case USER_TURN_OFF: if ((Boolean) message.obj) { mPersistBluetoothOff = true; persistSwitchSetting(false); } if (mBluetoothService.isDiscovering()) { mBluetoothService.cancelDiscovery(); } if (!mBluetoothService.isApplicationStateChangeTrackerEmpty()) { transitionTo(mPerProcessState); deferMessage(obtainMessage(USER_TURN_OFF)); break; } // let it fall through to AIRPLANE_MODE_ON //$FALL-THROUGH$ to AIRPLANE_MODE_ON case AIRPLANE_MODE_ON: transitionTo(mSwitching); broadcastState(BluetoothAdapter.STATE_TURNING_OFF); mBluetoothService.switchConnectable(false); mBluetoothService.disconnectDevices(); // we turn all the way to PowerOff with AIRPLANE_MODE_ON if (message.what == AIRPLANE_MODE_ON) { // We inform all the per process callbacks allProcessesCallback(false); deferMessage(obtainMessage(AIRPLANE_MODE_ON)); } break; case AIRPLANE_MODE_OFF: // ignore case USER_TURN_ON: // ignore break; case PER_PROCESS_TURN_ON: perProcessCallback(true, (IBluetoothStateChangeCallback)message.obj); break; case PER_PROCESS_TURN_OFF: perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj); break; default: return NOT_HANDLED; } return retValue; } } private class PerProcessState extends State { IBluetoothStateChangeCallback mCallback = null; @Override public void enter() { if (DBG) log("Enter PerProcessState"); } @Override public boolean processMessage(Message message) { if (DBG) log("PerProcessState process message: " + message.what); boolean retValue = HANDLED; switch (message.what) { case PER_PROCESS_TURN_ON: mCallback = (IBluetoothStateChangeCallback)getCurrentMessage().obj; // If this is not the first application call the callback. if (mBluetoothService.getNumberOfApplicationStateChangeTrackers() > 1) { perProcessCallback(true, mCallback); } break; case BECAME_PAIRABLE: perProcessCallback(true, mCallback); break; case USER_TURN_ON: broadcastState(BluetoothAdapter.STATE_TURNING_ON); persistSwitchSetting(true); String[] propVal = {"Pairable", mBluetoothService.getProperty("Pairable")}; mEventLoop.onPropertyChanged(propVal); // run bluetooth now that it's turned on mBluetoothService.runBluetooth(); transitionTo(mBluetoothOn); broadcastState(BluetoothAdapter.STATE_ON); break; case USER_TURN_OFF: broadcastState(BluetoothAdapter.STATE_TURNING_OFF); if (mBluetoothService.getAdapterConnectionState() != BluetoothAdapter.STATE_DISCONNECTED) { mBluetoothService.disconnectDevices(); break; } //$FALL-THROUGH$ all devices are already disconnected case ALL_DEVICES_DISCONNECTED: mBluetoothService.finishDisable(); broadcastState(BluetoothAdapter.STATE_OFF); break; case PER_PROCESS_TURN_OFF: perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj); if (mBluetoothService.isApplicationStateChangeTrackerEmpty()) { mBluetoothService.switchConnectable(false); } break; case BECAME_NON_PAIRABLE: transitionTo(mHotOff); if (!mContext.getResources().getBoolean (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) { deferMessage(obtainMessage(TURN_COLD)); } break; case AIRPLANE_MODE_ON: mBluetoothService.switchConnectable(false); allProcessesCallback(false); // we turn all the way to PowerOff with AIRPLANE_MODE_ON deferMessage(obtainMessage(AIRPLANE_MODE_ON)); break; default: return NOT_HANDLED; } return retValue; } } private void perProcessCallback(boolean on, IBluetoothStateChangeCallback c) { if (c == null) return; try { c.onBluetoothStateChange(on); } catch (RemoteException e) {} } private void allProcessesCallback(boolean on) { for (IBluetoothStateChangeCallback c: mBluetoothService.getApplicationStateChangeCallbacks()) { perProcessCallback(on, c); } if (!on) { mBluetoothService.clearApplicationStateChangeTracker(); } } /** Loading Loading @@ -476,7 +616,7 @@ final class BluetoothAdapterStateMachine extends StateMachine { private void broadcastState(int newState) { if (DBG) log("Bluetooth state " + mPublicState + " -> " + newState); log("Bluetooth state " + mPublicState + " -> " + newState); if (mPublicState == newState) { return; } Loading Loading
Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,7 @@ LOCAL_SRC_FILES += \ core/java/android/bluetooth/IBluetoothHeadset.aidl \ core/java/android/bluetooth/IBluetoothHealthCallback.aidl \ core/java/android/bluetooth/IBluetoothPbap.aidl \ core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \ core/java/android/content/IClipboard.aidl \ core/java/android/content/IContentService.aidl \ core/java/android/content/IIntentReceiver.aidl \ Loading
core/java/android/bluetooth/BluetoothAdapter.java +63 −0 Original line number Diff line number Diff line Loading @@ -1143,6 +1143,69 @@ public final class BluetoothAdapter { } } /** * Enable control of the Bluetooth Adapter for a single application. * * <p>Some applications need to use Bluetooth for short periods of time to * transfer data but don't want all the associated implications like * automatic connection to headsets etc. * * <p> Multiple applications can call this. This is reference counted and * Bluetooth disabled only when no one else is using it. There will be no UI * shown to the user while bluetooth is being enabled. Any user action will * override this call. For example, if user wants Bluetooth on and the last * user of this API wanted to disable Bluetooth, Bluetooth will not be * turned off. * * <p> This API is only meant to be used by internal applications. Third * party applications but use {@link #enable} and {@link #disable} APIs. * * <p> If this API returns true, it means the callback will be called. * The callback will be called with the current state of Bluetooth. * If the state is not what was requested, an internal error would be the * reason. * * @param on True for on, false for off. * @param callback The callback to notify changes to the state. * @hide */ public boolean changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback) { if (callback == null) return false; try { return mService.changeApplicationBluetoothState(on, new StateChangeCallbackWrapper(callback), new Binder()); } catch (RemoteException e) { Log.e(TAG, "changeBluetoothState", e); } return false; } /** * @hide */ public interface BluetoothStateChangeCallback { public void onBluetoothStateChange(boolean on); } /** * @hide */ public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub { private BluetoothStateChangeCallback mCallback; StateChangeCallbackWrapper(BluetoothStateChangeCallback callback) { mCallback = callback; } @Override public void onBluetoothStateChange(boolean on) { mCallback.onBluetoothStateChange(on); } } private Set<BluetoothDevice> toDeviceSet(String[] addresses) { Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length); for (int i = 0; i < addresses.length; i++) { Loading
core/java/android/bluetooth/IBluetooth.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.bluetooth; import android.bluetooth.IBluetoothCallback; import android.bluetooth.IBluetoothStateChangeCallback; import android.bluetooth.IBluetoothHealthCallback; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHealthAppConfiguration; Loading Loading @@ -52,6 +53,9 @@ interface IBluetooth byte[] readOutOfBandData(); int getAdapterConnectionState(); boolean changeApplicationBluetoothState(boolean on, in IBluetoothStateChangeCallback callback, in IBinder b); boolean createBond(in String address); boolean createBondOutOfBand(in String address, in byte[] hash, in byte[] randomizer); Loading
core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl 0 → 100644 +27 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.bluetooth; /** * System private API for Bluetooth state change callback. * * {@hide} */ interface IBluetoothStateChangeCallback { void onBluetoothStateChange(boolean on); }
core/java/android/server/BluetoothAdapterStateMachine.java +187 −47 Original line number Diff line number Diff line Loading @@ -17,11 +17,13 @@ package android.server; import android.bluetooth.BluetoothAdapter; import android.bluetooth.IBluetoothStateChangeCallback; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Message; import android.os.RemoteException; import android.provider.Settings; import android.util.Log; Loading @@ -34,17 +36,18 @@ import java.io.PrintWriter; /** * Bluetooth Adapter StateMachine * All the states are at the same level, ie, no hierarchy. * (BluetootOn) * | ^ * TURN_OFF | | BECOME_PAIRABLE * AIRPLANE_MODE_ON | | * V | * (Switching) * | ^ * BECOME_NON_PAIRABLE& | | TURN_ON(_CONTINUE)/TURN_ON_FOR_PRIVILEGED * ALL_DEVICES_DISCONNECTED | | * V | * (HotOff) * (BluetootOn)<----------------------<- * | ^ -------------------->- | * | | | | * TURN_OFF | | BECAME_PAIRABLE m1 | | USER_TURN_ON * AIRPLANE_MODE_ON | | | | * V | | | * (Switching) (PerProcessState) * | ^ | | * BECAME_NON_PAIRABLE& | | TURN_ON(_CONTINUE) | | * ALL_DEVICES_DISCONNECTED | | m2 | | * V |------------------------< | BECAME_PAIRABLE * (HotOff)---------------------------- PER_PROCESS_TURN_ON * / ^ * / | SERVICE_RECORD_LOADED * | | Loading @@ -55,6 +58,10 @@ import java.io.PrintWriter; * V | * (PowerOff) <----- initial state * * Legend: * m1 = USER_TURN_OFF * m2 = Transition to HotOff when number of process wanting BT on is 0. * BECAME_NON_PAIRABLE will make the transition. */ final class BluetoothAdapterStateMachine extends StateMachine { private static final String TAG = "BluetoothAdapterStateMachine"; Loading @@ -63,24 +70,24 @@ final class BluetoothAdapterStateMachine extends StateMachine { // Message(what) to take an action // // We get this message when user tries to turn on BT public static final int USER_TURN_ON = 1; static final int USER_TURN_ON = 1; // We get this message when user tries to turn off BT public static final int USER_TURN_OFF = 2; static final int USER_TURN_OFF = 2; // Message(what) to report a event that the state machine need to respond to // // Event indicates sevice records have been loaded public static final int SERVICE_RECORD_LOADED = 51; static final int SERVICE_RECORD_LOADED = 51; // Event indicates all the remote Bluetooth devices has been disconnected public static final int ALL_DEVICES_DISCONNECTED = 52; static final int ALL_DEVICES_DISCONNECTED = 52; // Event indicates the Bluetooth is connectable public static final int BECOME_PAIRABLE = 53; static final int BECAME_PAIRABLE = 53; // Event indicates the Bluetooth is non-connectable. public static final int BECOME_NON_PAIRABLE = 54; static final int BECAME_NON_PAIRABLE = 54; // Event indicates airplane mode is turned on public static final int AIRPLANE_MODE_ON = 55; static final int AIRPLANE_MODE_ON = 55; // Event indicates airplane mode is turned off public static final int AIRPLANE_MODE_OFF = 56; static final int AIRPLANE_MODE_OFF = 56; // private internal messages // Loading @@ -95,8 +102,9 @@ final class BluetoothAdapterStateMachine extends StateMachine { private static final int TURN_ON_CONTINUE = 102; // Unload firmware, turning off Bluetooth module power private static final int TURN_COLD = 103; // For NFC, turn on bluetooth for certain process private static final int TURN_ON_FOR_PRIVILEGED = 104; // Per process enable / disable messages static final int PER_PROCESS_TURN_ON = 104; static final int PER_PROCESS_TURN_OFF = 105; private Context mContext; private BluetoothService mBluetoothService; Loading @@ -107,6 +115,7 @@ final class BluetoothAdapterStateMachine extends StateMachine { private HotOff mHotOff; private WarmUp mWarmUp; private PowerOff mPowerOff; private PerProcessState mPerProcessState; // this is the BluetoothAdapter state that reported externally private int mPublicState; Loading @@ -123,12 +132,15 @@ final class BluetoothAdapterStateMachine extends StateMachine { mHotOff = new HotOff(); mWarmUp = new WarmUp(); mPowerOff = new PowerOff(); mPerProcessState = new PerProcessState(); addState(mBluetoothOn); addState(mSwitching); addState(mHotOff); addState(mWarmUp); addState(mPowerOff); addState(mPerProcessState); setInitialState(mPowerOff); mPublicState = BluetoothAdapter.STATE_OFF; Loading @@ -142,12 +154,9 @@ final class BluetoothAdapterStateMachine extends StateMachine { * Bluetooth module's power is off, firmware is not loaded. */ private class PowerOff extends State { private boolean mPersistSwitchOn = false; @Override public void enter() { if (DBG) log("Enter PowerOff: " + mPersistSwitchOn); mPersistSwitchOn = false; if (DBG) log("Enter PowerOff: "); } @Override public boolean processMessage(Message message) { Loading @@ -162,7 +171,7 @@ final class BluetoothAdapterStateMachine extends StateMachine { if (prepareBluetooth()) { // this is user request, save the setting if ((Boolean) message.obj) { mPersistSwitchOn = true; persistSwitchSetting(true); } // We will continue turn the BT on all the way to the BluetoothOn state deferMessage(obtainMessage(TURN_ON_CONTINUE)); Loading Loading @@ -191,9 +200,21 @@ final class BluetoothAdapterStateMachine extends StateMachine { transitionTo(mPowerOff); broadcastState(BluetoothAdapter.STATE_OFF); } } else if (mContext.getResources().getBoolean (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) { sendMessage(TURN_HOT); } break; case AIRPLANE_MODE_ON: // ignore case PER_PROCESS_TURN_ON: if (prepareBluetooth()) { transitionTo(mWarmUp); } deferMessage(obtainMessage(PER_PROCESS_TURN_ON)); break; case PER_PROCESS_TURN_OFF: perProcessCallback(false, (IBluetoothStateChangeCallback) message.obj); break; case AIRPLANE_MODE_ON: case USER_TURN_OFF: // ignore break; default: Loading Loading @@ -276,6 +297,8 @@ final class BluetoothAdapterStateMachine extends StateMachine { // on to the BluetoothOn state case AIRPLANE_MODE_ON: case AIRPLANE_MODE_OFF: case PER_PROCESS_TURN_ON: case PER_PROCESS_TURN_OFF: deferMessage(message); break; case USER_TURN_OFF: // ignore Loading @@ -294,12 +317,9 @@ final class BluetoothAdapterStateMachine extends StateMachine { * non-connectable. */ private class HotOff extends State { private boolean mPersistSwitchOn = false; @Override public void enter() { if (DBG) log("Enter HotOff: " + mPersistSwitchOn); mPersistSwitchOn = false; if (DBG) log("Enter HotOff:"); } @Override Loading @@ -310,9 +330,10 @@ final class BluetoothAdapterStateMachine extends StateMachine { switch(message.what) { case USER_TURN_ON: if ((Boolean) message.obj) { mPersistSwitchOn = true; persistSwitchSetting(true); } // let it fall to TURN_ON_CONTINUE: //$FALL-THROUGH$ case TURN_ON_CONTINUE: mBluetoothService.switchConnectable(true); transitionTo(mSwitching); Loading @@ -328,13 +349,25 @@ final class BluetoothAdapterStateMachine extends StateMachine { break; case AIRPLANE_MODE_OFF: if (getBluetoothPersistedSetting()) { mBluetoothService.switchConnectable(true); transitionTo(mSwitching); mBluetoothService.switchConnectable(true); broadcastState(BluetoothAdapter.STATE_TURNING_ON); } break; case USER_TURN_OFF: // ignore break; case PER_PROCESS_TURN_ON: transitionTo(mPerProcessState); // Resend the PER_PROCESS_TURN_ON message so that the callback // can be sent through. deferMessage(message); mBluetoothService.switchConnectable(true); break; case PER_PROCESS_TURN_OFF: perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj); break; default: return NOT_HANDLED; } Loading @@ -356,11 +389,7 @@ final class BluetoothAdapterStateMachine extends StateMachine { boolean retValue = HANDLED; switch(message.what) { case BECOME_PAIRABLE: if (mPowerOff.mPersistSwitchOn || mHotOff.mPersistSwitchOn) { persistSwitchSetting(true); mPowerOff.mPersistSwitchOn = mHotOff.mPersistSwitchOn = false; } case BECAME_PAIRABLE: String[] propVal = {"Pairable", mBluetoothService.getProperty("Pairable")}; mEventLoop.onPropertyChanged(propVal); Loading @@ -369,7 +398,7 @@ final class BluetoothAdapterStateMachine extends StateMachine { transitionTo(mBluetoothOn); broadcastState(BluetoothAdapter.STATE_ON); break; case BECOME_NON_PAIRABLE: case BECAME_NON_PAIRABLE: if (mBluetoothService.getAdapterConnectionState() == BluetoothAdapter.STATE_DISCONNECTED) { transitionTo(mHotOff); Loading @@ -385,9 +414,12 @@ final class BluetoothAdapterStateMachine extends StateMachine { case USER_TURN_ON: case AIRPLANE_MODE_OFF: case AIRPLANE_MODE_ON: case PER_PROCESS_TURN_ON: case PER_PROCESS_TURN_OFF: case USER_TURN_OFF: deferMessage(message); break; default: return NOT_HANDLED; } Loading @@ -395,10 +427,6 @@ final class BluetoothAdapterStateMachine extends StateMachine { } private void finishSwitchingOff() { if (mBluetoothOn.mPersistBluetoothOff) { persistSwitchSetting(false); mBluetoothOn.mPersistBluetoothOff = false; } mBluetoothService.finishDisable(); if (mContext.getResources().getBoolean (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) { Loading @@ -415,7 +443,6 @@ final class BluetoothAdapterStateMachine extends StateMachine { @Override public void enter() { if (DBG) log("Enter BluetoothOn: " + mPersistBluetoothOff); mPersistBluetoothOff = false; } @Override public boolean processMessage(Message message) { Loading @@ -425,28 +452,141 @@ final class BluetoothAdapterStateMachine extends StateMachine { switch(message.what) { case USER_TURN_OFF: if ((Boolean) message.obj) { mPersistBluetoothOff = true; persistSwitchSetting(false); } if (mBluetoothService.isDiscovering()) { mBluetoothService.cancelDiscovery(); } if (!mBluetoothService.isApplicationStateChangeTrackerEmpty()) { transitionTo(mPerProcessState); deferMessage(obtainMessage(USER_TURN_OFF)); break; } // let it fall through to AIRPLANE_MODE_ON //$FALL-THROUGH$ to AIRPLANE_MODE_ON case AIRPLANE_MODE_ON: transitionTo(mSwitching); broadcastState(BluetoothAdapter.STATE_TURNING_OFF); mBluetoothService.switchConnectable(false); mBluetoothService.disconnectDevices(); // we turn all the way to PowerOff with AIRPLANE_MODE_ON if (message.what == AIRPLANE_MODE_ON) { // We inform all the per process callbacks allProcessesCallback(false); deferMessage(obtainMessage(AIRPLANE_MODE_ON)); } break; case AIRPLANE_MODE_OFF: // ignore case USER_TURN_ON: // ignore break; case PER_PROCESS_TURN_ON: perProcessCallback(true, (IBluetoothStateChangeCallback)message.obj); break; case PER_PROCESS_TURN_OFF: perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj); break; default: return NOT_HANDLED; } return retValue; } } private class PerProcessState extends State { IBluetoothStateChangeCallback mCallback = null; @Override public void enter() { if (DBG) log("Enter PerProcessState"); } @Override public boolean processMessage(Message message) { if (DBG) log("PerProcessState process message: " + message.what); boolean retValue = HANDLED; switch (message.what) { case PER_PROCESS_TURN_ON: mCallback = (IBluetoothStateChangeCallback)getCurrentMessage().obj; // If this is not the first application call the callback. if (mBluetoothService.getNumberOfApplicationStateChangeTrackers() > 1) { perProcessCallback(true, mCallback); } break; case BECAME_PAIRABLE: perProcessCallback(true, mCallback); break; case USER_TURN_ON: broadcastState(BluetoothAdapter.STATE_TURNING_ON); persistSwitchSetting(true); String[] propVal = {"Pairable", mBluetoothService.getProperty("Pairable")}; mEventLoop.onPropertyChanged(propVal); // run bluetooth now that it's turned on mBluetoothService.runBluetooth(); transitionTo(mBluetoothOn); broadcastState(BluetoothAdapter.STATE_ON); break; case USER_TURN_OFF: broadcastState(BluetoothAdapter.STATE_TURNING_OFF); if (mBluetoothService.getAdapterConnectionState() != BluetoothAdapter.STATE_DISCONNECTED) { mBluetoothService.disconnectDevices(); break; } //$FALL-THROUGH$ all devices are already disconnected case ALL_DEVICES_DISCONNECTED: mBluetoothService.finishDisable(); broadcastState(BluetoothAdapter.STATE_OFF); break; case PER_PROCESS_TURN_OFF: perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj); if (mBluetoothService.isApplicationStateChangeTrackerEmpty()) { mBluetoothService.switchConnectable(false); } break; case BECAME_NON_PAIRABLE: transitionTo(mHotOff); if (!mContext.getResources().getBoolean (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) { deferMessage(obtainMessage(TURN_COLD)); } break; case AIRPLANE_MODE_ON: mBluetoothService.switchConnectable(false); allProcessesCallback(false); // we turn all the way to PowerOff with AIRPLANE_MODE_ON deferMessage(obtainMessage(AIRPLANE_MODE_ON)); break; default: return NOT_HANDLED; } return retValue; } } private void perProcessCallback(boolean on, IBluetoothStateChangeCallback c) { if (c == null) return; try { c.onBluetoothStateChange(on); } catch (RemoteException e) {} } private void allProcessesCallback(boolean on) { for (IBluetoothStateChangeCallback c: mBluetoothService.getApplicationStateChangeCallbacks()) { perProcessCallback(on, c); } if (!on) { mBluetoothService.clearApplicationStateChangeTracker(); } } /** Loading Loading @@ -476,7 +616,7 @@ final class BluetoothAdapterStateMachine extends StateMachine { private void broadcastState(int newState) { if (DBG) log("Bluetooth state " + mPublicState + " -> " + newState); log("Bluetooth state " + mPublicState + " -> " + newState); if (mPublicState == newState) { return; } Loading