summaryrefslogtreecommitdiff
path: root/core/java/android/bluetooth/BluetoothAdapter.java
diff options
context:
space:
mode:
authorNitin Arora <niarora@codeaurora.org>2015-03-02 15:03:51 -0800
committerAndre Eisenbach <eisenbach@google.com>2015-04-15 16:26:42 +0000
commit6ddbb5e55f72e870899731ff12af9945fa970e6e (patch)
tree5fcbba4465a16a2d8b7726ad87894c51553c4df3 /core/java/android/bluetooth/BluetoothAdapter.java
parent104b0f1353934fc5caa045441d22becf0f90dac2 (diff)
Bluetooth LE background operation mode (2/2)
Changes include new framework APIs to enable and disable Bluetooth LE separately from Bluetooth Classic. Along with handling the new states in the Bluetooth manager service. Change-Id: Idf667981f48fcbcb6dfda1aa77ea8bab1b2361f0
Diffstat (limited to 'core/java/android/bluetooth/BluetoothAdapter.java')
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java312
1 files changed, 304 insertions, 8 deletions
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ac74a621a763..88bb626bfd7e 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -34,6 +34,9 @@ import android.os.Looper;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.app.ActivityThread;
+import android.os.SystemProperties;
+import android.os.Binder;
import android.util.Log;
import android.util.Pair;
@@ -121,6 +124,9 @@ public final class BluetoothAdapter {
* {@link #STATE_TURNING_ON},
* {@link #STATE_ON},
* {@link #STATE_TURNING_OFF},
+ * {@link #STATE_BLE_TURNING_ON},
+ * {@link #STATE_BLE_ON},
+ * {@link #STATE_BLE_TURNING_OFF},
*/
public static final String EXTRA_STATE =
"android.bluetooth.adapter.extra.STATE";
@@ -131,6 +137,9 @@ public final class BluetoothAdapter {
* {@link #STATE_TURNING_ON},
* {@link #STATE_ON},
* {@link #STATE_TURNING_OFF},
+ * {@link #STATE_BLE_TURNING_ON},
+ * {@link #STATE_BLE_ON},
+ * {@link #STATE_BLE_TURNING_OFF},
*/
public static final String EXTRA_PREVIOUS_STATE =
"android.bluetooth.adapter.extra.PREVIOUS_STATE";
@@ -156,6 +165,24 @@ public final class BluetoothAdapter {
public static final int STATE_TURNING_OFF = 13;
/**
+ * Indicates the local Bluetooth adapter is turning Bluetooth LE mode on.
+ * @hide
+ */
+ public static final int STATE_BLE_TURNING_ON = 14;
+
+ /**
+ * Indicates the local Bluetooth adapter is in LE only mode.
+ * @hide
+ */
+ public static final int STATE_BLE_ON = 15;
+
+ /**
+ * Indicates the local Bluetooth adapter is turning off LE only mode.
+ * @hide
+ */
+ public static final int STATE_BLE_TURNING_OFF = 16;
+
+ /**
* Activity Action: Show a system activity that requests discoverable mode.
* This activity will also request the user to turn on Bluetooth if it
* is not currently enabled.
@@ -366,6 +393,39 @@ public final class BluetoothAdapter {
public static final String EXTRA_PREVIOUS_CONNECTION_STATE =
"android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
+ /**
+ * Broadcast Action: The Bluetooth adapter state has changed in LE only mode.
+ * @hide
+ */
+ public static final String ACTION_BLE_STATE_CHANGED =
+ "anrdoid.bluetooth.adapter.action.BLE_STATE_CHANGED";
+
+ /**
+ * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
+ * by BLE Always on enabled application to know the ACL_CONNECTED event
+ * when Bluetooth state in STATE_BLE_ON. This denotes GATT connection
+ * as Bluetooth LE is the only feature available in STATE_BLE_ON
+ *
+ * This is counterpart of {@link BluetoothDevice#ACTION_ACL_CONNECTED} which
+ * works in Bluetooth state STATE_ON
+ * @hide
+ */
+ public static final String ACTION_BLE_ACL_CONNECTED =
+ "android.bluetooth.adapter.action.BLE_ACL_CONNECTED";
+
+ /**
+ * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
+ * by BLE Always on enabled application to know the ACL_DISCONNECTED event
+ * when Bluetooth state in STATE_BLE_ON. This denotes GATT disconnection as Bluetooth
+ * LE is the only feature available in STATE_BLE_ON
+ *
+ * This is counterpart of {@link BluetoothDevice#ACTION_ACL_DISCONNECTED} which
+ * works in Bluetooth state STATE_ON
+ * @hide
+ */
+ public static final String ACTION_BLE_ACL_DISCONNECTED =
+ "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED";
+
/** The profile is in disconnected state */
public static final int STATE_DISCONNECTED = 0;
/** The profile is in connecting state */
@@ -377,6 +437,7 @@ public final class BluetoothAdapter {
/** @hide */
public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
+ private final IBinder mToken;
/** When creating a ServerSocket using listenUsingRfcommOn() or
@@ -447,6 +508,7 @@ public final class BluetoothAdapter {
} catch (RemoteException e) {Log.e(TAG, "", e);}
mManagerService = managerService;
mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
+ mToken = new Binder();
}
/**
@@ -493,11 +555,9 @@ public final class BluetoothAdapter {
* on this device before calling this method.
*/
public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
- if (getState() != STATE_ON) {
- return null;
- }
+ if (!getLeAccess()) return null;
if (!isMultipleAdvertisementSupported() && !isPeripheralModeSupported()) {
- Log.e(TAG, "bluetooth le advertising not supported");
+ Log.e(TAG, "Bluetooth LE advertising not supported");
return null;
}
synchronized(mLock) {
@@ -512,9 +572,7 @@ public final class BluetoothAdapter {
* Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
*/
public BluetoothLeScanner getBluetoothLeScanner() {
- if (getState() != STATE_ON) {
- return null;
- }
+ if (!getLeAccess()) return null;
synchronized(mLock) {
if (sBluetoothLeScanner == null) {
sBluetoothLeScanner = new BluetoothLeScanner(mManagerService);
@@ -532,7 +590,6 @@ public final class BluetoothAdapter {
* @return true if the local adapter is turned on
*/
public boolean isEnabled() {
-
try {
synchronized(mManagerCallback) {
if (mService != null) return mService.isEnabled();
@@ -542,6 +599,178 @@ public final class BluetoothAdapter {
}
/**
+ * Return true if Bluetooth LE(Always BLE On feature) is currently
+ * enabled and ready for use
+ * <p>This returns true if current state is either STATE_ON or STATE_BLE_ON
+ *
+ * @return true if the local Bluetooth LE adapter is turned on
+ * @hide
+ */
+ public boolean isLeEnabled() {
+ final int state = getLeState();
+ if (state == BluetoothAdapter.STATE_ON) {
+ if (DBG) Log.d (TAG, "STATE_ON");
+ } else if (state == BluetoothAdapter.STATE_BLE_ON) {
+ if (DBG) Log.d (TAG, "STATE_BLE_ON");
+ } else {
+ if (DBG) Log.d (TAG, "STATE_OFF");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Performs action based on user action to turn BT ON
+ * or OFF if BT is in BLE_ON state
+ */
+ private void notifyUserAction(boolean enable) {
+ if (mService == null) {
+ Log.e(TAG, "mService is null");
+ return;
+ }
+
+ try {
+ if (enable) {
+ mService.onLeServiceUp(); //NA:TODO implementation pending
+ } else {
+ mService.onBrEdrDown(); //NA:TODO implementation pending
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
+ /**
+ * Returns true if LE only mode is enabled, that is apps
+ * have authorization to turn only BT ON and the calling
+ * app has privilage to do so
+ */
+ private boolean isLEAlwaysOnEnabled() {
+ boolean ret = false;
+ if (SystemProperties.getBoolean("ro.bluetooth.blealwayson", true) == true) {
+ Log.v(TAG, "LE always on mode is enabled");
+ // TODO: System API authorization check
+ ret = true;
+ } else {
+ Log.v(TAG, "LE always on mode is disabled");
+ ret = false;
+ }
+ return ret;
+ }
+
+ /**
+ * Turns off Bluetooth LE which was earlier turned on by calling EnableBLE().
+ *
+ * <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition
+ * to STATE_OFF and completely shut-down Bluetooth
+ *
+ * <p> If the Adapter state is STATE_ON, This would unregister the existance of
+ * special Bluetooth LE application and hence the further turning off of Bluetooth
+ * from UI would ensure the complete turn-off of Bluetooth rather than staying back
+ * BLE only state
+ *
+ * <p>This is an asynchronous call: it will return immediately, and
+ * clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
+ * to be notified of subsequent adapter state changes If this call returns
+ * true, then the adapter state will immediately transition from {@link
+ * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
+ * later transition to either {@link #STATE_BLE_ON} or {@link
+ * #STATE_OFF} based on the existance of the further Always BLE ON enabled applications
+ * If this call returns false then there was an
+ * immediate problem that will prevent the QAdapter from being turned off -
+ * such as the QAadapter already being turned off.
+ *
+ * @return true to indicate success, or false on
+ * immediate error
+ * @hide
+ */
+ public boolean disableBLE() {
+ if (isLEAlwaysOnEnabled() != true) return false;
+
+ int state = getLeState();
+ if (state == BluetoothAdapter.STATE_ON) {
+ if (DBG) Log.d (TAG, "STATE_ON: shouldn't disable");
+ try {
+ mManagerService.updateBleAppCount(mToken, false);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ return true;
+
+ } else if (state == BluetoothAdapter.STATE_BLE_ON) {
+ if (DBG) Log.d (TAG, "STATE_BLE_ON");
+ int bleAppCnt = 0;
+ try {
+ bleAppCnt = mManagerService.updateBleAppCount(mToken, false);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ if (bleAppCnt == 0) {
+ // Disable only if there are no other clients
+ notifyUserAction(false);
+ }
+ return true;
+ }
+
+ if (DBG) Log.d (TAG, "STATE_OFF: Already disabled");
+ return false;
+ }
+
+ /**
+ * Special Applications who want to only turn on Bluetooth Low Energy (BLE) would
+ * EnableBLE, EnableBLE brings-up Bluetooth so that application can access
+ * only LE related feature (Bluetooth GATT layers interfaces using the respective class)
+ * EnableBLE in turn registers the existance of a special App which wants to
+ * turn on Bluetooth Low enrgy part without making it visible at the settings UI
+ * as Bluetooth ON.
+ * <p>Invoking EnableBLE when Bluetooth is already in ON state, would just registers
+ * the existance of special Application and doesn't do anything to current BT state.
+ * when user turn OFF Bluetooth from UI, if there is an existance of special app, Bluetooth
+ * would stay in BLE_ON state so that LE features are still acessible to the special
+ * Applications.
+ *
+ * <p>This is an asynchronous call: it will return immediately, and
+ * clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
+ * to be notified of subsequent adapter state changes. If this call returns
+ * true, then the adapter state will immediately transition from {@link
+ * #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, and some time
+ * later transition to either {@link #STATE_OFF} or {@link
+ * #STATE_BLE_ON}. If this call returns false then there was an
+ * immediate problem that will prevent the adapter from being turned on -
+ * such as Airplane mode, or the adapter is already turned on.
+ * (@link #ACTION_BLE_STATE_CHANGED) returns the Bluetooth Adapter's various
+ * states, It includes all the classic Bluetooth Adapter states along with
+ * internal BLE only states
+ *
+ * @return true to indicate Bluetooth LE start-up has begun, or false on
+ * immediate error
+ * @hide
+ */
+ public boolean enableBLE() {
+ if (isLEAlwaysOnEnabled() != true) return false;
+
+ if (isLeEnabled() == true) {
+ if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!");
+ try {
+ mManagerService.updateBleAppCount(mToken, true);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ return true;
+ }
+
+ try {
+ if (DBG) Log.d(TAG, "Calling enableBLE");
+ mManagerService.updateBleAppCount(mToken, true);
+ return mManagerService.enable();
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+
+ return false;
+ }
+
+ /**
* Get the current state of the local Bluetooth adapter.
* <p>Possible return values are
* {@link #STATE_OFF},
@@ -559,6 +788,13 @@ public final class BluetoothAdapter {
{
int state= mService.getState();
if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
+ //consider all internal states as OFF
+ if (state == BluetoothAdapter.STATE_BLE_ON
+ || state == BluetoothAdapter.STATE_BLE_TURNING_ON
+ || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
+ if (VDBG) Log.d(TAG, "Consider internal state as OFF");
+ state = BluetoothAdapter.STATE_OFF;
+ }
return state;
}
// TODO(BT) there might be a small gap during STATE_TURNING_ON that
@@ -570,6 +806,49 @@ public final class BluetoothAdapter {
}
/**
+ * Get the current state of the local Bluetooth adapter
+ * <p>This returns current internal state of Adapter including LE ON/OFF
+ *
+ * <p>Possible return values are
+ * {@link #STATE_OFF},
+ * {@link #STATE_BLE_TURNING_ON},
+ * {@link #STATE_BLE_ON},
+ * {@link #STATE_TURNING_ON},
+ * {@link #STATE_ON},
+ * {@link #STATE_TURNING_OFF},
+ * {@link #STATE_BLE_TURNING_OFF}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+ *
+ * @return current state of Bluetooth adapter
+ * @hide
+ */
+ public int getLeState() {
+ try {
+ synchronized(mManagerCallback) {
+ if (mService != null)
+ {
+ int state= mService.getState();
+ if (VDBG) Log.d(TAG,"getLeState() returning " + state);
+ return state;
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ return BluetoothAdapter.STATE_OFF;
+ }
+
+ boolean getLeAccess() {
+ if(getLeState() == STATE_ON)
+ return true;
+
+ else if (getLeState() == STATE_BLE_ON)
+ return true; // TODO: FILTER SYSTEM APPS HERE <--
+
+ return false;
+ }
+
+ /**
* Turn on the local Bluetooth adapter&mdash;do not use without explicit
* user action to turn on Bluetooth.
* <p>This powers on the underlying Bluetooth hardware, and starts all
@@ -597,10 +876,23 @@ public final class BluetoothAdapter {
* immediate error
*/
public boolean enable() {
+ int state = STATE_OFF;
if (isEnabled() == true){
if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
return true;
}
+ //Use service interface to get the exact state
+ if (mService != null) {
+ try {
+ state = mService.getState();
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ }
+
+ if (state == BluetoothAdapter.STATE_BLE_ON) {
+ Log.e(TAG, "BT is in BLE_ON State");
+ notifyUserAction(true);
+ return true;
+ }
try {
return mManagerService.enable();
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -1561,6 +1853,10 @@ public final class BluetoothAdapter {
}
}
}
+
+ public void onBrEdrDown() {
+ if (VDBG) Log.i(TAG, "on QBrEdrDown: ");
+ }
};
/**