From 2d66488e7d7aeb87e4f7385dfe1a6c800c08391b Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Fri, 14 Aug 2009 18:33:38 -0700 Subject: Bluetooth: API change. Split BluetoothDevice into BluetoothDevice and BluetoothAdapter. BluetoothAdapter: Represents the local BT adapter. Operations on the local adapter (start a scan, etc). BluetoothDevice: Represents a remote BT device. Operations on remote devices (pair, connect, etc). IBluetoothDevice.aidl -> Bluetooth.aidl BluetoothDeviceService.java -> BluetoothDeviceService.java TODO: Javadoc --- .../java/android/bluetooth/BluetoothAdapter.java | 331 +++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 framework/java/android/bluetooth/BluetoothAdapter.java (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java new file mode 100644 index 0000000000..d2075407a4 --- /dev/null +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2009 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; + +import android.os.RemoteException; +import android.util.Log; + +import java.io.IOException; +import java.util.Collections; +import java.util.Set; +import java.util.HashSet; + +/** + * Represents the local Bluetooth adapter. + * + * @hide + */ +public final class BluetoothAdapter { + private static final String TAG = "BluetoothAdapter"; + + public static final int BLUETOOTH_STATE_OFF = 0; + public static final int BLUETOOTH_STATE_TURNING_ON = 1; + public static final int BLUETOOTH_STATE_ON = 2; + public static final int BLUETOOTH_STATE_TURNING_OFF = 3; + + /** Inquiry scan and page scan are both off. + * Device is neither discoverable nor connectable */ + public static final int SCAN_MODE_NONE = 0; + /** Page scan is on, inquiry scan is off. + * Device is connectable, but not discoverable */ + public static final int SCAN_MODE_CONNECTABLE = 1; + /** Page scan and inquiry scan are on. + * Device is connectable and discoverable */ + public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3; + + public static final int RESULT_FAILURE = -1; + public static final int RESULT_SUCCESS = 0; + + /* The user will be prompted to enter a pin */ + public static final int PAIRING_VARIANT_PIN = 0; + /* The user will be prompted to enter a passkey */ + public static final int PAIRING_VARIANT_PASSKEY = 1; + /* The user will be prompted to confirm the passkey displayed on the screen */ + public static final int PAIRING_VARIANT_CONFIRMATION = 2; + + private final IBluetooth mService; + + /** + * Do not use this constructor. Use Context.getSystemService() instead. + * @hide + */ + public BluetoothAdapter(IBluetooth service) { + if (service == null) { + throw new IllegalArgumentException("service is null"); + } + mService = service; + } + + /** + * Get the remote BluetoothDevice associated with the given MAC address. + * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB". + * @param address valid Bluetooth MAC address + */ + public BluetoothDevice getRemoteDevice(String address) { + return new BluetoothDevice(address); + } + + /** + * Is Bluetooth currently turned on. + * + * @return true if Bluetooth enabled, false otherwise. + */ + public boolean isEnabled() { + try { + return mService.isEnabled(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** + * Get the current state of Bluetooth. + * + * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR. + */ + public int getBluetoothState() { + try { + return mService.getBluetoothState(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return BluetoothError.ERROR; + } + + /** + * Enable the Bluetooth device. + * Turn on the underlying hardware. + * This is an asynchronous call, + * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if + * and when the device is sucessfully enabled. + * @return false if we cannot enable the Bluetooth device. True does not + * imply the device was enabled, it only implies that so far there were no + * problems. + */ + public boolean enable() { + try { + return mService.enable(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** + * Disable the Bluetooth device. + * This turns off the underlying hardware. + * + * @return true if successful, false otherwise. + */ + public boolean disable() { + try { + return mService.disable(true); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + public String getAddress() { + try { + return mService.getAddress(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return null; + } + + /** + * Get the friendly Bluetooth name of this device. + * + * This name is visible to remote Bluetooth devices. Currently it is only + * possible to retrieve the Bluetooth name when Bluetooth is enabled. + * + * @return the Bluetooth name, or null if there was a problem. + */ + public String getName() { + try { + return mService.getName(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return null; + } + + /** + * Set the friendly Bluetooth name of this device. + * + * This name is visible to remote Bluetooth devices. The Bluetooth Service + * is responsible for persisting this name. + * + * @param name the name to set + * @return true, if the name was successfully set. False otherwise. + */ + public boolean setName(String name) { + try { + return mService.setName(name); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** + * Get the current scan mode. + * Used to determine if the local device is connectable and/or discoverable + * @return Scan mode, one of SCAN_MODE_* or an error code + */ + public int getScanMode() { + try { + return mService.getScanMode(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return BluetoothError.ERROR_IPC; + } + + /** + * Set the current scan mode. + * Used to make the local device connectable and/or discoverable + * @param scanMode One of SCAN_MODE_* + */ + public void setScanMode(int scanMode) { + try { + mService.setScanMode(scanMode); + } catch (RemoteException e) {Log.e(TAG, "", e);} + } + + public int getDiscoverableTimeout() { + try { + return mService.getDiscoverableTimeout(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return -1; + } + + public void setDiscoverableTimeout(int timeout) { + try { + mService.setDiscoverableTimeout(timeout); + } catch (RemoteException e) {Log.e(TAG, "", e);} + } + + public boolean startDiscovery() { + try { + return mService.startDiscovery(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + public void cancelDiscovery() { + try { + mService.cancelDiscovery(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + } + + public boolean isDiscovering() { + try { + return mService.isDiscovering(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** + * List remote devices that are bonded (paired) to the local adapter. + * + * Bonding (pairing) is the process by which the user enters a pin code for + * the device, which generates a shared link key, allowing for + * authentication and encryption of future connections. In Android we + * require bonding before RFCOMM or SCO connections can be made to a remote + * device. + * + * This function lists which remote devices we have a link key for. It does + * not cause any RF transmission, and does not check if the remote device + * still has it's link key with us. If the other side no longer has its + * link key then the RFCOMM or SCO connection attempt will result in an + * error. + * + * This function does not check if the remote device is in range. + * + * Remote devices that have an in-progress bonding attempt are not + * returned. + * + * @return unmodifiable set of bonded devices, or null on error + */ + public Set getBondedDevices() { + try { + return toDeviceSet(mService.listBonds()); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return null; + } + + /** + * Construct a listening, secure RFCOMM server socket. + * The remote device connecting to this socket will be authenticated and + * communication on this socket will be encrypted. + * Call #accept to retrieve connections to this socket. + * @return An RFCOMM BluetoothServerSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + */ + public BluetoothServerSocket listenUsingRfcommOn(int port) throws IOException { + BluetoothServerSocket socket = new BluetoothServerSocket( + BluetoothSocket.TYPE_RFCOMM, true, true, port); + try { + socket.mSocket.bindListenNative(); + } catch (IOException e) { + try { + socket.close(); + } catch (IOException e2) { } + throw e; + } + return socket; + } + + /** + * Construct an unencrypted, unauthenticated, RFCOMM server socket. + * Call #accept to retrieve connections to this socket. + * @return An RFCOMM BluetoothServerSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + */ + public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { + BluetoothServerSocket socket = new BluetoothServerSocket( + BluetoothSocket.TYPE_RFCOMM, false, false, port); + try { + socket.mSocket.bindListenNative(); + } catch (IOException e) { + try { + socket.close(); + } catch (IOException e2) { } + throw e; + } + return socket; + } + + /** + * Construct a SCO server socket. + * Call #accept to retrieve connections to this socket. + * @return A SCO BluetoothServerSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + */ + public static BluetoothServerSocket listenUsingScoOn() throws IOException { + BluetoothServerSocket socket = new BluetoothServerSocket( + BluetoothSocket.TYPE_SCO, false, false, -1); + try { + socket.mSocket.bindListenNative(); + } catch (IOException e) { + try { + socket.close(); + } catch (IOException e2) { } + throw e; + } + return socket; + } + + private Set toDeviceSet(String[] addresses) { + Set devices = new HashSet(addresses.length); + for (int i = 0; i < addresses.length; i++) { + devices.add(getRemoteDevice(addresses[i])); + } + return Collections.unmodifiableSet(devices); + } +} -- cgit v1.2.3 From 753da539da89aac6762ef2183680205f8fd4e95a Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Wed, 19 Aug 2009 11:00:00 -0700 Subject: API CHANGE Javadoc, and unhide the first pieces of the Bluetooth API. With this commit there is enough public API to connect and use an RFCOMM connection between Bluetooth devices. --- .../java/android/bluetooth/BluetoothAdapter.java | 79 +++++++++++++++++----- 1 file changed, 62 insertions(+), 17 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index d2075407a4..6bd2a5abc3 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -27,34 +27,54 @@ import java.util.HashSet; /** * Represents the local Bluetooth adapter. * - * @hide + *

Use {@link android.content.Context#getSystemService} with {@link + * android.content.Context#BLUETOOTH_SERVICE} to get the default local + * Bluetooth adapter. On most Android devices there is only one local + * Bluetotoh adapter. + * + *

Use the {@link BluetoothDevice} class for operations on remote Bluetooth + * devices. + * + *

TODO: unhide more of this class */ public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; + /** @hide */ public static final int BLUETOOTH_STATE_OFF = 0; + /** @hide */ public static final int BLUETOOTH_STATE_TURNING_ON = 1; + /** @hide */ public static final int BLUETOOTH_STATE_ON = 2; + /** @hide */ public static final int BLUETOOTH_STATE_TURNING_OFF = 3; /** Inquiry scan and page scan are both off. - * Device is neither discoverable nor connectable */ + * Device is neither discoverable nor connectable + * @hide */ public static final int SCAN_MODE_NONE = 0; /** Page scan is on, inquiry scan is off. - * Device is connectable, but not discoverable */ + * Device is connectable, but not discoverable + * @hide*/ public static final int SCAN_MODE_CONNECTABLE = 1; /** Page scan and inquiry scan are on. - * Device is connectable and discoverable */ + * Device is connectable and discoverable + * @hide*/ public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3; + /** @hide */ public static final int RESULT_FAILURE = -1; + /** @hide */ public static final int RESULT_SUCCESS = 0; - /* The user will be prompted to enter a pin */ + /** The user will be prompted to enter a pin + * @hide */ public static final int PAIRING_VARIANT_PIN = 0; - /* The user will be prompted to enter a passkey */ + /** The user will be prompted to enter a passkey + * @hide */ public static final int PAIRING_VARIANT_PASSKEY = 1; - /* The user will be prompted to confirm the passkey displayed on the screen */ + /** The user will be prompted to confirm the passkey displayed on the screen + * @hide */ public static final int PAIRING_VARIANT_CONFIRMATION = 2; private final IBluetooth mService; @@ -71,9 +91,14 @@ public final class BluetoothAdapter { } /** - * Get the remote BluetoothDevice associated with the given MAC address. - * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB". + * Get a {@link BluetoothDevice} object for the given Bluetooth hardware + * address. + *

Valid Bluetooth hardware addresses must be upper case, in a format + * such as "00:11:22:33:AA:BB". + *

A {@link BluetoothDevice} will always be returned for a valid + * hardware address, even if this adapter has never seen that device. * @param address valid Bluetooth MAC address + * @throws IllegalArgumentException if address is invalid */ public BluetoothDevice getRemoteDevice(String address) { return new BluetoothDevice(address); @@ -83,6 +108,7 @@ public final class BluetoothAdapter { * Is Bluetooth currently turned on. * * @return true if Bluetooth enabled, false otherwise. + * @hide */ public boolean isEnabled() { try { @@ -95,6 +121,7 @@ public final class BluetoothAdapter { * Get the current state of Bluetooth. * * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR. + * @hide */ public int getBluetoothState() { try { @@ -112,6 +139,7 @@ public final class BluetoothAdapter { * @return false if we cannot enable the Bluetooth device. True does not * imply the device was enabled, it only implies that so far there were no * problems. + * @hide */ public boolean enable() { try { @@ -125,6 +153,7 @@ public final class BluetoothAdapter { * This turns off the underlying hardware. * * @return true if successful, false otherwise. + * @hide */ public boolean disable() { try { @@ -133,6 +162,7 @@ public final class BluetoothAdapter { return false; } + /** @hide */ public String getAddress() { try { return mService.getAddress(); @@ -147,6 +177,7 @@ public final class BluetoothAdapter { * possible to retrieve the Bluetooth name when Bluetooth is enabled. * * @return the Bluetooth name, or null if there was a problem. + * @hide */ public String getName() { try { @@ -163,6 +194,7 @@ public final class BluetoothAdapter { * * @param name the name to set * @return true, if the name was successfully set. False otherwise. + * @hide */ public boolean setName(String name) { try { @@ -175,6 +207,7 @@ public final class BluetoothAdapter { * Get the current scan mode. * Used to determine if the local device is connectable and/or discoverable * @return Scan mode, one of SCAN_MODE_* or an error code + * @hide */ public int getScanMode() { try { @@ -187,6 +220,7 @@ public final class BluetoothAdapter { * Set the current scan mode. * Used to make the local device connectable and/or discoverable * @param scanMode One of SCAN_MODE_* + * @hide */ public void setScanMode(int scanMode) { try { @@ -194,6 +228,7 @@ public final class BluetoothAdapter { } catch (RemoteException e) {Log.e(TAG, "", e);} } + /** @hide */ public int getDiscoverableTimeout() { try { return mService.getDiscoverableTimeout(); @@ -201,12 +236,14 @@ public final class BluetoothAdapter { return -1; } + /** @hide */ public void setDiscoverableTimeout(int timeout) { try { mService.setDiscoverableTimeout(timeout); } catch (RemoteException e) {Log.e(TAG, "", e);} } + /** @hide */ public boolean startDiscovery() { try { return mService.startDiscovery(); @@ -214,12 +251,14 @@ public final class BluetoothAdapter { return false; } + /** @hide */ public void cancelDiscovery() { try { mService.cancelDiscovery(); } catch (RemoteException e) {Log.e(TAG, "", e);} } + /** @hide */ public boolean isDiscovering() { try { return mService.isDiscovering(); @@ -248,6 +287,7 @@ public final class BluetoothAdapter { * returned. * * @return unmodifiable set of bonded devices, or null on error + * @hide */ public Set getBondedDevices() { try { @@ -257,17 +297,20 @@ public final class BluetoothAdapter { } /** - * Construct a listening, secure RFCOMM server socket. - * The remote device connecting to this socket will be authenticated and + * Create a listening, secure RFCOMM Bluetooth socket. + *

A remote device connecting to this socket will be authenticated and * communication on this socket will be encrypted. - * Call #accept to retrieve connections to this socket. - * @return An RFCOMM BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or - * insufficient permissions. + *

Use {@link BluetoothServerSocket#accept} to retrieve incoming + * connections to listening {@link BluetoothServerSocket}. + *

Valid RFCOMM channels are in range 1 to 30. + * @param channel RFCOMM channel to listen on + * @return a listening RFCOMM BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or + * insufficient permissions, or channel in use. */ - public BluetoothServerSocket listenUsingRfcommOn(int port) throws IOException { + public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, true, true, port); + BluetoothSocket.TYPE_RFCOMM, true, true, channel); try { socket.mSocket.bindListenNative(); } catch (IOException e) { @@ -285,6 +328,7 @@ public final class BluetoothAdapter { * @return An RFCOMM BluetoothServerSocket * @throws IOException On error, for example Bluetooth not available, or * insufficient permissions. + * @hide */ public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( @@ -306,6 +350,7 @@ public final class BluetoothAdapter { * @return A SCO BluetoothServerSocket * @throws IOException On error, for example Bluetooth not available, or * insufficient permissions. + * @hide */ public static BluetoothServerSocket listenUsingScoOn() throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( -- cgit v1.2.3 From 4cd2cd92746e80798c79161791a4042251ed356a Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Wed, 2 Sep 2009 11:51:35 -0700 Subject: Immediately destroy BluetoothSocket's on close(). Unfortunatley, shutdown() on the underlying fd does not actually stop a listening socket from listening. You need to call close() on the fd to do this. There is no way around it. So this means the Java BluetoothSocket code has to call destroyNative() during BluetoothSocket.close(). Since native methods cannot be called after destroyNative(), add a ReadWrite lock and mClosed field to protect access to native methods. This fixes the "resource busy" error when Bluetooth OPP and Bluetooth PBAP tried to resume listening after turning BT off and then on. --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 6bd2a5abc3..8975fe27b7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -312,7 +312,7 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, true, true, channel); try { - socket.mSocket.bindListenNative(); + socket.mSocket.bindListen(); } catch (IOException e) { try { socket.close(); @@ -334,7 +334,7 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, false, false, port); try { - socket.mSocket.bindListenNative(); + socket.mSocket.bindListen(); } catch (IOException e) { try { socket.close(); @@ -356,7 +356,7 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_SCO, false, false, -1); try { - socket.mSocket.bindListenNative(); + socket.mSocket.bindListen(); } catch (IOException e) { try { socket.close(); -- cgit v1.2.3 From ed6f2ce927782e15c662eab48cd95d95e7ef7841 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Tue, 8 Sep 2009 10:12:06 -0700 Subject: Add javadoc to explain which permissions are required for Public BT API's. --- framework/java/android/bluetooth/BluetoothAdapter.java | 1 + 1 file changed, 1 insertion(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8975fe27b7..5a182f0fb4 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -303,6 +303,7 @@ public final class BluetoothAdapter { *

Use {@link BluetoothServerSocket#accept} to retrieve incoming * connections to listening {@link BluetoothServerSocket}. *

Valid RFCOMM channels are in range 1 to 30. + *

Requires {@link android.Manifest.permission#BLUETOOTH} * @param channel RFCOMM channel to listen on * @return a listening RFCOMM BluetoothServerSocket * @throws IOException on error, for example Bluetooth not available, or -- cgit v1.2.3 From 7482a80ce3d46f9991302cc464bc6a9e5a317451 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Tue, 8 Sep 2009 13:15:33 -0700 Subject: API_CHANGE Another round of Bluetooth API clean up, javadoc'ing and unhide'ing. -- Symbols for getting/setting bluetooth state -- BluetoothAdapter.ACTION_STATE_CHANGED BluetoothAdapter.EXTRA_STATE BluetoothAdapter.EXTRA_PREVIOUS_STATE BluetoothAdapter.STATE_OFF BluetoothAdapter.STATE_TURNING_ON BluetoothAdapter.STATE_ON BluetoothAdapter.STATE_TURNING_OFF BluetoothAdapter.isEnabled() BluetoothAdapter.getState() BluetoothAdapter.enable() BluetoothAdapter.disable() -- Symbols for getting/setting scan mode -- BluetoothAdapter.ACTION_SCAN_MODE_CHANGED BluetoothAdapter.EXTRA_SCAN_MODE BluetoothAdapter.EXTRA_PREVIOUS_SCAN_MODE BluetoothAdapter.SCAN_MODE_NONE BluetoothAdapter.SCAN_MODE_CONNECTABLE BluetoothAdapter.SCAN_MODE_DISCOVERABLE BluetoothAdapter.getScanMode() BluetoothAdapter.setScanMode() -- Symbols for getting address/names -- BluetoothAdapter.getAddress() BluetoothAdapter.getName() BluetoothAdapter.setName() --- .../java/android/bluetooth/BluetoothAdapter.java | 270 +++++++++++++++------ 1 file changed, 199 insertions(+), 71 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 5a182f0fb4..1770bc7935 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -16,6 +16,8 @@ package android.bluetooth; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; import android.os.RemoteException; import android.util.Log; @@ -40,32 +42,109 @@ import java.util.HashSet; public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; - /** @hide */ - public static final int BLUETOOTH_STATE_OFF = 0; - /** @hide */ - public static final int BLUETOOTH_STATE_TURNING_ON = 1; - /** @hide */ - public static final int BLUETOOTH_STATE_ON = 2; - /** @hide */ - public static final int BLUETOOTH_STATE_TURNING_OFF = 3; - - /** Inquiry scan and page scan are both off. - * Device is neither discoverable nor connectable - * @hide */ - public static final int SCAN_MODE_NONE = 0; - /** Page scan is on, inquiry scan is off. - * Device is connectable, but not discoverable - * @hide*/ - public static final int SCAN_MODE_CONNECTABLE = 1; - /** Page scan and inquiry scan are on. - * Device is connectable and discoverable - * @hide*/ - public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3; + /** + * Broadcast Action: The state of the local Bluetooth adapter has been + * changed. + *

For example, Bluetooth has been turned on or off. + *

Contains the extra fields {@link #EXTRA_STATE} and {@link + * #EXTRA_PREVIOUS_STATE} containing the new and old states + * respectively. + *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_STATE_CHANGED = + "android.bluetooth.intent.action.STATE_CHANGED"; - /** @hide */ - public static final int RESULT_FAILURE = -1; - /** @hide */ - public static final int RESULT_SUCCESS = 0; + /** + * Used as an int extra field in {@link #ACTION_STATE_CHANGED} + * intents to request the current power state. Possible values are: + * {@link #STATE_OFF}, + * {@link #STATE_TURNING_ON}, + * {@link #STATE_ON}, + * {@link #STATE_TURNING_OFF}, + */ + public static final String EXTRA_STATE = + "android.bluetooth.intent.extra.STATE"; + /** + * Used as an int extra field in {@link #ACTION_STATE_CHANGED} + * intents to request the previous power state. Possible values are: + * {@link #STATE_OFF}, + * {@link #STATE_TURNING_ON}, + * {@link #STATE_ON}, + * {@link #STATE_TURNING_OFF}, + */ + public static final String EXTRA_PREVIOUS_STATE = + "android.bluetooth.intent.extra.PREVIOUS_STATE"; + + /** + * Indicates the local Bluetooth adapter is off. + */ + public static final int STATE_OFF = 40; + /** + * Indicates the local Bluetooth adapter is turning on. However local + * clients should wait for {@link #STATE_ON} before attempting to + * use the adapter. + */ + public static final int STATE_TURNING_ON = 41; + /** + * Indicates the local Bluetooth adapter is on, and ready for use. + */ + public static final int STATE_ON = 42; + /** + * Indicates the local Bluetooth adapter is turning off. Local clients + * should immediately attempt graceful disconnection of any remote links. + */ + public static final int STATE_TURNING_OFF = 43; + + /** + * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter + * has changed. + *

Contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link + * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes + * respectively. + *

Requires {@link android.Manifest.permission#BLUETOOTH} + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_SCAN_MODE_CHANGED = + "android.bluetooth.intent.action.SCAN_MODE_CHANGED"; + + /** + * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} + * intents to request the current scan mode. Possible values are: + * {@link #SCAN_MODE_NONE}, + * {@link #SCAN_MODE_CONNECTABLE}, + * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, + */ + public static final String EXTRA_SCAN_MODE = "android.bluetooth.intent.extra.SCAN_MODE"; + /** + * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} + * intents to request the previous scan mode. Possible values are: + * {@link #SCAN_MODE_NONE}, + * {@link #SCAN_MODE_CONNECTABLE}, + * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, + */ + public static final String EXTRA_PREVIOUS_SCAN_MODE = + "android.bluetooth.intent.extra.PREVIOUS_SCAN_MODE"; + + /** + * Indicates that both inquiry scan and page scan are disabled on the local + * Bluetooth adapter. Therefore this device is neither discoverable + * nor connectable from remote Bluetooth devices. + */ + public static final int SCAN_MODE_NONE = 50; + /** + * Indicates that inquiry scan is disabled, but page scan is enabled on the + * local Bluetooth adapter. Therefore this device is not discoverable from + * remote Bluetooth devices, but is connectable from remote devices that + * have previously discovered this device. + */ + public static final int SCAN_MODE_CONNECTABLE = 51; + /** + * Indicates that both inquiry scan and page scan are enabled on the local + * Bluetooth adapter. Therefore this device is both discoverable and + * connectable from remote Bluetooth devices. + */ + public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 53; /** The user will be prompted to enter a pin * @hide */ @@ -97,6 +176,7 @@ public final class BluetoothAdapter { * such as "00:11:22:33:AA:BB". *

A {@link BluetoothDevice} will always be returned for a valid * hardware address, even if this adapter has never seen that device. + * * @param address valid Bluetooth MAC address * @throws IllegalArgumentException if address is invalid */ @@ -105,10 +185,12 @@ public final class BluetoothAdapter { } /** - * Is Bluetooth currently turned on. + * Return true if Bluetooth is currently enabled and ready for use. + *

Equivalent to: + * getBluetoothState() == STATE_ON + *

Requires {@link android.Manifest.permission#BLUETOOTH} * - * @return true if Bluetooth enabled, false otherwise. - * @hide + * @return true if the local adapter is turned on */ public boolean isEnabled() { try { @@ -118,28 +200,40 @@ public final class BluetoothAdapter { } /** - * Get the current state of Bluetooth. + * Get the current state of the local Bluetooth adapter. + *

Possible return values are + * {@link #STATE_OFF}, + * {@link #STATE_TURNING_ON}, + * {@link #STATE_ON}, + * {@link #STATE_TURNING_OFF}. + *

Requires {@link android.Manifest.permission#BLUETOOTH} * - * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR. - * @hide + * @return current state of Bluetooth adapter */ - public int getBluetoothState() { + public int getState() { try { return mService.getBluetoothState(); } catch (RemoteException e) {Log.e(TAG, "", e);} - return BluetoothError.ERROR; + return STATE_OFF; } /** - * Enable the Bluetooth device. - * Turn on the underlying hardware. - * This is an asynchronous call, - * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if - * and when the device is sucessfully enabled. - * @return false if we cannot enable the Bluetooth device. True does not - * imply the device was enabled, it only implies that so far there were no - * problems. - * @hide + * Turn on the local Bluetooth adapter. + *

This powers on the underlying Bluetooth hardware, and starts all + * Bluetooth system services. + *

This is an asynchronous call: it will return immediatley, and + * clients should listen for {@link #ACTION_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_TURNING_ON}, and some time + * later transition to either {@link #STATE_OFF} or {@link + * #STATE_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. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * + * @return true to indicate adapter startup has begun, or false on + * immediate error */ public boolean enable() { try { @@ -149,11 +243,22 @@ public final class BluetoothAdapter { } /** - * Disable the Bluetooth device. - * This turns off the underlying hardware. + * Turn off the local Bluetooth adapter. + *

This gracefully shuts down all Bluetooth connections, stops Bluetooth + * system services, and powers down the underlying Bluetooth hardware. + *

This is an asynchronous call: it will return immediatley, and + * clients should listen for {@link #ACTION_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_OFF} or {@link + * #STATE_ON}. If this call returns false then there was an + * immediate problem that will prevent the adapter from being turned off - + * such as the adapter already being turned off. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * - * @return true if successful, false otherwise. - * @hide + * @return true to indicate adapter shutdown has begun, or false on + * immediate error */ public boolean disable() { try { @@ -162,7 +267,13 @@ public final class BluetoothAdapter { return false; } - /** @hide */ + /** + * Returns the hardware address of the local Bluetooth adapter. + *

For example, "00:11:22:AA:BB:CC". + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * + * @return Bluetooth hardware address as string + */ public String getAddress() { try { return mService.getAddress(); @@ -171,13 +282,11 @@ public final class BluetoothAdapter { } /** - * Get the friendly Bluetooth name of this device. - * - * This name is visible to remote Bluetooth devices. Currently it is only - * possible to retrieve the Bluetooth name when Bluetooth is enabled. + * Get the friendly Bluetooth name of the local Bluetooth adapter. + *

This name is visible to remote Bluetooth devices. + *

Requires {@link android.Manifest.permission#BLUETOOTH} * - * @return the Bluetooth name, or null if there was a problem. - * @hide + * @return the Bluetooth name, or null on error */ public String getName() { try { @@ -187,14 +296,15 @@ public final class BluetoothAdapter { } /** - * Set the friendly Bluetooth name of this device. - * - * This name is visible to remote Bluetooth devices. The Bluetooth Service - * is responsible for persisting this name. + * Set the friendly Bluetooth name of the local Bluetoth adapter. + *

This name is visible to remote Bluetooth devices. + *

Valid Bluetooth names are a maximum of 248 UTF-8 characters, however + * many remote devices can only display the first 40 characters, and some + * may be limited to just 20. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * - * @param name the name to set - * @return true, if the name was successfully set. False otherwise. - * @hide + * @param name a valid Bluetooth name + * @return true if the name was set, false otherwise */ public boolean setName(String name) { try { @@ -204,28 +314,46 @@ public final class BluetoothAdapter { } /** - * Get the current scan mode. - * Used to determine if the local device is connectable and/or discoverable - * @return Scan mode, one of SCAN_MODE_* or an error code - * @hide + * Get the current Bluetooth scan mode of the local Bluetooth adaper. + *

The Bluetooth scan mode determines if the local adapter is + * connectable and/or discoverable from remote Bluetooth devices. + *

Possible values are: + * {@link #SCAN_MODE_NONE}, + * {@link #SCAN_MODE_CONNECTABLE}, + * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * + * @return scan mode */ public int getScanMode() { try { return mService.getScanMode(); } catch (RemoteException e) {Log.e(TAG, "", e);} - return BluetoothError.ERROR_IPC; + return SCAN_MODE_NONE; } /** - * Set the current scan mode. - * Used to make the local device connectable and/or discoverable - * @param scanMode One of SCAN_MODE_* - * @hide + * Set the Bluetooth scan mode of the local Bluetooth adapter. + *

The Bluetooth scan mode determines if the local adapter is + * connectable and/or discoverable from remote Bluetooth devices. + *

For privacy reasons, it is recommended to limit the duration of time + * that the local adapter remains in a discoverable scan mode. For example, + * 2 minutes is a generous time to allow a remote Bluetooth device to + * initiate and complete its discovery process. + *

Valid scan mode values are: + * {@link #SCAN_MODE_NONE}, + * {@link #SCAN_MODE_CONNECTABLE}, + * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * + * @param mode valid scan mode + * @return true if the scan mode was set, false otherwise */ - public void setScanMode(int scanMode) { + public boolean setScanMode(int mode) { try { - mService.setScanMode(scanMode); + return mService.setScanMode(mode); } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; } /** @hide */ -- cgit v1.2.3 From 8a1cd0cdce892a6bd25bc7292007fe0220b3ae10 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Tue, 8 Sep 2009 17:40:43 -0700 Subject: API_CHANGE Deprecate BluetoothError.java. I spent a lot of time experimenting with a class BluetoothError to enumerate the many error codes returned by the Bluetooth API. But at the end of the day they were never used. The vast majority of method calls only really need a true/false error value, and often not even that. Methods which do need more detailed error enumeration (for example, bonding failures) can have there own enumerated error codes. But there is no need for a common set of error codes. Also change the IPC failed warnings in BluetoothA2dp to Log.e. These indicate a very serious error. Introduce BluetoothAdapter.ERROR and BluetoothDevice.ERROR as helper sentinel values. --- framework/java/android/bluetooth/BluetoothAdapter.java | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 1770bc7935..18f6995d26 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -42,6 +42,15 @@ import java.util.HashSet; public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; + /** + * Sentinel error value for this class. Guaranteed to not equal any other + * integer constant in this class. Provided as a convenience for functions + * that require a sentinel error value, for example: + *

Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, + * BluetoothAdapter.ERROR) + */ + public static final int ERROR = -1; + /** * Broadcast Action: The state of the local Bluetooth adapter has been * changed. -- cgit v1.2.3 From dac4c0d7c3ac27746fb8feaf8fc74221972ff5f2 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Thu, 10 Sep 2009 10:21:56 -0700 Subject: API_CHANGE: Cleanup, javadoc and unhide more Bluetooth API. This is a large batch, and covers: -- Bluetooth Device Discovery -- BluetoothAdapter.ACTION_DISCOVERY_STARTED BluetoothAdapter.ACTION_DISCOVERY_FINISHED BluetoothAdapter.startDiscovery() BluetoothAdapter.cancelDiscovery() BluetoothAdapter.isDiscovering() -- Bluetooth bonding (pairing) -- BluetoothAdapter.getBondedDevices() BluetoothDevice.ACTION_BOND_STATE_CHANGED BluetoothDevice.EXTRA_BOND_STATE BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE BluetoothDevice.BOND_NONE BluetoothDevice.BOND_BONDING BluetoothDevice.BOND_BONDED BluetoothDevice.getBondState() BluetoothDevice.createBond() BluetoothDevice.cancelBondProcess() BluetoothDevice.removeBond() -- BluetoothClass -- BluetoothDevice.ACTION_CLASS_CHANGED BluetoothDevice.EXTRA_CLASS BluetoothDevice.getBluetoothClass() BluetoothClass.Service.* BluetoothClass.Device.Major.* BluetoothClass.Device.* BluetoothClass.getDeviceClass() BluetoothClass.getMajorDeviceClass() BluetoothClass.hasService() -- Misc BluetoothDevice -- BluetoothDevice.ACTION_ACL_CONNECTED BluetoothDevice.ACTION_ACL_DISCONNECTED_REQUESTED BluetoothDevice.ACTION_ACL_DISCONNECTED BluetoothDevice.ACTION_DISCOVERED BluetoothDevice.ACTION_NAME_CHANGED BluetoothDevice.EXTRA_DEVICE BluetoothDevice.EXTRA_NAME BluetoothDevice.EXTRA_RSSI -- Misc BluetoothAdapter -- BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED BluetoothAdapter.EXTRA_LOCAL_NAME BluetoothAdapter.checkBluetoothAddress() I deprecated BluetoothIntent and moved each intent into the class it relates to. Change-Id: I877b1280428ab46278b2bc25668bb44cda22dc36 --- .../java/android/bluetooth/BluetoothAdapter.java | 192 +++++++++++++++------ 1 file changed, 140 insertions(+), 52 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 18f6995d26..96a927b30c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -36,8 +36,6 @@ import java.util.HashSet; * *

Use the {@link BluetoothDevice} class for operations on remote Bluetooth * devices. - * - *

TODO: unhide more of this class */ public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; @@ -49,20 +47,20 @@ public final class BluetoothAdapter { *

Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, * BluetoothAdapter.ERROR) */ - public static final int ERROR = -1; + public static final int ERROR = Integer.MIN_VALUE; /** * Broadcast Action: The state of the local Bluetooth adapter has been * changed. *

For example, Bluetooth has been turned on or off. - *

Contains the extra fields {@link #EXTRA_STATE} and {@link + *

Always contains the extra fields {@link #EXTRA_STATE} and {@link * #EXTRA_PREVIOUS_STATE} containing the new and old states * respectively. *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_STATE_CHANGED = - "android.bluetooth.intent.action.STATE_CHANGED"; + "android.bluetooth.adapter.action.STATE_CHANGED"; /** * Used as an int extra field in {@link #ACTION_STATE_CHANGED} @@ -73,7 +71,7 @@ public final class BluetoothAdapter { * {@link #STATE_TURNING_OFF}, */ public static final String EXTRA_STATE = - "android.bluetooth.intent.extra.STATE"; + "android.bluetooth.adapter.extra.STATE"; /** * Used as an int extra field in {@link #ACTION_STATE_CHANGED} * intents to request the previous power state. Possible values are: @@ -83,39 +81,39 @@ public final class BluetoothAdapter { * {@link #STATE_TURNING_OFF}, */ public static final String EXTRA_PREVIOUS_STATE = - "android.bluetooth.intent.extra.PREVIOUS_STATE"; + "android.bluetooth.adapter.extra.PREVIOUS_STATE"; /** * Indicates the local Bluetooth adapter is off. */ - public static final int STATE_OFF = 40; + public static final int STATE_OFF = 10; /** * Indicates the local Bluetooth adapter is turning on. However local * clients should wait for {@link #STATE_ON} before attempting to * use the adapter. */ - public static final int STATE_TURNING_ON = 41; + public static final int STATE_TURNING_ON = 11; /** * Indicates the local Bluetooth adapter is on, and ready for use. */ - public static final int STATE_ON = 42; + public static final int STATE_ON = 12; /** * Indicates the local Bluetooth adapter is turning off. Local clients * should immediately attempt graceful disconnection of any remote links. */ - public static final int STATE_TURNING_OFF = 43; + public static final int STATE_TURNING_OFF = 13; /** * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter * has changed. - *

Contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link + *

Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes * respectively. *

Requires {@link android.Manifest.permission#BLUETOOTH} */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_SCAN_MODE_CHANGED = - "android.bluetooth.intent.action.SCAN_MODE_CHANGED"; + "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; /** * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} @@ -124,7 +122,7 @@ public final class BluetoothAdapter { * {@link #SCAN_MODE_CONNECTABLE}, * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, */ - public static final String EXTRA_SCAN_MODE = "android.bluetooth.intent.extra.SCAN_MODE"; + public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE"; /** * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} * intents to request the previous scan mode. Possible values are: @@ -133,37 +131,73 @@ public final class BluetoothAdapter { * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, */ public static final String EXTRA_PREVIOUS_SCAN_MODE = - "android.bluetooth.intent.extra.PREVIOUS_SCAN_MODE"; + "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE"; /** * Indicates that both inquiry scan and page scan are disabled on the local * Bluetooth adapter. Therefore this device is neither discoverable * nor connectable from remote Bluetooth devices. */ - public static final int SCAN_MODE_NONE = 50; + public static final int SCAN_MODE_NONE = 20; /** * Indicates that inquiry scan is disabled, but page scan is enabled on the * local Bluetooth adapter. Therefore this device is not discoverable from * remote Bluetooth devices, but is connectable from remote devices that * have previously discovered this device. */ - public static final int SCAN_MODE_CONNECTABLE = 51; + public static final int SCAN_MODE_CONNECTABLE = 21; /** * Indicates that both inquiry scan and page scan are enabled on the local * Bluetooth adapter. Therefore this device is both discoverable and * connectable from remote Bluetooth devices. */ - public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 53; + public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; + + + /** + * Broadcast Action: The local Bluetooth adapter has started the remote + * device discovery process. + *

This usually involves an inquiry scan of about 12 seconds, followed + * by a page scan of each new device to retrieve its Bluetooth name. + *

Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as + * remote Bluetooth devices are found. + *

Device discovery is a heavyweight procedure. New connections to + * remote Bluetooth devices should not be attempted while discovery is in + * progress, and existing connections will experience limited bandwidth + * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing + * discovery. + *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_DISCOVERY_STARTED = + "android.bluetooth.adapter.action.DISCOVERY_STARTED"; + /** + * Broadcast Action: The local Bluetooth adapter has finished the device + * discovery process. + *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_DISCOVERY_FINISHED = + "android.bluetooth.adapter.action.DISCOVERY_FINISHED"; + + /** + * Broadcast Action: The local Bluetooth adapter has changed its friendly + * Bluetooth name. + *

This name is visible to remote Bluetooth devices. + *

Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing + * the name. + *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_LOCAL_NAME_CHANGED = + "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED"; + /** + * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED} + * intents to request the local Bluetooth name. + */ + public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME"; - /** The user will be prompted to enter a pin - * @hide */ - public static final int PAIRING_VARIANT_PIN = 0; - /** The user will be prompted to enter a passkey - * @hide */ - public static final int PAIRING_VARIANT_PASSKEY = 1; - /** The user will be prompted to confirm the passkey displayed on the screen - * @hide */ - public static final int PAIRING_VARIANT_CONFIRMATION = 2; + private static final int ADDRESS_LENGTH = 17; private final IBluetooth mService; @@ -182,7 +216,8 @@ public final class BluetoothAdapter { * Get a {@link BluetoothDevice} object for the given Bluetooth hardware * address. *

Valid Bluetooth hardware addresses must be upper case, in a format - * such as "00:11:22:33:AA:BB". + * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is + * available to validate a Bluetooth address. *

A {@link BluetoothDevice} will always be returned for a valid * hardware address, even if this adapter has never seen that device. * @@ -380,7 +415,29 @@ public final class BluetoothAdapter { } catch (RemoteException e) {Log.e(TAG, "", e);} } - /** @hide */ + /** + * Start the remote device discovery process. + *

The discovery process usually involves an inquiry scan of about 12 + * seconds, followed by a page scan of each new device to retrieve its + * Bluetooth name. + *

This is an asynchronous call, it will return immediately. Register + * for {@link #ACTION_DISCOVERY_STARTED} and {@link + * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the + * discovery starts and completes. Register for {@link + * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices + * are found. + *

Device discovery is a heavyweight procedure. New connections to + * remote Bluetooth devices should not be attempted while discovery is in + * progress, and existing connections will experience limited bandwidth + * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing + * discovery. + *

Device discovery will only find remote devices that are currently + * discoverable (inquiry scan enabled). Many Bluetooth devices are + * not discoverable by default, and need to be entered into a special mode. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. + * + * @return true on success, false on error + */ public boolean startDiscovery() { try { return mService.startDiscovery(); @@ -388,14 +445,33 @@ public final class BluetoothAdapter { return false; } - /** @hide */ - public void cancelDiscovery() { + /** + * Cancel the current device discovery process. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. + * + * @return true on success, false on error + */ + public boolean cancelDiscovery() { try { mService.cancelDiscovery(); } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; } - /** @hide */ + /** + * Return true if the local Bluetooth adapter is currently in the device + * discovery process. + *

Device discovery is a heavyweight procedure. New connections to + * remote Bluetooth devices should not be attempted while discovery is in + * progress, and existing connections will experience limited bandwidth + * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing + * discovery. + *

Applications can also register for {@link #ACTION_DISCOVERY_STARTED} + * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery + * starts or completes. + * + * @return true if discovering + */ public boolean isDiscovering() { try { return mService.isDiscovering(); @@ -404,27 +480,10 @@ public final class BluetoothAdapter { } /** - * List remote devices that are bonded (paired) to the local adapter. - * - * Bonding (pairing) is the process by which the user enters a pin code for - * the device, which generates a shared link key, allowing for - * authentication and encryption of future connections. In Android we - * require bonding before RFCOMM or SCO connections can be made to a remote - * device. + * Return the set of {@link BluetoothDevice} objects that are bonded + * (paired) to the local adapter. * - * This function lists which remote devices we have a link key for. It does - * not cause any RF transmission, and does not check if the remote device - * still has it's link key with us. If the other side no longer has its - * link key then the RFCOMM or SCO connection attempt will result in an - * error. - * - * This function does not check if the remote device is in range. - * - * Remote devices that have an in-progress bonding attempt are not - * returned. - * - * @return unmodifiable set of bonded devices, or null on error - * @hide + * @return unmodifiable set of {@link BluetoothDevice}, or null on error */ public Set getBondedDevices() { try { @@ -511,4 +570,33 @@ public final class BluetoothAdapter { } return Collections.unmodifiableSet(devices); } + + /** + * Validate a Bluetooth address, such as "00:43:A8:23:10:F0" + * + * @param address Bluetooth address as string + * @return true if the address is valid, false otherwise + */ + public static boolean checkBluetoothAddress(String address) { + if (address == null || address.length() != ADDRESS_LENGTH) { + return false; + } + for (int i = 0; i < ADDRESS_LENGTH; i++) { + char c = address.charAt(i); + switch (i % 3) { + case 0: + case 1: + if (Character.digit(c, 16) != -1) { + break; // hex character, OK + } + return false; + case 2: + if (c == ':') { + break; // OK + } + return false; + } + } + return true; + } } -- cgit v1.2.3 From 6ef935c90c0988645d33529f4ddbe058977c765c Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Fri, 18 Sep 2009 11:37:06 -0700 Subject: Reject lowercase characters in checkBluetoothAddress(). This keeps consistency with Bluez which uses upper case string address. It's important to keep the case the same so that .equals() in BluetoothService.java work. Change-Id: I6404ca137d0aec3cc2e6e7cb79763d5305a03547 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 96a927b30c..1fc22fe524 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -573,6 +573,7 @@ public final class BluetoothAdapter { /** * Validate a Bluetooth address, such as "00:43:A8:23:10:F0" + *

Alphabetic characters must be uppercase to be valid. * * @param address Bluetooth address as string * @return true if the address is valid, false otherwise @@ -586,8 +587,9 @@ public final class BluetoothAdapter { switch (i % 3) { case 0: case 1: - if (Character.digit(c, 16) != -1) { - break; // hex character, OK + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { + // hex character, OK + break; } return false; case 2: -- cgit v1.2.3 From dc7043578c102cf719049414eb3b81c847d8f00c Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Thu, 24 Sep 2009 11:14:15 -0700 Subject: Bluetooth API: Do not allow apps to programmatically make BT discoverable. Instead add ACTION_REQUEST_DISCOVERABLE for the system to show a dialog to adjust discoverable mode. Also remove createBond(), removeBond() and cancelBondProcess(). The Settings App already handles these automatically when connections require bonding. Change-Id: I216154cd1b6de410de64ba91b07d7263ac03e8df --- .../java/android/bluetooth/BluetoothAdapter.java | 39 +++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 1fc22fe524..6aec52c0d4 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -103,6 +103,38 @@ public final class BluetoothAdapter { */ public static final int STATE_TURNING_OFF = 13; + /** + * Activity Action: Show a system activity that requests discoverable mode. + *

Discoverable mode is equivalent to {@link + * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see + * this Bluetooth adapter when they perform a discovery. + *

For privacy, Android is not by default discoverable. + *

The sender can optionally use extra field {@link + * #EXTRA_DISCOVERABLE_DURATION} to request the duration of + * discoverability. Currently the default duration is 120 seconds, and + * maximum duration is capped at 300 seconds for each request. + *

Notification of the result of this activity is posted using the + * {@link android.app.Activity#onActivityResult} callback. The + * resultCode + * will be the duration (in seconds) of discoverability, or a negative + * value if the user rejected discoverability. + *

Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED} + * for global notification whenever the scan mode changes. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_REQUEST_DISCOVERABLE = + "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"; + + /** + * Used as an optional int extra field in {@link + * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration + * for discoverability in seconds. The current default is 120 seconds, and + * requests over 300 seconds will be capped. These values could change. + */ + public static final String EXTRA_DISCOVERABLE_DURATION = + "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; + /** * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter * has changed. @@ -388,10 +420,15 @@ public final class BluetoothAdapter { * {@link #SCAN_MODE_NONE}, * {@link #SCAN_MODE_CONNECTABLE}, * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + *

Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} + *

Applications cannot set the scan mode. They should use + * startActivityForResult( + * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) + * instead. * * @param mode valid scan mode * @return true if the scan mode was set, false otherwise + * @hide */ public boolean setScanMode(int mode) { try { -- cgit v1.2.3 From 8946f239c4b2bc28191f5c61334ff026b574ee27 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 25 Sep 2009 16:31:39 +0400 Subject: Fix typo in Bluetooth docs. --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 6aec52c0d4..776c923c0b 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -297,7 +297,7 @@ public final class BluetoothAdapter { * Turn on the local Bluetooth adapter. *

This powers on the underlying Bluetooth hardware, and starts all * Bluetooth system services. - *

This is an asynchronous call: it will return immediatley, and + *

This is an asynchronous call: it will return immediately, and * clients should listen for {@link #ACTION_STATE_CHANGED} * to be notified of subsequent adapter state changes. If this call returns * true, then the adapter state will immediately transition from {@link @@ -322,7 +322,7 @@ public final class BluetoothAdapter { * Turn off the local Bluetooth adapter. *

This gracefully shuts down all Bluetooth connections, stops Bluetooth * system services, and powers down the underlying Bluetooth hardware. - *

This is an asynchronous call: it will return immediatley, and + *

This is an asynchronous call: it will return immediately, and * clients should listen for {@link #ACTION_STATE_CHANGED} * to be notified of subsequent adapter state changes. If this call returns * true, then the adapter state will immediately transition from {@link -- cgit v1.2.3 From 694305cd0ab6e95763aef6ee5e3732865af5642d Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Fri, 25 Sep 2009 15:00:29 -0700 Subject: Handle expiration of discovery mode in system server. Change-Id: I58fd199b40ffdf8168a5489be8eedb5d25d56722 --- .../java/android/bluetooth/BluetoothAdapter.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 776c923c0b..3aaed385df 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -412,10 +412,10 @@ public final class BluetoothAdapter { * Set the Bluetooth scan mode of the local Bluetooth adapter. *

The Bluetooth scan mode determines if the local adapter is * connectable and/or discoverable from remote Bluetooth devices. - *

For privacy reasons, it is recommended to limit the duration of time - * that the local adapter remains in a discoverable scan mode. For example, - * 2 minutes is a generous time to allow a remote Bluetooth device to - * initiate and complete its discovery process. + *

For privacy reasons, discoverable mode is automatically turned off + * after duration seconds. For example, 120 seconds should be + * enough for a remote device to initiate and complete its discovery + * process. *

Valid scan mode values are: * {@link #SCAN_MODE_NONE}, * {@link #SCAN_MODE_CONNECTABLE}, @@ -427,16 +427,23 @@ public final class BluetoothAdapter { * instead. * * @param mode valid scan mode + * @param duration time in seconds to apply scan mode, only used for + * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE} * @return true if the scan mode was set, false otherwise * @hide */ - public boolean setScanMode(int mode) { + public boolean setScanMode(int mode, int duration) { try { - return mService.setScanMode(mode); + return mService.setScanMode(mode, duration); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } + /** @hide */ + public boolean setScanMode(int mode) { + return setScanMode(mode, 120); + } + /** @hide */ public int getDiscoverableTimeout() { try { -- cgit v1.2.3 From b450b3153e4618801376fad8f4bbd945cf07eb31 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Mon, 28 Sep 2009 10:33:55 -0700 Subject: Add an API to request a system activity to turn on Bluetooth. Change-Id: I2fca33ad27017ea4e2ecba37854b749682d07672 --- .../java/android/bluetooth/BluetoothAdapter.java | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3aaed385df..7d94554286 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -105,6 +105,8 @@ public final class BluetoothAdapter { /** * 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. *

Discoverable mode is equivalent to {@link * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see * this Bluetooth adapter when they perform a discovery. @@ -120,7 +122,7 @@ public final class BluetoothAdapter { * value if the user rejected discoverability. *

Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED} * for global notification whenever the scan mode changes. - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + *

Requires {@link android.Manifest.permission#BLUETOOTH} */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_REQUEST_DISCOVERABLE = @@ -135,6 +137,24 @@ public final class BluetoothAdapter { public static final String EXTRA_DISCOVERABLE_DURATION = "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; + /** + * Activity Action: Show a system activity that allows the user to turn on + * Bluetooth. + *

This system activity will return once Bluetooth has completed turning + * on, or the user has decided not to turn Bluetooth on. + *

Notification of the result of this activity is posted using the + * {@link android.app.Activity#onActivityResult} callback. The + * resultCode + * will be negative if the user did not turn on Bluetooth, and non-negative + * if Bluetooth has been turned on. + *

Applications can also listen for {@link #ACTION_STATE_CHANGED} + * for global notification whenever Bluetooth is turned on or off. + *

Requires {@link android.Manifest.permission#BLUETOOTH} + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_REQUEST_ENABLE = + "android.bluetooth.adapter.action.REQUEST_ENABLE"; + /** * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter * has changed. -- cgit v1.2.3 From 03759e5324aeae8b7f95dfba6e6101baa3286184 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Mon, 28 Sep 2009 12:33:17 -0700 Subject: Move android.bluetooth.ParcelUuid to android.os.ParcelUuid Change-Id: I564429d5c5b6a5372b6ff26a53b0d7e518b53631 --- framework/java/android/bluetooth/BluetoothAdapter.java | 1 + 1 file changed, 1 insertion(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 7d94554286..e3ec2cc4cb 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -18,6 +18,7 @@ package android.bluetooth; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; -- cgit v1.2.3 From ee1402d8d697be3aa2858ee35e57db8c3e845a12 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Fri, 2 Oct 2009 20:34:18 -0700 Subject: Provide an API for apps to use a dynamic RFCOMM channel and SDP record. Hide listenUsingRfcommOn(int channel) Add listenUsingRfcomm(String name, ParcelUuid uuid) The new API automatically finds a free RFCOMM channel and registers an SDP record with the given uuid and name. The SDP record is automatically removed when the socket is closed, or if the application dies. Apps are prevented from registering SDP records with the uuid of system Bluetooth profiles, such as A2DP, HFP and OPP. Apps are prevented from removing SDP records that they did not create. This is tracked by pid. TODO: Provide an API for the connecting app to look up an SDP record. Bug: 2158900 DrNo: eastham Joke: "What did the dog say to the tree? bark." Change-Id: Ia92f51c34615a7270a403255ad2b8faa98c4a3f5 --- .../java/android/bluetooth/BluetoothAdapter.java | 158 ++++++++++++++++++--- 1 file changed, 141 insertions(+), 17 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e3ec2cc4cb..c6a0619cf8 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -18,14 +18,19 @@ package android.bluetooth; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.os.Binder; +import android.os.Handler; +import android.os.Message; import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; import java.io.IOException; import java.util.Collections; -import java.util.Set; import java.util.HashSet; +import java.util.LinkedList; +import java.util.Random; +import java.util.Set; /** * Represents the local Bluetooth adapter. @@ -40,6 +45,7 @@ import java.util.HashSet; */ public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; + private static final boolean DBG = true; //STOPSHIP: Remove excess logging /** * Sentinel error value for this class. Guaranteed to not equal any other @@ -557,30 +563,139 @@ public final class BluetoothAdapter { return null; } + /** + * Randomly picks RFCOMM channels until none are left. + * Avoids reserved channels. + */ + private static class RfcommChannelPicker { + private static final int[] RESERVED_RFCOMM_CHANNELS = new int[] { + 10, // HFAG + 11, // HSAG + 12, // OPUSH + 19, // PBAP + }; + private static LinkedList sChannels; // master list of non-reserved channels + private static Random sRandom; + + private final LinkedList mChannels; // local list of channels left to try + + public RfcommChannelPicker() { + synchronized (RfcommChannelPicker.class) { + if (sChannels == null) { + // lazy initialization of non-reserved rfcomm channels + sChannels = new LinkedList(); + for (int i = 1; i <= BluetoothSocket.MAX_RFCOMM_CHANNEL; i++) { + sChannels.addLast(new Integer(i)); + } + for (int reserved : RESERVED_RFCOMM_CHANNELS) { + sChannels.remove(new Integer(reserved)); + } + sRandom = new Random(); + } + mChannels = (LinkedList)sChannels.clone(); + } + } + /* Returns next random channel, or -1 if we're out */ + public int nextChannel() { + if (mChannels.size() == 0) { + return -1; + } + return mChannels.remove(sRandom.nextInt(mChannels.size())); + } + } + /** * Create a listening, secure RFCOMM Bluetooth socket. *

A remote device connecting to this socket will be authenticated and * communication on this socket will be encrypted. *

Use {@link BluetoothServerSocket#accept} to retrieve incoming - * connections to listening {@link BluetoothServerSocket}. + * connections from a listening {@link BluetoothServerSocket}. *

Valid RFCOMM channels are in range 1 to 30. - *

Requires {@link android.Manifest.permission#BLUETOOTH} + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * @param channel RFCOMM channel to listen on * @return a listening RFCOMM BluetoothServerSocket * @throws IOException on error, for example Bluetooth not available, or * insufficient permissions, or channel in use. + * @hide */ public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, true, true, channel); + int errno = socket.mSocket.bindListen(); + if (errno != 0) { + try { + socket.close(); + } catch (IOException e) {} + socket.mSocket.throwErrnoNative(errno); + } + return socket; + } + + /** + * Create a listening, secure RFCOMM Bluetooth socket with Service Record. + *

A remote device connecting to this socket will be authenticated and + * communication on this socket will be encrypted. + *

Use {@link BluetoothServerSocket#accept} to retrieve incoming + * connections from a listening {@link BluetoothServerSocket}. + *

The system will assign an unused RFCOMM channel to listen on. + *

The system will also register a Service Discovery + * Protocol (SDP) record with the local SDP server containing the specified + * UUID, service name, and auto-assigned channel. Remote Bluetooth devices + * can use the same UUID to query our SDP server and discover which channel + * to connect to. This SDP record will be removed when this socket is + * closed, or if this application closes unexpectedly. + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * @param name service name for SDP record + * @param uuid uuid for SDP record + * @return a listening RFCOMM BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or + * insufficient permissions, or channel in use. + */ + public BluetoothServerSocket listenUsingRfcomm(String name, ParcelUuid uuid) + throws IOException { + RfcommChannelPicker picker = new RfcommChannelPicker(); + + BluetoothServerSocket socket; + int channel; + int errno; + while (true) { + channel = picker.nextChannel(); + + if (channel == -1) { + throw new IOException("No available channels"); + } + + socket = new BluetoothServerSocket( + BluetoothSocket.TYPE_RFCOMM, true, true, channel); + errno = socket.mSocket.bindListen(); + if (errno == 0) { + if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel); + break; // success + } else if (errno == BluetoothSocket.EADDRINUSE) { + if (DBG) Log.d(TAG, "RFCOMM channel " + channel + " in use"); + try { + socket.close(); + } catch (IOException e) {} + continue; // try another channel + } else { + try { + socket.close(); + } catch (IOException e) {} + socket.mSocket.throwErrnoNative(errno); // Exception as a result of bindListen() + } + } + + int handle = -1; try { - socket.mSocket.bindListen(); - } catch (IOException e) { + handle = mService.addRfcommServiceRecord(name, uuid, channel, new Binder()); + } catch (RemoteException e) {Log.e(TAG, "", e);} + if (handle == -1) { try { socket.close(); - } catch (IOException e2) { } - throw e; + } catch (IOException e) {} + throw new IOException("Not able to register SDP record for " + name); } + socket.setCloseHandler(mHandler, handle); return socket; } @@ -595,13 +710,12 @@ public final class BluetoothAdapter { public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, false, false, port); - try { - socket.mSocket.bindListen(); - } catch (IOException e) { + int errno = socket.mSocket.bindListen(); + if (errno != 0) { try { socket.close(); - } catch (IOException e2) { } - throw e; + } catch (IOException e) {} + socket.mSocket.throwErrnoNative(errno); } return socket; } @@ -617,13 +731,12 @@ public final class BluetoothAdapter { public static BluetoothServerSocket listenUsingScoOn() throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_SCO, false, false, -1); - try { - socket.mSocket.bindListen(); - } catch (IOException e) { + int errno = socket.mSocket.bindListen(); + if (errno != 0) { try { socket.close(); - } catch (IOException e2) { } - throw e; + } catch (IOException e) {} + socket.mSocket.throwErrnoNative(errno); } return socket; } @@ -636,6 +749,17 @@ public final class BluetoothAdapter { return Collections.unmodifiableSet(devices); } + private Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + /* handle socket closing */ + int handle = msg.what; + try { + if (DBG) Log.d(TAG, "Removing service record " + Integer.toHexString(handle)); + mService.removeServiceRecord(handle); + } catch (RemoteException e) {Log.e(TAG, "", e);} + } + }; + /** * Validate a Bluetooth address, such as "00:43:A8:23:10:F0" *

Alphabetic characters must be uppercase to be valid. -- cgit v1.2.3 From 07b84cb5bb5283352a27cc0cf651586ed00035a0 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Wed, 7 Oct 2009 07:44:03 +0200 Subject: Encourage developers to connect RFCOMM by UUID instead of Channel. Hide createRfcommSocket(int channel) Add createRfcommSocketWithServiceRecord(UUID uuid) Rename listenUsingRfcomm(String,UUID) -> listenUsingRfcommWithServiceRecord(..) Now we have a complete API for developers to make peer-peer RFCOMM connections with hard-coding the limited (30) RFCOMM channels, instead using SDP lookup of an UUID. This commit addresses two serious bugs: - Do not throw IOException on accepting an incoming RFCOMM connection with BluetoothSocket. This was a regression from commit ee1402d8d697be3a - Workaround failure of bluez to update SDP cache when channel changes by trying to use the same RFCOMM channel on the server every time, instead of picking server channels randomly. This is a pretty ugly workaround, and we are still trying to fix the caching issue - but with this workaround we are at least shippable and apps will work at least until they start colliding on the 30 RFCOMM channels. DrNo: eastham Bug: 2158900 Joke: What did the digital watch say to his mom? "Look mom no hands." Change-Id: Ia4879943b83afac06b6f1a3f2391cf1628afce7d --- .../java/android/bluetooth/BluetoothAdapter.java | 40 +++++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index c6a0619cf8..8ce911de37 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.Random; import java.util.Set; +import java.util.UUID; /** * Represents the local Bluetooth adapter. @@ -564,8 +565,16 @@ public final class BluetoothAdapter { } /** - * Randomly picks RFCOMM channels until none are left. + * Picks RFCOMM channels until none are left. * Avoids reserved channels. + * Ideally we would pick random channels, but in the current implementation + * we start with the channel that is the hash of the UUID, and try every + * available channel from there. This means that in most cases a given + * uuid will use the same channel. This is a workaround for a Bluez SDP + * bug where we are not updating the cache when the channel changes for a + * uuid. + * TODO: Fix the Bluez SDP caching bug, and go back to random channel + * selection */ private static class RfcommChannelPicker { private static final int[] RESERVED_RFCOMM_CHANNELS = new int[] { @@ -579,7 +588,9 @@ public final class BluetoothAdapter { private final LinkedList mChannels; // local list of channels left to try - public RfcommChannelPicker() { + private final UUID mUuid; + + public RfcommChannelPicker(UUID uuid) { synchronized (RfcommChannelPicker.class) { if (sChannels == null) { // lazy initialization of non-reserved rfcomm channels @@ -594,13 +605,21 @@ public final class BluetoothAdapter { } mChannels = (LinkedList)sChannels.clone(); } + mUuid = uuid; } - /* Returns next random channel, or -1 if we're out */ + /* Returns next channel, or -1 if we're out */ public int nextChannel() { - if (mChannels.size() == 0) { - return -1; + int channel = mUuid.hashCode(); // always pick the same channel to try first + Integer channelInt; + while (mChannels.size() > 0) { + channelInt = new Integer(channel); + if (mChannels.remove(channelInt)) { + return channel; + } + channel = (channel % BluetoothSocket.MAX_RFCOMM_CHANNEL) + 1; } - return mChannels.remove(sRandom.nextInt(mChannels.size())); + + return -1; } } @@ -644,6 +663,8 @@ public final class BluetoothAdapter { * can use the same UUID to query our SDP server and discover which channel * to connect to. This SDP record will be removed when this socket is * closed, or if this application closes unexpectedly. + *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to + * connect to this socket from another device using the same {@link UUID}. *

Requires {@link android.Manifest.permission#BLUETOOTH} * @param name service name for SDP record * @param uuid uuid for SDP record @@ -651,9 +672,9 @@ public final class BluetoothAdapter { * @throws IOException on error, for example Bluetooth not available, or * insufficient permissions, or channel in use. */ - public BluetoothServerSocket listenUsingRfcomm(String name, ParcelUuid uuid) + public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) throws IOException { - RfcommChannelPicker picker = new RfcommChannelPicker(); + RfcommChannelPicker picker = new RfcommChannelPicker(uuid); BluetoothServerSocket socket; int channel; @@ -687,7 +708,8 @@ public final class BluetoothAdapter { int handle = -1; try { - handle = mService.addRfcommServiceRecord(name, uuid, channel, new Binder()); + handle = mService.addRfcommServiceRecord(name, new ParcelUuid(uuid), channel, + new Binder()); } catch (RemoteException e) {Log.e(TAG, "", e);} if (handle == -1) { try { -- cgit v1.2.3 From 79b3ff80ff00f3186f8d8cc07520a3c211e489a0 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Thu, 8 Oct 2009 00:12:45 +0200 Subject: Introduce BluetoothAdapter.getDefaultAdapter(). This is the main entry point to the Bluetooth APIs, and returns the default local Bluetooth adapter. It replaces context.getSystemService(Context.BLUETOOTH_SERVICE). This was never in a public SDK release. DrNo: eastham Bug: 2158765 Joke: Why can't you play cards in the jungle? Because there's too many cheetas! Change-Id: Ieed8be009ee5aba621cb69090ee8c8a9c19c840d --- .../java/android/bluetooth/BluetoothAdapter.java | 38 +++++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8ce911de37..cc35b7da9f 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -20,9 +20,11 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.os.Binder; import android.os.Handler; +import android.os.IBinder; import android.os.Message; import android.os.ParcelUuid; import android.os.RemoteException; +import android.os.ServiceManager; import android.util.Log; import java.io.IOException; @@ -36,10 +38,8 @@ import java.util.UUID; /** * Represents the local Bluetooth adapter. * - *

Use {@link android.content.Context#getSystemService} with {@link - * android.content.Context#BLUETOOTH_SERVICE} to get the default local - * Bluetooth adapter. On most Android devices there is only one local - * Bluetotoh adapter. + *

Use {@link #getDefaultAdapter} to get the default local Bluetooth + * adapter. * *

Use the {@link BluetoothDevice} class for operations on remote Bluetooth * devices. @@ -257,12 +257,40 @@ public final class BluetoothAdapter { */ public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME"; + /** @hide */ + public static final String BLUETOOTH_SERVICE = "bluetooth"; + private static final int ADDRESS_LENGTH = 17; + /** + * Lazyily initialized singleton. Guaranteed final after first object + * constructed. + */ + private static BluetoothAdapter sAdapter; + private final IBluetooth mService; /** - * Do not use this constructor. Use Context.getSystemService() instead. + * Get a handle to the default local Bluetooth adapter. + *

Currently Android only supports one Bluetooth adapter, but the API + * could be extended to support more. This will always return the default + * adapter. + * @return the default local adapter, or null if Bluetooth is not supported + * on this hardware platform + */ + public static synchronized BluetoothAdapter getDefaultAdapter() { + if (sAdapter == null) { + IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE); + if (b != null) { + IBluetooth service = IBluetooth.Stub.asInterface(b); + sAdapter = new BluetoothAdapter(service); + } + } + return sAdapter; + } + + /** + * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. * @hide */ public BluetoothAdapter(IBluetooth service) { -- cgit v1.2.3 From 2076d39018a62610c1242870a63e1f057b1e076a Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Thu, 8 Oct 2009 23:27:28 +0200 Subject: BT API security audit: fix a couple of permission mistakes. Make functions that are meant to be BLUETOOTH_ADMIN really BLUETOOTH_ADMIN. Add some missing javadoc for permissions. The only functional change here is the BLUETOOTH->BLUETOOTH_ADMIN changes. This is super safe because every system app that uses BT has both permissions. Change-Id: Iddc61f9fd5d81fe0171358665a0fa52f2fa02871 DrNo: eastham Joke: How do you catch a rabbit? Hide behind a tree and make carrott noises. --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index cc35b7da9f..5b34ef9ec0 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -569,6 +569,7 @@ public final class BluetoothAdapter { *

Applications can also register for {@link #ACTION_DISCOVERY_STARTED} * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery * starts or completes. + *

Requires {@link android.Manifest.permission#BLUETOOTH}. * * @return true if discovering */ @@ -582,6 +583,7 @@ public final class BluetoothAdapter { /** * Return the set of {@link BluetoothDevice} objects that are bonded * (paired) to the local adapter. + *

Requires {@link android.Manifest.permission#BLUETOOTH}. * * @return unmodifiable set of {@link BluetoothDevice}, or null on error */ -- cgit v1.2.3 From 4d4be0b0198c1718f42b1457e57d5cd1b178d2c7 Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Fri, 9 Oct 2009 00:54:41 +0200 Subject: Remove STOPSHIP BT logging. Do not merge. Change-Id: I428bc0fc67030f24112f2e9c865824dfaea4897d DrNo: eastham Bug: 2089423 Joke: Why was Tigger looking in the toilet? To find Pooh --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 5b34ef9ec0..ff48583a80 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -46,7 +46,7 @@ import java.util.UUID; */ public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; - private static final boolean DBG = true; //STOPSHIP: Remove excess logging + private static final boolean DBG = false; /** * Sentinel error value for this class. Guaranteed to not equal any other -- cgit v1.2.3 From 0abeb7e929ff9102e6c927c3603c7dbda17ffd20 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Fri, 30 Oct 2009 09:37:25 -0700 Subject: Revert the channge where channels were not selected randomly. The Bluez SDP bug has been fixed. Reverting parts of the commit: 07b84cb5bb5283352a27cc0cf651586ed00035a0 Bug: 2173752 Dr No: Eastham --- .../java/android/bluetooth/BluetoothAdapter.java | 23 ++++------------------ 1 file changed, 4 insertions(+), 19 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ff48583a80..3fc676b271 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -597,14 +597,6 @@ public final class BluetoothAdapter { /** * Picks RFCOMM channels until none are left. * Avoids reserved channels. - * Ideally we would pick random channels, but in the current implementation - * we start with the channel that is the hash of the UUID, and try every - * available channel from there. This means that in most cases a given - * uuid will use the same channel. This is a workaround for a Bluez SDP - * bug where we are not updating the cache when the channel changes for a - * uuid. - * TODO: Fix the Bluez SDP caching bug, and go back to random channel - * selection */ private static class RfcommChannelPicker { private static final int[] RESERVED_RFCOMM_CHANNELS = new int[] { @@ -637,19 +629,12 @@ public final class BluetoothAdapter { } mUuid = uuid; } - /* Returns next channel, or -1 if we're out */ + /* Returns next random channel, or -1 if we're out */ public int nextChannel() { - int channel = mUuid.hashCode(); // always pick the same channel to try first - Integer channelInt; - while (mChannels.size() > 0) { - channelInt = new Integer(channel); - if (mChannels.remove(channelInt)) { - return channel; - } - channel = (channel % BluetoothSocket.MAX_RFCOMM_CHANNEL) + 1; + if (mChannels.size() == 0) { + return -1; } - - return -1; + return mChannels.remove(sRandom.nextInt(mChannels.size())); } } -- cgit v1.2.3 From 2e2338332fd394754e74481c3f1f9e923bc3e842 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 5 Nov 2009 18:29:01 -0800 Subject: b/2234854 Fixed Bluetooth API return codes for requesting permission to enable bluetooth --- framework/java/android/bluetooth/BluetoothAdapter.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3fc676b271..4684f455e9 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -126,8 +126,9 @@ public final class BluetoothAdapter { *

Notification of the result of this activity is posted using the * {@link android.app.Activity#onActivityResult} callback. The * resultCode - * will be the duration (in seconds) of discoverability, or a negative - * value if the user rejected discoverability. + * will be the duration (in seconds) of discoverability or + * {@link android.app.Activity#RESULT_CANCELED} if the user rejected + * discoverability or an error has occurred. *

Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED} * for global notification whenever the scan mode changes. *

Requires {@link android.Manifest.permission#BLUETOOTH} @@ -153,8 +154,9 @@ public final class BluetoothAdapter { *

Notification of the result of this activity is posted using the * {@link android.app.Activity#onActivityResult} callback. The * resultCode - * will be negative if the user did not turn on Bluetooth, and non-negative - * if Bluetooth has been turned on. + * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been + * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user + * has rejected the request or an error has occurred. *

Applications can also listen for {@link #ACTION_STATE_CHANGED} * for global notification whenever Bluetooth is turned on or off. *

Requires {@link android.Manifest.permission#BLUETOOTH} -- cgit v1.2.3 From beef809fa89a5e7955a4c25cf70e00adbcf2e24e Mon Sep 17 00:00:00 2001 From: Scott Main Date: Tue, 3 Nov 2009 18:17:59 -0800 Subject: docs: add more documentation for the bluetooth apis. more descriptions for some of the classes and a new overview and pseudo-code example for using BT APIs in the package summary. --- .../java/android/bluetooth/BluetoothAdapter.java | 27 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ff48583a80..595156f71c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -36,13 +36,30 @@ import java.util.Set; import java.util.UUID; /** - * Represents the local Bluetooth adapter. + * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter} + * lets you perform fundamental Bluetooth tasks, such as initiate + * device discovery, query a list of bonded (paired) devices, + * instantiate a {@link BluetoothDevice} using a known MAC address, and create + * a {@link BluetoothServerSocket} to listen for connection requests from other + * devices. * - *

Use {@link #getDefaultAdapter} to get the default local Bluetooth - * adapter. + *

To get a {@link BluetoothAdapter} representing the local Bluetooth + * adapter, call the static {@link #getDefaultAdapter} method. + * Fundamentally, this is your starting point for all + * Bluetooth actions. Once you have the local adapter, you can get a set of + * {@link BluetoothDevice} objects representing all paired devices with + * {@link #getBondedDevices()}; start device discovery with + * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to + * listen for incoming connection requests with + * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}. * - *

Use the {@link BluetoothDevice} class for operations on remote Bluetooth - * devices. + *

Note: + * Most methods require the {@link android.Manifest.permission#BLUETOOTH} + * permission and some also require the + * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. + * + * {@see BluetoothDevice} + * {@see BluetoothServerSocket} */ public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; -- cgit v1.2.3 From a7848ce834a484d194d05afd8097ab3014f9b449 Mon Sep 17 00:00:00 2001 From: Scott Main Date: Thu, 19 Nov 2009 17:00:19 -0800 Subject: docs for ESR: add docs to bluetooth explainin that discovery should be cancelled before connecting to a device bug: 2160782,2198463 --- .../java/android/bluetooth/BluetoothAdapter.java | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 595156f71c..f8cf4f2491 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -130,13 +130,13 @@ public final class BluetoothAdapter { /** * Activity Action: Show a system activity that requests discoverable mode. - *

This activity will also request the user to turn on Bluetooth if it + * This activity will also request the user to turn on Bluetooth if it * is not currently enabled. *

Discoverable mode is equivalent to {@link * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see * this Bluetooth adapter when they perform a discovery. - *

For privacy, Android is not by default discoverable. - *

The sender can optionally use extra field {@link + *

For privacy, Android is not discoverable by default. + *

The sender of this Intent can optionally use extra field {@link * #EXTRA_DISCOVERABLE_DURATION} to request the duration of * discoverability. Currently the default duration is 120 seconds, and * maximum duration is capped at 300 seconds for each request. @@ -146,7 +146,8 @@ public final class BluetoothAdapter { * will be the duration (in seconds) of discoverability, or a negative * value if the user rejected discoverability. *

Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED} - * for global notification whenever the scan mode changes. + * for global notification whenever the scan mode changes. For example, an + * application can be notified when the device has ended discoverability. *

Requires {@link android.Manifest.permission#BLUETOOTH} */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) @@ -547,7 +548,10 @@ public final class BluetoothAdapter { * remote Bluetooth devices should not be attempted while discovery is in * progress, and existing connections will experience limited bandwidth * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing - * discovery. + * discovery. Discovery is not managed by the Activity, + * but is run as a system service, so an application should always call + * {@link BluetoothAdapter#cancelDiscovery()} even if it + * did not directly request a discovery, just to be sure. *

Device discovery will only find remote devices that are currently * discoverable (inquiry scan enabled). Many Bluetooth devices are * not discoverable by default, and need to be entered into a special mode. @@ -565,6 +569,13 @@ public final class BluetoothAdapter { /** * Cancel the current device discovery process. *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. + *

Because discovery is a heavyweight precedure for the Bluetooth + * adapter, this method should always be called before attempting to connect + * to a remote device with {@link + * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by + * the Activity, but is run as a system service, so an application should + * always call cancel discovery even if it did not directly request a + * discovery, just to be sure. * * @return true on success, false on error */ -- cgit v1.2.3 From cdd8b7ec707d0005c3176b4481cab730a92df236 Mon Sep 17 00:00:00 2001 From: Scott Main Date: Wed, 9 Dec 2009 16:07:39 -0800 Subject: docs: add the Bluetooth developer guide, and make some revisions to the BT javadocs --- .../java/android/bluetooth/BluetoothAdapter.java | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index bf561ef94e..8eda844380 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -370,9 +370,17 @@ public final class BluetoothAdapter { } /** - * Turn on the local Bluetooth adapter. + * Turn on the local Bluetooth adapter—do not use without explicit + * user action to turn on Bluetooth. *

This powers on the underlying Bluetooth hardware, and starts all * Bluetooth system services. + *

Bluetooth should never be enabled without + * direct user consent. If you want to turn on Bluetooth in order + * to create a wireless connection, you should use the {@link + * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests + * user permission to turn on Bluetooth. The {@link #enable()} method is + * provided only for applications that include a user interface for changing + * system settings, such as a "power manager" app.

*

This is an asynchronous call: it will return immediately, and * clients should listen for {@link #ACTION_STATE_CHANGED} * to be notified of subsequent adapter state changes. If this call returns @@ -382,7 +390,8 @@ public final class BluetoothAdapter { * #STATE_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. - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + *

Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission * * @return true to indicate adapter startup has begun, or false on * immediate error @@ -395,9 +404,14 @@ public final class BluetoothAdapter { } /** - * Turn off the local Bluetooth adapter. + * Turn off the local Bluetooth adapter—do not use without explicit + * user action to turn off Bluetooth. *

This gracefully shuts down all Bluetooth connections, stops Bluetooth * system services, and powers down the underlying Bluetooth hardware. + *

Bluetooth should never be disbled without + * direct user consent. The {@link #disable()} method is + * provided only for applications that include a user interface for changing + * system settings, such as a "power manager" app.

*

This is an asynchronous call: it will return immediately, and * clients should listen for {@link #ACTION_STATE_CHANGED} * to be notified of subsequent adapter state changes. If this call returns @@ -407,7 +421,8 @@ public final class BluetoothAdapter { * #STATE_ON}. If this call returns false then there was an * immediate problem that will prevent the adapter from being turned off - * such as the adapter already being turned off. - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + *

Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission * * @return true to indicate adapter shutdown has begun, or false on * immediate error -- cgit v1.2.3 From 9ad892c51e2e37a5506416bb45d43e191003b3fa Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Tue, 18 May 2010 14:36:48 -0700 Subject: Removing STOPSHIP logs. Bug: 2694602 Change-Id: Id56e1ddcf5ea76de32238cd6761f2caf053f1fa1 --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 42d87f4118..8eda844380 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -63,7 +63,7 @@ import java.util.UUID; */ public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; - private static final boolean DBG = true; //STOPSHIP: Remove excess logging + private static final boolean DBG = false; /** * Sentinel error value for this class. Guaranteed to not equal any other -- cgit v1.2.3 From fc0c182532491dff4a77fd3ead33e97cafbc3205 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Fri, 6 Aug 2010 19:03:13 -0700 Subject: Check whether Bluetooth is enabled before making any API calls. For example, Settings app makes calls to get Bonded Devices before Bluetooth is on. This leads to ANRs and will prevent autoconnection. Change-Id: I56748a9bd1d603b5782c17775c6b20b831bf6572 --- framework/java/android/bluetooth/BluetoothAdapter.java | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8eda844380..bb4774d567 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -474,6 +474,7 @@ public final class BluetoothAdapter { * @return true if the name was set, false otherwise */ public boolean setName(String name) { + if (getState() != STATE_ON) return false; try { return mService.setName(name); } catch (RemoteException e) {Log.e(TAG, "", e);} @@ -493,6 +494,7 @@ public final class BluetoothAdapter { * @return scan mode */ public int getScanMode() { + if (getState() != STATE_ON) return SCAN_MODE_NONE; try { return mService.getScanMode(); } catch (RemoteException e) {Log.e(TAG, "", e);} @@ -524,6 +526,7 @@ public final class BluetoothAdapter { * @hide */ public boolean setScanMode(int mode, int duration) { + if (getState() != STATE_ON) return false; try { return mService.setScanMode(mode, duration); } catch (RemoteException e) {Log.e(TAG, "", e);} @@ -532,11 +535,13 @@ public final class BluetoothAdapter { /** @hide */ public boolean setScanMode(int mode) { + if (getState() != STATE_ON) return false; return setScanMode(mode, 120); } /** @hide */ public int getDiscoverableTimeout() { + if (getState() != STATE_ON) return -1; try { return mService.getDiscoverableTimeout(); } catch (RemoteException e) {Log.e(TAG, "", e);} @@ -545,6 +550,7 @@ public final class BluetoothAdapter { /** @hide */ public void setDiscoverableTimeout(int timeout) { + if (getState() != STATE_ON) return; try { mService.setDiscoverableTimeout(timeout); } catch (RemoteException e) {Log.e(TAG, "", e);} @@ -577,6 +583,7 @@ public final class BluetoothAdapter { * @return true on success, false on error */ public boolean startDiscovery() { + if (getState() != STATE_ON) return false; try { return mService.startDiscovery(); } catch (RemoteException e) {Log.e(TAG, "", e);} @@ -597,6 +604,7 @@ public final class BluetoothAdapter { * @return true on success, false on error */ public boolean cancelDiscovery() { + if (getState() != STATE_ON) return false; try { mService.cancelDiscovery(); } catch (RemoteException e) {Log.e(TAG, "", e);} @@ -619,6 +627,7 @@ public final class BluetoothAdapter { * @return true if discovering */ public boolean isDiscovering() { + if (getState() != STATE_ON) return false; try { return mService.isDiscovering(); } catch (RemoteException e) {Log.e(TAG, "", e);} @@ -633,6 +642,7 @@ public final class BluetoothAdapter { * @return unmodifiable set of {@link BluetoothDevice}, or null on error */ public Set getBondedDevices() { + if (getState() != STATE_ON) return null; try { return toDeviceSet(mService.listBonds()); } catch (RemoteException e) {Log.e(TAG, "", e);} -- cgit v1.2.3 From 1c8dba03ace069cf5fa83fd8cdc29988a777b07f Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Mon, 9 Aug 2010 16:54:03 -0700 Subject: Update javadoc for the API and change return of getBondedDevices(). getBondedDevices() *might* work if called before the Bluetooth State intent is broadcasted. However, this can cause ANRs and problems. This API was updated to return null, if called before the intent is received. However, this might cause existing apps to crash. Return an empty set instead. Change-Id: Ibc484d3394aa0bbebd651221efde6a7015ce7110 --- .../java/android/bluetooth/BluetoothAdapter.java | 32 +++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index bb4774d567..03bcadc69b 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -468,6 +468,10 @@ public final class BluetoothAdapter { *

Valid Bluetooth names are a maximum of 248 UTF-8 characters, however * many remote devices can only display the first 40 characters, and some * may be limited to just 20. + *

If Bluetooth state is not {@link #STATE_ON}, this API + * will return false. After turning on Bluetooth, + * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} + * to get the updated value. *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * * @param name a valid Bluetooth name @@ -489,6 +493,10 @@ public final class BluetoothAdapter { * {@link #SCAN_MODE_NONE}, * {@link #SCAN_MODE_CONNECTABLE}, * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. + *

If Bluetooth state is not {@link #STATE_ON}, this API + * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth, + * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} + * to get the updated value. *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @return scan mode @@ -513,6 +521,10 @@ public final class BluetoothAdapter { * {@link #SCAN_MODE_NONE}, * {@link #SCAN_MODE_CONNECTABLE}, * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. + *

If Bluetooth state is not {@link #STATE_ON}, this API + * will return false. After turning on Bluetooth, + * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} + * to get the updated value. *

Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} *

Applications cannot set the scan mode. They should use * startActivityForResult( @@ -578,6 +590,10 @@ public final class BluetoothAdapter { *

Device discovery will only find remote devices that are currently * discoverable (inquiry scan enabled). Many Bluetooth devices are * not discoverable by default, and need to be entered into a special mode. + *

If Bluetooth state is not {@link #STATE_ON}, this API + * will return false. After turning on Bluetooth, + * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} + * to get the updated value. *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. * * @return true on success, false on error @@ -600,6 +616,10 @@ public final class BluetoothAdapter { * the Activity, but is run as a system service, so an application should * always call cancel discovery even if it did not directly request a * discovery, just to be sure. + *

If Bluetooth state is not {@link #STATE_ON}, this API + * will return false. After turning on Bluetooth, + * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} + * to get the updated value. * * @return true on success, false on error */ @@ -622,6 +642,10 @@ public final class BluetoothAdapter { *

Applications can also register for {@link #ACTION_DISCOVERY_STARTED} * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery * starts or completes. + *

If Bluetooth state is not {@link #STATE_ON}, this API + * will return false. After turning on Bluetooth, + * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} + * to get the updated value. *

Requires {@link android.Manifest.permission#BLUETOOTH}. * * @return true if discovering @@ -637,12 +661,18 @@ public final class BluetoothAdapter { /** * Return the set of {@link BluetoothDevice} objects that are bonded * (paired) to the local adapter. + *

If Bluetooth state is not {@link #STATE_ON}, this API + * will return an empty set. After turning on Bluetooth, + * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} + * to get the updated value. *

Requires {@link android.Manifest.permission#BLUETOOTH}. * * @return unmodifiable set of {@link BluetoothDevice}, or null on error */ public Set getBondedDevices() { - if (getState() != STATE_ON) return null; + if (getState() != STATE_ON) { + return toDeviceSet(new String[0]); + } try { return toDeviceSet(mService.listBonds()); } catch (RemoteException e) {Log.e(TAG, "", e);} -- cgit v1.2.3 From 76965ca62f7b54ca277f06a597373439cc87c311 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Thu, 9 Sep 2010 15:37:57 -0700 Subject: Out Of Band API for Secure Simple Pairing. Change-Id: I54ded27ab85d46eef3d2cca84f2394b1ffe88ced --- .../java/android/bluetooth/BluetoothAdapter.java | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 03bcadc69b..16a8c571f4 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -26,8 +26,10 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; +import android.util.Pair; import java.io.IOException; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; @@ -863,6 +865,37 @@ public final class BluetoothAdapter { return socket; } + /** + * Read the local Out of Band Pairing Data + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * + * @return Pair of Hash and Randomizer + * + * @hide + */ + public Pair readOutOfBandData() { + if (getState() != STATE_ON) return null; + try { + byte[] hash = new byte[16]; + byte[] randomizer = new byte[16]; + + byte[] ret = mService.readOutOfBandData(); + + if (ret == null || ret.length != 32) return null; + + hash = Arrays.copyOfRange(ret, 0, 16); + randomizer = Arrays.copyOfRange(ret, 16, 32); + + if (DBG) { + Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) + + ":" + Arrays.toString(randomizer)); + } + return new Pair(hash, randomizer); + + } catch (RemoteException e) {Log.e(TAG, "", e);} + return null; + } + private Set toDeviceSet(String[] addresses) { Set devices = new HashSet(addresses.length); for (int i = 0; i < addresses.length; i++) { -- cgit v1.2.3 From c7e8488fc4a1b3f5bcfbfba153be079fded7cdaa Mon Sep 17 00:00:00 2001 From: Jake Hamby Date: Thu, 16 Sep 2010 18:12:51 -0700 Subject: Fix Bluetooth Javadoc to clarify the maximum device name length. The maximum length of a Bluetooth device name is 248 bytes using UTF-8 encoding. Updated the Javadoc to clarify that the length is limited by the number of UTF-8 bytes and not the number of characters. Change-Id: I135671f5ee6c5eb6372f3fbbc5fccb02de65e6c4 --- framework/java/android/bluetooth/BluetoothAdapter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 16a8c571f4..33fd39513f 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -465,11 +465,11 @@ public final class BluetoothAdapter { } /** - * Set the friendly Bluetooth name of the local Bluetoth adapter. + * Set the friendly Bluetooth name of the local Bluetooth adapter. *

This name is visible to remote Bluetooth devices. - *

Valid Bluetooth names are a maximum of 248 UTF-8 characters, however - * many remote devices can only display the first 40 characters, and some - * may be limited to just 20. + *

Valid Bluetooth names are a maximum of 248 bytes using UTF-8 + * encoding, although many remote devices can only display the first + * 40 characters, and some may be limited to just 20. *

If Bluetooth state is not {@link #STATE_ON}, this API * will return false. After turning on Bluetooth, * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} @@ -488,7 +488,7 @@ public final class BluetoothAdapter { } /** - * Get the current Bluetooth scan mode of the local Bluetooth adaper. + * Get the current Bluetooth scan mode of the local Bluetooth adapter. *

The Bluetooth scan mode determines if the local adapter is * connectable and/or discoverable from remote Bluetooth devices. *

Possible values are: @@ -611,7 +611,7 @@ public final class BluetoothAdapter { /** * Cancel the current device discovery process. *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. - *

Because discovery is a heavyweight precedure for the Bluetooth + *

Because discovery is a heavyweight procedure for the Bluetooth * adapter, this method should always be called before attempting to connect * to a remote device with {@link * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by -- cgit v1.2.3 From 2af0776a750217842622b1f54b4964b5e9ec371c Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Tue, 24 Aug 2010 17:36:13 -0700 Subject: New public APIs for BluetoothA2dp and BluetoothHeadset profiles. Change-Id: I1cc4b109542dfd62473cb95797c8c3d0d15725f4 --- .../java/android/bluetooth/BluetoothAdapter.java | 104 +++++++++++++++++++++ 1 file changed, 104 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 33fd39513f..21a4bd64b4 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -18,6 +18,7 @@ package android.bluetooth; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -279,6 +280,61 @@ public final class BluetoothAdapter { */ public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME"; + /** + * Intent used to broadcast the change in connection state of the local + * Bluetooth adapter to a profile of the remote device. When the adapter is + * not connected to any profiles of any remote devices and it attempts a + * connection to a profile this intent will sent. Once connected, this intent + * will not be sent for any more connection attempts to any profiles of any + * remote device. When the adapter disconnects from the last profile its + * connected to of any remote device, this intent will be sent. + * + *

This intent is useful for applications that are only concerned about + * whether the local adapter is connected to any profile of any device and + * are not really concerned about which profile. For example, an application + * which displays an icon to display whether Bluetooth is connected or not + * can use this intent. + * + *

This intent will have 3 extras: + * {@link #EXTRA_STATE} - The current state. + * {@link #EXTRA_PREVIOUS_STATE}- The previous. + * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. + * + * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of + * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, + * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + * + *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_CONNECTION_STATE_CHANGED = + "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"; + + /** + * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} + * + * This extra represents the current connection state. + */ + public static final String EXTRA_CONNECTION_STATE = + "android.bluetooth.adapter.extra.CONNECTION_STATE"; + + /** + * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} + * + * This extra represents the previous connection state. + */ + public static final String EXTRA_PREVIOUS_CONNECTION_STATE = + "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE"; + + /** The profile is in disconnected state */ + public static final int STATE_DISCONNECTED = 0; + /** The profile is in connecting state */ + public static final int STATE_CONNECTING = 1; + /** The profile is in connected state */ + public static final int STATE_CONNECTED = 2; + /** The profile is in disconnecting state */ + public static final int STATE_DISCONNECTING = 3; + /** @hide */ public static final String BLUETOOTH_SERVICE = "bluetooth"; @@ -896,6 +952,54 @@ public final class BluetoothAdapter { return null; } + /* + * Get the profile proxy object associated with the profile. + * + *

Profile can be one of {@link BluetoothProfile.HEADSET} or + * {@link BluetoothProfile.A2DP}. Clients must implements + * {@link BluetoothProfile.ServiceListener} to get notified of + * the connection status and to get the proxy object. + * + * @param context Context of the application + * @param listener The service Listener for connection callbacks. + * @param profile + * @return true on success, false on error + */ + public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, + int profile) { + if (context == null || listener == null) return false; + + if (profile == BluetoothProfile.HEADSET) { + BluetoothHeadset headset = new BluetoothHeadset(context, listener); + return true; + } else if (profile == BluetoothProfile.A2DP) { + BluetoothA2dp a2dp = new BluetoothA2dp(context, listener); + return true; + } else { + return false; + } + } + + /** + * Close the connection of the profile proxy to the Service. + * + *

Clients should call this when they are no longer using + * the proxy obtained from {@link #getProfileProxy}. + * Profile can be one of {@link BluetoothProfile#HEADSET} or + * {@link BluetoothProfile#A2DP} + * + * @param profile + * @param proxy Profile proxy object + */ + public void closeProfileProxy(int profile, BluetoothProfile proxy) { + if (profile == BluetoothProfile.HEADSET) { + BluetoothHeadset headset = (BluetoothHeadset)proxy; + if (headset != null) { + headset.close(); + } + } + } + private Set toDeviceSet(String[] addresses) { Set devices = new HashSet(addresses.length); for (int i = 0; i < addresses.length; i++) { -- cgit v1.2.3 From 04c7138c7c1f36d54fbe33c40644e197248166b9 Mon Sep 17 00:00:00 2001 From: Jake Hamby Date: Tue, 21 Sep 2010 13:39:53 -0700 Subject: Typo fixes in comments and minor code cleanups. * Fix some typos in Javadoc and log messages. * Remove redundant initializer in BluetoothAdapter.readOutOfBandData() * Use canonical "UTF-8" charset name instead of "UTF8" in BluetoothDevice.convertPinToBytes() Change-Id: I58cd5dc48a7ad0053d204c5f590b4b3d438d8672 --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 33fd39513f..3040319beb 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -285,7 +285,7 @@ public final class BluetoothAdapter { private static final int ADDRESS_LENGTH = 17; /** - * Lazyily initialized singleton. Guaranteed final after first object + * Lazily initialized singleton. Guaranteed final after first object * constructed. */ private static BluetoothAdapter sAdapter; @@ -410,7 +410,7 @@ public final class BluetoothAdapter { * user action to turn off Bluetooth. *

This gracefully shuts down all Bluetooth connections, stops Bluetooth * system services, and powers down the underlying Bluetooth hardware. - *

Bluetooth should never be disbled without + *

Bluetooth should never be disabled without * direct user consent. The {@link #disable()} method is * provided only for applications that include a user interface for changing * system settings, such as a "power manager" app.

@@ -876,8 +876,8 @@ public final class BluetoothAdapter { public Pair readOutOfBandData() { if (getState() != STATE_ON) return null; try { - byte[] hash = new byte[16]; - byte[] randomizer = new byte[16]; + byte[] hash; + byte[] randomizer; byte[] ret = mService.readOutOfBandData(); -- cgit v1.2.3 From 8e8b26d45e8664707246f5f8f9e73daebe20379a Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Tue, 26 Oct 2010 16:02:26 -0700 Subject: Add an API call to get the ConnectionState of the Bluetooth Adapter. Change-Id: Icd87d7720189034946aaa98e1a6c5d03ef4219e5 --- .../java/android/bluetooth/BluetoothAdapter.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index c66b2dec9e..556fb10fb9 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -737,6 +737,27 @@ public final class BluetoothAdapter { return null; } + /** + * Get the current connection state of the local Bluetooth adapter. + * This can be used to check whether the local Bluetooth adapter is connected + * to any profile of any other remote Bluetooth Device. + * + *

Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED} + * intent to get the connection state of the adapter. + * + * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED}, + * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED} + * + * @hide + */ + public int getConnectionState() { + if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED; + try { + return mService.getAdapterConnectionState(); + } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);} + return BluetoothAdapter.STATE_DISCONNECTED; + } + /** * Picks RFCOMM channels until none are left. * Avoids reserved channels. @@ -879,6 +900,7 @@ public final class BluetoothAdapter { return socket; } + /** * Construct an unencrypted, unauthenticated, RFCOMM server socket. * Call #accept to retrieve connections to this socket. -- cgit v1.2.3 From a2dbad40eee3c5561fd1840a6ca9a5a21521c486 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Tue, 23 Nov 2010 20:03:10 -0800 Subject: Update BT code for voice capability cases. 1. Disable PBAP and Headset / Handsfree records. 2. Add API to query for local adapter UUIDs. Change-Id: Ic84ba6a49738adc89a8695d3a4890f08562e0621 --- framework/java/android/bluetooth/BluetoothAdapter.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 556fb10fb9..32df4e8cbb 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -520,6 +520,21 @@ public final class BluetoothAdapter { return null; } + /** + * Get the UUIDs supported by the local Bluetooth adapter. + * + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * + * @return the UUIDs supported by the local Bluetooth Adapter. + * @hide + */ + public ParcelUuid[] getUuids() { + try { + return mService.getUuids(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return null; + } + /** * Set the friendly Bluetooth name of the local Bluetooth adapter. *

This name is visible to remote Bluetooth devices. -- cgit v1.2.3 From 203b5816c481025bb1252c791c69677dad57546f Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Thu, 23 Dec 2010 12:57:02 -0800 Subject: Expose insecure rfcomm Bluetooth API. This complements the secure rfcomm API. The link key is unauthenticated and is subject to MITM attacks. The link key may be encrypted depending on the type of Bluetooth device. This helps apps which don't need the extra security or have their own security layer built on top of the rfcomm link. Change-Id: I71b2fa8de469ef98faa204b4dafac18a8e21d0d9 --- .../java/android/bluetooth/BluetoothAdapter.java | 38 +++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 32df4e8cbb..b2185adc86 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -868,6 +868,42 @@ public final class BluetoothAdapter { */ public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) throws IOException { + return createNewRfcommSocketAndRecord(name, uuid, true, true); + } + + /** + * Create a listening, insecure RFCOMM Bluetooth socket with Service Record. + *

The link key will be unauthenticated i.e the communication is + * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices, + * the link key will be encrypted, as encryption is mandartory. + * For legacy devices (pre Bluetooth 2.1 devices) the link key will not + * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an + * encrypted and authenticated communication channel is desired. + *

Use {@link BluetoothServerSocket#accept} to retrieve incoming + * connections from a listening {@link BluetoothServerSocket}. + *

The system will assign an unused RFCOMM channel to listen on. + *

The system will also register a Service Discovery + * Protocol (SDP) record with the local SDP server containing the specified + * UUID, service name, and auto-assigned channel. Remote Bluetooth devices + * can use the same UUID to query our SDP server and discover which channel + * to connect to. This SDP record will be removed when this socket is + * closed, or if this application closes unexpectedly. + *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to + * connect to this socket from another device using the same {@link UUID}. + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * @param name service name for SDP record + * @param uuid uuid for SDP record + * @return a listening RFCOMM BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or + * insufficient permissions, or channel in use. + */ + public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid) + throws IOException { + return createNewRfcommSocketAndRecord(name, uuid, false, false); + } + + private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, + boolean auth, boolean encrypt) throws IOException { RfcommChannelPicker picker = new RfcommChannelPicker(uuid); BluetoothServerSocket socket; @@ -881,7 +917,7 @@ public final class BluetoothAdapter { } socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, true, true, channel); + BluetoothSocket.TYPE_RFCOMM, auth, encrypt, channel); errno = socket.mSocket.bindListen(); if (errno == 0) { if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel); -- cgit v1.2.3 From cee8d301f0b708c2922caaabb1b8bbf9730a6fdb Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Thu, 13 Jan 2011 22:50:51 -0800 Subject: Do Not Merge: Expose insecure rfcomm Bluetooth API. This complements the secure rfcomm API. The link key is unauthenticated and is subject to MITM attacks. The link key may be encrypted depending on the type of Bluetooth device. This helps apps which don't need the extra security or have their own security layer built on top of the rfcomm link. Bug: 3352266 Change-Id: I633fd0372e5e23288d6fec950dd1abc2896031f1 --- .../java/android/bluetooth/BluetoothAdapter.java | 56 +++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3040319beb..a7175e3036 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -729,6 +729,15 @@ public final class BluetoothAdapter { * Create a listening, secure RFCOMM Bluetooth socket. *

A remote device connecting to this socket will be authenticated and * communication on this socket will be encrypted. + *

Use this socket only if an authenticated socket link is possible. + * Authentication refers to the authentication of the link key to + * prevent man-in-the-middle type of attacks. + * For example, for Bluetooth 2.1 devices, if any of the devices does not + * have an input and output capability or just has the ability to + * display a numeric key, a secure socket connection is not possible. + * In such a case, use {#link listenUsingInsecureRfcommOn}. + * For more details, refer to the Security Model section 5.2 (vol 3) of + * Bluetooth Core Specification version 2.1 + EDR. *

Use {@link BluetoothServerSocket#accept} to retrieve incoming * connections from a listening {@link BluetoothServerSocket}. *

Valid RFCOMM channels are in range 1 to 30. @@ -756,6 +765,15 @@ public final class BluetoothAdapter { * Create a listening, secure RFCOMM Bluetooth socket with Service Record. *

A remote device connecting to this socket will be authenticated and * communication on this socket will be encrypted. + *

Use this socket only if an authenticated socket link is possible. + * Authentication refers to the authentication of the link key to + * prevent man-in-the-middle type of attacks. + * For example, for Bluetooth 2.1 devices, if any of the devices does not + * have an input and output capability or just has the ability to + * display a numeric key, a secure socket connection is not possible. + * In such a case, use {#link listenUsingInsecureRfcommWithServiceRecord}. + * For more details, refer to the Security Model section 5.2 (vol 3) of + * Bluetooth Core Specification version 2.1 + EDR. *

Use {@link BluetoothServerSocket#accept} to retrieve incoming * connections from a listening {@link BluetoothServerSocket}. *

The system will assign an unused RFCOMM channel to listen on. @@ -776,6 +794,42 @@ public final class BluetoothAdapter { */ public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) throws IOException { + return createNewRfcommSocketAndRecord(name, uuid, true, true); + } + + /** + * Create a listening, insecure RFCOMM Bluetooth socket with Service Record. + *

The link key will be unauthenticated i.e the communication is + * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices, + * the link key will be encrypted, as encryption is mandartory. + * For legacy devices (pre Bluetooth 2.1 devices) the link key will not + * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an + * encrypted and authenticated communication channel is desired. + *

Use {@link BluetoothServerSocket#accept} to retrieve incoming + * connections from a listening {@link BluetoothServerSocket}. + *

The system will assign an unused RFCOMM channel to listen on. + *

The system will also register a Service Discovery + * Protocol (SDP) record with the local SDP server containing the specified + * UUID, service name, and auto-assigned channel. Remote Bluetooth devices + * can use the same UUID to query our SDP server and discover which channel + * to connect to. This SDP record will be removed when this socket is + * closed, or if this application closes unexpectedly. + *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to + * connect to this socket from another device using the same {@link UUID}. + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * @param name service name for SDP record + * @param uuid uuid for SDP record + * @return a listening RFCOMM BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or + * insufficient permissions, or channel in use. + */ + public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid) + throws IOException { + return createNewRfcommSocketAndRecord(name, uuid, false, false); + } + + private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, + boolean auth, boolean encrypt) throws IOException { RfcommChannelPicker picker = new RfcommChannelPicker(uuid); BluetoothServerSocket socket; @@ -789,7 +843,7 @@ public final class BluetoothAdapter { } socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, true, true, channel); + BluetoothSocket.TYPE_RFCOMM, auth, encrypt, channel); errno = socket.mSocket.bindListen(); if (errno == 0) { if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel); -- cgit v1.2.3 From 4883a5778fa6bb2ad3d4a0dad25efbc7edf46a7b Mon Sep 17 00:00:00 2001 From: Scott Main Date: Wed, 19 Jan 2011 21:13:18 -0800 Subject: docs: small javadoc, but also make the existing getProfileProxy docs visible... had wrong comment tag Change-Id: Ia4b2178057c0263ec8f835342815082de87b3af1 --- framework/java/android/bluetooth/BluetoothAdapter.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b2185adc86..fb3744d530 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1025,17 +1025,18 @@ public final class BluetoothAdapter { return null; } - /* + /** * Get the profile proxy object associated with the profile. * - *

Profile can be one of {@link BluetoothProfile.HEADSET} or - * {@link BluetoothProfile.A2DP}. Clients must implements + *

Profile can be one of {@link BluetoothProfile#HEADSET} or + * {@link BluetoothProfile#A2DP}. Clients must implements * {@link BluetoothProfile.ServiceListener} to get notified of * the connection status and to get the proxy object. * * @param context Context of the application * @param listener The service Listener for connection callbacks. - * @param profile + * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEADSET} + * or {@link BluetoothProfile#A2DP}. * @return true on success, false on error */ public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, -- cgit v1.2.3 From f9660ec83110660a3610a8b5cd2bf52d06dff548 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Tue, 1 Feb 2011 16:47:11 -0800 Subject: Fix BluetoothAdapter Connection change intent doc. Bug: 3414206 Change-Id: Icf87e28e11b0b5072fe546225bbfb1dc68487ef0 --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index fb3744d530..4656e15391 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -296,12 +296,12 @@ public final class BluetoothAdapter { * can use this intent. * *

This intent will have 3 extras: - * {@link #EXTRA_STATE} - The current state. - * {@link #EXTRA_PREVIOUS_STATE}- The previous. + * {@link #EXTRA_CONNECTION_STATE} - The current connection state. + * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state. * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. * - * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of - * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, + * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE} + * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. * *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. -- cgit v1.2.3 From ad5d9c0ffd34c96faffdcee714e20ae7bd702ada Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Fri, 18 Feb 2011 14:52:32 -0800 Subject: Make BluetoothInputDevice inherit from BluetoothProfile. This makes it in sync with BluetoothHeadset and BluetoothA2dp profiles. Change-Id: I3ddb1d18b04aacb173b7bc376bca21c277a6afe4 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 4656e15391..1f4fe801e6 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1049,6 +1049,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.A2DP) { BluetoothA2dp a2dp = new BluetoothA2dp(context, listener); return true; + } else if (profile == BluetoothProfile.INPUT_DEVICE) { + BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener); + return true; } else { return false; } -- cgit v1.2.3 From 97f8ec41a556abc487ee412344e4f6c4c52613cb Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Wed, 23 Feb 2011 10:22:15 -0800 Subject: Make BluetoothPan inherit from BluetoothProfile. Change-Id: Ibd3e24e391be93ebe2cf975bd075efb68e10c1ff --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 1f4fe801e6..e1c904420a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1052,6 +1052,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.INPUT_DEVICE) { BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener); return true; + } else if (profile == BluetoothProfile.PAN) { + BluetoothPan pan = new BluetoothPan(context, listener); + return true; } else { return false; } -- cgit v1.2.3 From efd744ddb96769e41092d56f0cebf809e80f2a8e Mon Sep 17 00:00:00 2001 From: Mathias Jeppsson Date: Mon, 21 Mar 2011 15:06:52 +0100 Subject: Require bonding and encryption for PBAP server The Phonebook Access Profile specification requires bonding and encryption. For devices not supporting SSP (Secure Simple Pairing), InsecureRfcomm will require neither. Adding EncryptedRfcomm to force bonding and encryption but not requiring authenticated link key. Change-Id: If47cca9c5ffd89358bcd61d64f7785d17e0ca7cc --- .../java/android/bluetooth/BluetoothAdapter.java | 66 +++++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index a7175e3036..66a74503c9 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -799,10 +799,10 @@ public final class BluetoothAdapter { /** * Create a listening, insecure RFCOMM Bluetooth socket with Service Record. - *

The link key will be unauthenticated i.e the communication is + *

The link key is not required to be authenticated, i.e the communication may be * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices, - * the link key will be encrypted, as encryption is mandartory. - * For legacy devices (pre Bluetooth 2.1 devices) the link key will not + * the link will be encrypted, as encryption is mandartory. + * For legacy devices (pre Bluetooth 2.1 devices) the link will not * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an * encrypted and authenticated communication channel is desired. *

Use {@link BluetoothServerSocket#accept} to retrieve incoming @@ -828,6 +828,44 @@ public final class BluetoothAdapter { return createNewRfcommSocketAndRecord(name, uuid, false, false); } + /** + * Create a listening, encrypted, + * RFCOMM Bluetooth socket with Service Record. + *

The link will be encrypted, but the link key is not required to be authenticated + * i.e the communication is vulnerable to Man In the Middle attacks. Use + * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key. + *

Use this socket if authentication of link key is not possible. + * For example, for Bluetooth 2.1 devices, if any of the devices does not have + * an input and output capability or just has the ability to display a numeric key, + * a secure socket connection is not possible and this socket can be used. + * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required. + * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory. + * For more details, refer to the Security Model section 5.2 (vol 3) of + * Bluetooth Core Specification version 2.1 + EDR. + *

Use {@link BluetoothServerSocket#accept} to retrieve incoming + * connections from a listening {@link BluetoothServerSocket}. + *

The system will assign an unused RFCOMM channel to listen on. + *

The system will also register a Service Discovery + * Protocol (SDP) record with the local SDP server containing the specified + * UUID, service name, and auto-assigned channel. Remote Bluetooth devices + * can use the same UUID to query our SDP server and discover which channel + * to connect to. This SDP record will be removed when this socket is + * closed, or if this application closes unexpectedly. + *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to + * connect to this socket from another device using the same {@link UUID}. + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * @param name service name for SDP record + * @param uuid uuid for SDP record + * @return a listening RFCOMM BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or + * insufficient permissions, or channel in use. + * @hide + */ + public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord( + String name, UUID uuid) throws IOException { + return createNewRfcommSocketAndRecord(name, uuid, false, true); + } + private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt) throws IOException { RfcommChannelPicker picker = new RfcommChannelPicker(uuid); @@ -898,6 +936,28 @@ public final class BluetoothAdapter { return socket; } + /** + * Construct an encrypted, RFCOMM server socket. + * Call #accept to retrieve connections to this socket. + * @return An RFCOMM BluetoothServerSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + * @hide + */ + public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) + throws IOException { + BluetoothServerSocket socket = new BluetoothServerSocket( + BluetoothSocket.TYPE_RFCOMM, false, true, port); + int errno = socket.mSocket.bindListen(); + if (errno != 0) { + try { + socket.close(); + } catch (IOException e) {} + socket.mSocket.throwErrnoNative(errno); + } + return socket; + } + /** * Construct a SCO server socket. * Call #accept to retrieve connections to this socket. -- cgit v1.2.3 From ebb0628f431e330a85d4a194306de5418a939fb1 Mon Sep 17 00:00:00 2001 From: Albert Mojir Date: Mon, 21 Mar 2011 14:59:10 +0100 Subject: Bluetooth: correcting return value from cancelDiscovery BluetoothAdapter.cancelDiscovery was previously always returning false. Change-Id: Ic1fd134d4b710438d95c5b8ca009104529dd1bf5 --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e1c904420a..26707c96a2 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -699,7 +699,7 @@ public final class BluetoothAdapter { public boolean cancelDiscovery() { if (getState() != STATE_ON) return false; try { - mService.cancelDiscovery(); + return mService.cancelDiscovery(); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } -- cgit v1.2.3 From bf981ca2e9d1d75ef726fa6d17a0b5450cf17cdf Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Fri, 1 Apr 2011 16:33:09 -0700 Subject: Implement APIs for Bluetooth Health profile. This first patch implements all the APIs. The APIs wil be made public soon. The data specification API will be submited in another patchset. Change-Id: I2462683b7e07380e2c42474b0036b34d03b4bed1 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index a8c31f92e0..b993bd8e95 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1115,6 +1115,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.PAN) { BluetoothPan pan = new BluetoothPan(context, listener); return true; + } else if (profile == BluetoothProfile.HEALTH) { + BluetoothHealth health = new BluetoothHealth(context, listener); + return true; } else { return false; } -- cgit v1.2.3 From cb4d968b2d4464d2dba5da8050a3d9b0a3a50f91 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Thu, 21 Jul 2011 18:13:38 -0700 Subject: Add ability to turn BT on / off on a per application basis. This changes adds an API for system applications to enable bluetooth without all the side effects like auto connection to headsets etc. Also some tweaks to the adapter state machine Change-Id: Ib9f22d548a26d72334b300101c8eb0d80f08a4bb --- .../java/android/bluetooth/BluetoothAdapter.java | 63 ++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b993bd8e95..ca6f085dfb 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1143,6 +1143,69 @@ public final class BluetoothAdapter { } } + /** + * Enable control of the Bluetooth Adapter for a single application. + * + *

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. + * + *

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. + * + *

This API is only meant to be used by internal applications. Third + * party applications but use {@link #enable} and {@link #disable} APIs. + * + *

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 toDeviceSet(String[] addresses) { Set devices = new HashSet(addresses.length); for (int i = 0; i < addresses.length; i++) { -- cgit v1.2.3 From a13f8e871192642e66c38b0bc8166aa2629476f6 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Wed, 3 Aug 2011 14:17:22 -0700 Subject: Enforce permission for changeApplicationState function. The ADMIN permission is for use cases where we want to manage BT connection at a deeper level. So just the Bluetooth permission is good enough here. Change-Id: Iddd038fe9f9a26f155b4edc9484ba1fe27b178ba --- framework/java/android/bluetooth/BluetoothAdapter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ca6f085dfb..28bc424d93 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1163,7 +1163,10 @@ public final class BluetoothAdapter { *

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. + * reason. If Bluetooth is already on and if this function is called to turn + * it on, the api will return true and a callback will be called. + * + *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @param on True for on, false for off. * @param callback The callback to notify changes to the state. -- cgit v1.2.3 From 5317842b3d84997bc5327a404cea1d6bcd9d515d Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Fri, 19 Aug 2011 10:26:32 -0700 Subject: Add Api to get profile connection state. This gets the current connection state of the profile with respect to the local Bluetooth adapter. Change-Id: I7cff6c9201d29a8b45413cff7384b7483f21bd5c --- .../java/android/bluetooth/BluetoothAdapter.java | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 28bc424d93..264db1917d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -773,6 +773,31 @@ public final class BluetoothAdapter { return BluetoothAdapter.STATE_DISCONNECTED; } + /** + * Get the current connection state of a profile. + * This function can be used to check whether the local Bluetooth adapter + * is connected to any remote device for a specific profile. + * Profile can be one of {@link BluetoothProfile.HEADSET}, + * {@link BluetoothProfile.A2DP}. + * + *

Requires {@link android.Manifest.permission#BLUETOOTH}. + * + *

Return value can be one of + * {@link * BluetoothProfile.STATE_DISCONNECTED}, + * {@link * BluetoothProfile.STATE_CONNECTING}, + * {@link * BluetoothProfile.STATE_CONNECTED}, + * {@link * BluetoothProfile.STATE_DISCONNECTING} + * @hide + */ + public int getProfileConnectionState(int profile) { + if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED; + try { + return mService.getProfileConnectionState(profile); + } catch (RemoteException e) {Log.e(TAG, "getProfileConnectionState:", e);} + return BluetoothProfile.STATE_DISCONNECTED; + } + + /** /** * Picks RFCOMM channels until none are left. * Avoids reserved channels. -- cgit v1.2.3 From c875f3a646d871711988575642b38a17bf79f0f8 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Tue, 23 Aug 2011 12:21:55 -0700 Subject: Make profile connection state API public. Change-Id: I1f2810d4e820142435f7bbda051c98ec3e3cf3eb --- framework/java/android/bluetooth/BluetoothAdapter.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 264db1917d..223692859d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -777,23 +777,24 @@ public final class BluetoothAdapter { * Get the current connection state of a profile. * This function can be used to check whether the local Bluetooth adapter * is connected to any remote device for a specific profile. - * Profile can be one of {@link BluetoothProfile.HEADSET}, - * {@link BluetoothProfile.A2DP}. + * Profile can be one of {@link BluetoothProfile#HEADSET}, + * {@link BluetoothProfile#A2DP}. * *

Requires {@link android.Manifest.permission#BLUETOOTH}. * *

Return value can be one of - * {@link * BluetoothProfile.STATE_DISCONNECTED}, - * {@link * BluetoothProfile.STATE_CONNECTING}, - * {@link * BluetoothProfile.STATE_CONNECTED}, - * {@link * BluetoothProfile.STATE_DISCONNECTING} - * @hide + * {@link BluetoothProfile#STATE_DISCONNECTED}, + * {@link BluetoothProfile#STATE_CONNECTING}, + * {@link BluetoothProfile#STATE_CONNECTED}, + * {@link BluetoothProfile#STATE_DISCONNECTING} */ public int getProfileConnectionState(int profile) { if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED; try { return mService.getProfileConnectionState(profile); - } catch (RemoteException e) {Log.e(TAG, "getProfileConnectionState:", e);} + } catch (RemoteException e) { + Log.e(TAG, "getProfileConnectionState:", e); + } return BluetoothProfile.STATE_DISCONNECTED; } -- cgit v1.2.3 From 6e1b765e5b8cc70bacbaf04862d00cf8cc8c4a99 Mon Sep 17 00:00:00 2001 From: Matthew Xie Date: Thu, 25 Aug 2011 16:45:58 -0700 Subject: Move Bluetooth remove service record handler to the app main thread Move Bluetooth remove service record handler to the app main thread. This removes the dependency of caller thread that constructs the BluetoothAdapter singleton instance. The caller thread could stop while BluetoothAdapter singleton exists but lose the handler context. Make the BluetoothService.removeServiceRecord return quickly without blocking on native call. bug 4999443 Change-Id: I302534baa381f4aca8192e1e4a9ea21793b07ba6 --- .../java/android/bluetooth/BluetoothAdapter.java | 31 +++++++++++++--------- 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 223692859d..254c98ff8c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -22,6 +22,7 @@ import android.content.Context; import android.os.Binder; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.ParcelUuid; import android.os.RemoteException; @@ -348,6 +349,8 @@ public final class BluetoothAdapter { private final IBluetooth mService; + private Handler mServiceRecordHandler; + /** * Get a handle to the default local Bluetooth adapter. *

Currently Android only supports one Bluetooth adapter, but the API @@ -376,6 +379,7 @@ public final class BluetoothAdapter { throw new IllegalArgumentException("service is null"); } mService = service; + mServiceRecordHandler = null; } /** @@ -1011,7 +1015,21 @@ public final class BluetoothAdapter { } catch (IOException e) {} throw new IOException("Not able to register SDP record for " + name); } - socket.setCloseHandler(mHandler, handle); + + if (mServiceRecordHandler == null) { + mServiceRecordHandler = new Handler(Looper.getMainLooper()) { + public void handleMessage(Message msg) { + /* handle socket closing */ + int handle = msg.what; + try { + if (DBG) Log.d(TAG, "Removing service record " + + Integer.toHexString(handle)); + mService.removeServiceRecord(handle); + } catch (RemoteException e) {Log.e(TAG, "", e);} + } + }; + } + socket.setCloseHandler(mServiceRecordHandler, handle); return socket; } @@ -1243,17 +1261,6 @@ public final class BluetoothAdapter { return Collections.unmodifiableSet(devices); } - private Handler mHandler = new Handler() { - public void handleMessage(Message msg) { - /* handle socket closing */ - int handle = msg.what; - try { - if (DBG) Log.d(TAG, "Removing service record " + Integer.toHexString(handle)); - mService.removeServiceRecord(handle); - } catch (RemoteException e) {Log.e(TAG, "", e);} - } - }; - /** * Validate a Bluetooth address, such as "00:43:A8:23:10:F0" *

Alphabetic characters must be uppercase to be valid. -- cgit v1.2.3 From 3c0c5bee534ff1aa5dbf50385eacc3b9a8bcfee6 Mon Sep 17 00:00:00 2001 From: Scott Main Date: Mon, 26 Sep 2011 22:59:38 -0700 Subject: docs: mix of BT and NFC javadoc updates Add Health profile to various discussions about profiles Add descriptions to NFC interfaces, tweak some desciptions, and fix some broken links Change-Id: Ib89434c78a4ad60b4358dca9a6c335451d1c4125 --- framework/java/android/bluetooth/BluetoothAdapter.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 254c98ff8c..ea5c3db865 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -781,7 +781,7 @@ public final class BluetoothAdapter { * Get the current connection state of a profile. * This function can be used to check whether the local Bluetooth adapter * is connected to any remote device for a specific profile. - * Profile can be one of {@link BluetoothProfile#HEADSET}, + * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, * {@link BluetoothProfile#A2DP}. * *

Requires {@link android.Manifest.permission#BLUETOOTH}. @@ -1132,15 +1132,15 @@ public final class BluetoothAdapter { /** * Get the profile proxy object associated with the profile. * - *

Profile can be one of {@link BluetoothProfile#HEADSET} or + *

Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or * {@link BluetoothProfile#A2DP}. Clients must implements * {@link BluetoothProfile.ServiceListener} to get notified of * the connection status and to get the proxy object. * * @param context Context of the application * @param listener The service Listener for connection callbacks. - * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEADSET} - * or {@link BluetoothProfile#A2DP}. + * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH}, + * {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}. * @return true on success, false on error */ public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, @@ -1172,7 +1172,7 @@ public final class BluetoothAdapter { * *

Clients should call this when they are no longer using * the proxy obtained from {@link #getProfileProxy}. - * Profile can be one of {@link BluetoothProfile#HEADSET} or + * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or * {@link BluetoothProfile#A2DP} * * @param profile -- cgit v1.2.3 From 70c4b33caa3d366f887e9d94848b6421ba327205 Mon Sep 17 00:00:00 2001 From: Matthew Xie Date: Wed, 16 Nov 2011 12:27:57 -0800 Subject: Check the bluetooth state for getUuid call Donnot make the bluetoothservice.getUuids call if the bluetooth is not on. Also get rid of all the necessary locks on BluetoothService for get property call. It had a lock on BluetoothAdapterProperty. bug5472114 Change-Id: I383472ae6006fc1f0129c960c8a44ed0df027a43 --- framework/java/android/bluetooth/BluetoothAdapter.java | 1 + 1 file changed, 1 insertion(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ea5c3db865..d971652565 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -533,6 +533,7 @@ public final class BluetoothAdapter { * @hide */ public ParcelUuid[] getUuids() { + if (getState() != STATE_ON) return null; try { return mService.getUuids(); } catch (RemoteException e) {Log.e(TAG, "", e);} -- cgit v1.2.3 From 05180edf7371643b6a9c7643c888b12a461d1a01 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Mon, 28 Nov 2011 09:59:08 -0800 Subject: Cleanup references when turning BT off. Bug: 5572649 Change-Id: I62f9e0620832b69995d5c6e1c24634c9a3895a4b --- .../java/android/bluetooth/BluetoothAdapter.java | 26 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index d971652565..5f5ba50413 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1180,11 +1180,29 @@ public final class BluetoothAdapter { * @param proxy Profile proxy object */ public void closeProfileProxy(int profile, BluetoothProfile proxy) { - if (profile == BluetoothProfile.HEADSET) { - BluetoothHeadset headset = (BluetoothHeadset)proxy; - if (headset != null) { + if (proxy == null) return; + + switch (profile) { + case BluetoothProfile.HEADSET: + BluetoothHeadset headset = (BluetoothHeadset)proxy; headset.close(); - } + break; + case BluetoothProfile.A2DP: + BluetoothA2dp a2dp = (BluetoothA2dp)proxy; + a2dp.close(); + break; + case BluetoothProfile.INPUT_DEVICE: + BluetoothInputDevice iDev = (BluetoothInputDevice)proxy; + iDev.close(); + break; + case BluetoothProfile.PAN: + BluetoothPan pan = (BluetoothPan)proxy; + pan.close(); + break; + case BluetoothProfile.HEALTH: + BluetoothHealth health = (BluetoothHealth)proxy; + health.close(); + break; } } -- cgit v1.2.3 From d3fca95609666ed243262f7476621538c929b99b Mon Sep 17 00:00:00 2001 From: Nick Pelly Date: Wed, 7 Dec 2011 15:03:55 -0800 Subject: Add BluetoothAdapter.getRemoteDevice(byte[]) This is useful for NFC->BT hand-over, where we are already working with bytes. Change-Id: I2fff0b4fa0cefe9bfdf9a13f7ec6f557776a8a03 --- .../java/android/bluetooth/BluetoothAdapter.java | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 5f5ba50413..e420bfd8c1 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -398,6 +398,25 @@ public final class BluetoothAdapter { return new BluetoothDevice(address); } + /** + * Get a {@link BluetoothDevice} object for the given Bluetooth hardware + * address. + *

Valid Bluetooth hardware addresses must be 6 bytes. This method + * expects the address in network byte order (MSB first). + *

A {@link BluetoothDevice} will always be returned for a valid + * hardware address, even if this adapter has never seen that device. + * + * @param address Bluetooth MAC address (6 bytes) + * @throws IllegalArgumentException if address is invalid + */ + public BluetoothDevice getRemoteDevice(byte[] address) { + if (address == null || address.length != 6) { + throw new IllegalArgumentException("Bluetooth address must have 6 bytes"); + } + return new BluetoothDevice(String.format("%02X:%02X:%02X:%02X:%02X:%02X", + address[0], address[1], address[2], address[3], address[4], address[5])); + } + /** * Return true if Bluetooth is currently enabled and ready for use. *

Equivalent to: @@ -1281,7 +1300,7 @@ public final class BluetoothAdapter { } /** - * Validate a Bluetooth address, such as "00:43:A8:23:10:F0" + * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0" *

Alphabetic characters must be uppercase to be valid. * * @param address Bluetooth address as string -- cgit v1.2.3 From da4e2ab44781662822e2f8ee1f94f2085309d66d Mon Sep 17 00:00:00 2001 From: Joe Fernandez Date: Tue, 20 Dec 2011 10:38:34 -0800 Subject: docs: Add developer guide cross-references, Project ACRE, round 4 Change-Id: I1b43414aaec8ea217b39a0d780c80a25409d0991 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 5f5ba50413..899816c4e1 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -62,6 +62,12 @@ import java.util.UUID; * permission and some also require the * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. * + *

+ *

Developer Guides

+ *

For more information about using Bluetooth, read the + * Bluetooth developer guide.

+ *
+ * * {@see BluetoothDevice} * {@see BluetoothServerSocket} */ -- cgit v1.2.3 From a9110b8e7ebe9d6aef89ed9be1ccead99f87760b Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 18 Apr 2012 13:01:15 -0700 Subject: Allow enabling Bluetooth without auto-connecting. This is a feature used for NFC-to-Bluetooth handover: we want to enable BT for file transfer, and disconnect it when we're done. During this period we don't want to auto-connect other devices - it should be transparent to the user that Bluetooth is used. Also, don't allow A2DP/HSP incoming connections. Change-Id: I0a03e8084c439b1271b6a80f4d9da5aacfe19c45 --- framework/java/android/bluetooth/BluetoothAdapter.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 600ce6f71e..8e3df472a3 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1231,6 +1231,18 @@ public final class BluetoothAdapter { } } + /** + * Enable the Bluetooth Adapter, but don't auto-connect devices + * and don't persist state. Only for use by system applications. + * @hide + */ + public boolean enableNoAutoConnect() { + try { + return mService.enableNoAutoConnect(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + /** * Enable control of the Bluetooth Adapter for a single application. * -- cgit v1.2.3 From 884452306d321a159f432fbec2573d2f37e513c5 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Wed, 25 Jan 2012 16:16:48 -0800 Subject: Changes for new Bluetooth APIs. Changes to Bluetooth Adapter, Device and IBluetooth interfaces for new Bluetooth APIs. Delete AudioGateway. Change-Id: Ib51b31187eafde261441b9311b5e7e13c8bff82f --- .../java/android/bluetooth/BluetoothAdapter.java | 45 ++++++++++++---------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8e3df472a3..755884c270 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -367,10 +367,12 @@ public final class BluetoothAdapter { */ public static synchronized BluetoothAdapter getDefaultAdapter() { if (sAdapter == null) { - IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE); + IBinder b = ServiceManager.getService("bluetooth"); if (b != null) { IBluetooth service = IBluetooth.Stub.asInterface(b); sAdapter = new BluetoothAdapter(service); + } else { + Log.e(TAG, "Bluetooth binder is null"); } } return sAdapter; @@ -378,9 +380,8 @@ public final class BluetoothAdapter { /** * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. - * @hide */ - public BluetoothAdapter(IBluetooth service) { + BluetoothAdapter(IBluetooth service) { if (service == null) { throw new IllegalArgumentException("service is null"); } @@ -450,8 +451,9 @@ public final class BluetoothAdapter { * @return current state of Bluetooth adapter */ public int getState() { + if (mService == null) return STATE_OFF; try { - return mService.getBluetoothState(); + return mService.getState(); } catch (RemoteException e) {Log.e(TAG, "", e);} return STATE_OFF; } @@ -516,7 +518,7 @@ public final class BluetoothAdapter { */ public boolean disable() { try { - return mService.disable(true); + return mService.disable(); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -774,10 +776,10 @@ public final class BluetoothAdapter { */ public Set getBondedDevices() { if (getState() != STATE_ON) { - return toDeviceSet(new String[0]); + return toDeviceSet(new BluetoothDevice[0]); } try { - return toDeviceSet(mService.listBonds()); + return toDeviceSet(mService.getBondedDevices()); } catch (RemoteException e) {Log.e(TAG, "", e);} return null; } @@ -999,7 +1001,6 @@ public final class BluetoothAdapter { private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt) throws IOException { RfcommChannelPicker picker = new RfcommChannelPicker(uuid); - BluetoothServerSocket socket; int channel; int errno; @@ -1031,10 +1032,11 @@ public final class BluetoothAdapter { } int handle = -1; - try { + //TODO(BT): + /*try { handle = mService.addRfcommServiceRecord(name, new ParcelUuid(uuid), channel, new Binder()); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) {Log.e(TAG, "", e);}*/ if (handle == -1) { try { socket.close(); @@ -1047,11 +1049,13 @@ public final class BluetoothAdapter { public void handleMessage(Message msg) { /* handle socket closing */ int handle = msg.what; + // TODO(BT): + /* try { if (DBG) Log.d(TAG, "Removing service record " + - Integer.toHexString(handle)); - mService.removeServiceRecord(handle); + Integer.toHexString(handle)); } catch (RemoteException e) {Log.e(TAG, "", e);} + */ } }; } @@ -1134,6 +1138,8 @@ public final class BluetoothAdapter { */ public Pair readOutOfBandData() { if (getState() != STATE_ON) return null; + //TODO(BT + /* try { byte[] hash; byte[] randomizer; @@ -1151,7 +1157,7 @@ public final class BluetoothAdapter { } return new Pair(hash, randomizer); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) {Log.e(TAG, "", e);}*/ return null; } @@ -1276,12 +1282,14 @@ public final class BluetoothAdapter { BluetoothStateChangeCallback callback) { if (callback == null) return false; + //TODO(BT) + /* try { return mService.changeApplicationBluetoothState(on, new StateChangeCallbackWrapper(callback), new Binder()); } catch (RemoteException e) { Log.e(TAG, "changeBluetoothState", e); - } + }*/ return false; } @@ -1309,12 +1317,9 @@ public final class BluetoothAdapter { } } - private Set toDeviceSet(String[] addresses) { - Set devices = new HashSet(addresses.length); - for (int i = 0; i < addresses.length; i++) { - devices.add(getRemoteDevice(addresses[i])); - } - return Collections.unmodifiableSet(devices); + private Set toDeviceSet(BluetoothDevice[] devices) { + Set deviceSet = new HashSet(Arrays.asList(devices)); + return Collections.unmodifiableSet(deviceSet); } /** -- cgit v1.2.3 From d95bd9c8fbae3ce3b5d7c011b58df67ba1602ba7 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Tue, 6 Mar 2012 17:15:16 -0800 Subject: Add a new version of the disable API. This allows for the setting to be persisted or not. Also turn on Bluetooth in System Server if needed. It won't work currently because the service wouldn't have started. Change-Id: I15fa2bff93aa32134c1b565fcbe90ba68614b6a1 --- .../java/android/bluetooth/BluetoothAdapter.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 755884c270..8d4c3afe63 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -518,7 +518,24 @@ public final class BluetoothAdapter { */ public boolean disable() { try { - return mService.disable(); + return mService.disable(true); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + + /** + * Turn off the local Bluetooth adapter and don't persist the setting. + * + *

Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission + * + * @return true to indicate adapter shutdown has begun, or false on + * immediate error + * @hide + */ + public boolean disable(boolean persist) { + try { + return mService.disable(persist); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } -- cgit v1.2.3 From fab62db7cf9962e90bfe30b85df57b6c621b7310 Mon Sep 17 00:00:00 2001 From: zzy Date: Tue, 3 Apr 2012 19:48:32 -0700 Subject: Added new rfcomm multi accept code --- .../java/android/bluetooth/BluetoothAdapter.java | 149 ++++----------------- 1 file changed, 27 insertions(+), 122 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8d4c3afe63..c4595a16c4 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -847,51 +847,6 @@ public final class BluetoothAdapter { return BluetoothProfile.STATE_DISCONNECTED; } - /** - /** - * Picks RFCOMM channels until none are left. - * Avoids reserved channels. - */ - private static class RfcommChannelPicker { - private static final int[] RESERVED_RFCOMM_CHANNELS = new int[] { - 10, // HFAG - 11, // HSAG - 12, // OPUSH - 19, // PBAP - }; - private static LinkedList sChannels; // master list of non-reserved channels - private static Random sRandom; - - private final LinkedList mChannels; // local list of channels left to try - - private final UUID mUuid; - - public RfcommChannelPicker(UUID uuid) { - synchronized (RfcommChannelPicker.class) { - if (sChannels == null) { - // lazy initialization of non-reserved rfcomm channels - sChannels = new LinkedList(); - for (int i = 1; i <= BluetoothSocket.MAX_RFCOMM_CHANNEL; i++) { - sChannels.addLast(new Integer(i)); - } - for (int reserved : RESERVED_RFCOMM_CHANNELS) { - sChannels.remove(new Integer(reserved)); - } - sRandom = new Random(); - } - mChannels = (LinkedList)sChannels.clone(); - } - mUuid = uuid; - } - /* Returns next random channel, or -1 if we're out */ - public int nextChannel() { - if (mChannels.size() == 0) { - return -1; - } - return mChannels.remove(sRandom.nextInt(mChannels.size())); - } - } - /** * Create a listening, secure RFCOMM Bluetooth socket. *

A remote device connecting to this socket will be authenticated and @@ -911,10 +866,10 @@ public final class BluetoothAdapter { BluetoothSocket.TYPE_RFCOMM, true, true, channel); int errno = socket.mSocket.bindListen(); if (errno != 0) { - try { - socket.close(); - } catch (IOException e) {} - socket.mSocket.throwErrnoNative(errno); + //TODO(BT): Throw the same exception error code + // that the previous code was using. + //socket.mSocket.throwErrnoNative(errno); + throw new IOException("Error: " + errno); } return socket; } @@ -1015,72 +970,23 @@ public final class BluetoothAdapter { return createNewRfcommSocketAndRecord(name, uuid, false, true); } + private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt) throws IOException { - RfcommChannelPicker picker = new RfcommChannelPicker(uuid); BluetoothServerSocket socket; - int channel; - int errno; - while (true) { - channel = picker.nextChannel(); - - if (channel == -1) { - throw new IOException("No available channels"); - } - - socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, auth, encrypt, channel); - errno = socket.mSocket.bindListen(); - if (errno == 0) { - if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel); - break; // success - } else if (errno == BluetoothSocket.EADDRINUSE) { - if (DBG) Log.d(TAG, "RFCOMM channel " + channel + " in use"); - try { - socket.close(); - } catch (IOException e) {} - continue; // try another channel - } else { - try { - socket.close(); - } catch (IOException e) {} - socket.mSocket.throwErrnoNative(errno); // Exception as a result of bindListen() - } - } - - int handle = -1; - //TODO(BT): - /*try { - handle = mService.addRfcommServiceRecord(name, new ParcelUuid(uuid), channel, - new Binder()); - } catch (RemoteException e) {Log.e(TAG, "", e);}*/ - if (handle == -1) { - try { - socket.close(); - } catch (IOException e) {} - throw new IOException("Not able to register SDP record for " + name); - } - - if (mServiceRecordHandler == null) { - mServiceRecordHandler = new Handler(Looper.getMainLooper()) { - public void handleMessage(Message msg) { - /* handle socket closing */ - int handle = msg.what; - // TODO(BT): - /* - try { - if (DBG) Log.d(TAG, "Removing service record " + - Integer.toHexString(handle)); - } catch (RemoteException e) {Log.e(TAG, "", e);} - */ - } - }; + socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, + encrypt, new ParcelUuid(uuid)); + socket.setServiceName(name); + int errno = socket.mSocket.bindListen(); + if (errno != 0) { + //TODO(BT): Throw the same exception error code + // that the previous code was using. + //socket.mSocket.throwErrnoNative(errno); + throw new IOException("Error: " + errno); } - socket.setCloseHandler(mServiceRecordHandler, handle); return socket; } - /** * Construct an unencrypted, unauthenticated, RFCOMM server socket. * Call #accept to retrieve connections to this socket. @@ -1094,10 +1000,10 @@ public final class BluetoothAdapter { BluetoothSocket.TYPE_RFCOMM, false, false, port); int errno = socket.mSocket.bindListen(); if (errno != 0) { - try { - socket.close(); - } catch (IOException e) {} - socket.mSocket.throwErrnoNative(errno); + //TODO(BT): Throw the same exception error code + // that the previous code was using. + //socket.mSocket.throwErrnoNative(errno); + throw new IOException("Error: " + errno); } return socket; } @@ -1115,11 +1021,11 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, false, true, port); int errno = socket.mSocket.bindListen(); - if (errno != 0) { - try { - socket.close(); - } catch (IOException e) {} - socket.mSocket.throwErrnoNative(errno); + if (errno < 0) { + //TODO(BT): Throw the same exception error code + // that the previous code was using. + //socket.mSocket.throwErrnoNative(errno); + throw new IOException("Error: " + errno); } return socket; } @@ -1136,11 +1042,10 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_SCO, false, false, -1); int errno = socket.mSocket.bindListen(); - if (errno != 0) { - try { - socket.close(); - } catch (IOException e) {} - socket.mSocket.throwErrnoNative(errno); + if (errno < 0) { + //TODO(BT): Throw the same exception error code + // that the previous code was using. + //socket.mSocket.throwErrnoNative(errno); } return socket; } -- cgit v1.2.3 From b527e5f44a3a3663c6794eeae95bac1e4b94db9c Mon Sep 17 00:00:00 2001 From: Srikanth Uppala Date: Wed, 4 Apr 2012 03:33:26 -0700 Subject: Fix discoverability timeout issues. (a) implement timeout logic (b) persist 'never timeout' after reboot (c) code cleanup Change-Id: Iacaec4a48a45935a49576c140ea11ea3d0da6361 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) mode change 100644 => 100755 framework/java/android/bluetooth/BluetoothAdapter.java (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java old mode 100644 new mode 100755 index c4595a16c4..c822754311 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -670,7 +670,8 @@ public final class BluetoothAdapter { /** @hide */ public boolean setScanMode(int mode) { if (getState() != STATE_ON) return false; - return setScanMode(mode, 120); + /* getDiscoverableTimeout() to use the latest from NV than use 0 */ + return setScanMode(mode, getDiscoverableTimeout()); } /** @hide */ -- cgit v1.2.3 From 3c7196448a62414bf1bfcc94947bfcfa2d60278a Mon Sep 17 00:00:00 2001 From: fredc Date: Thu, 12 Apr 2012 00:02:00 -0700 Subject: Non persistent adapter service Change-Id: Ib13d5c77416e58161df0e04d7a15ec0dddbde8b5 Conflicts: core/java/android/bluetooth/BluetoothInputDevice.java Conflicts: core/java/com/android/internal/app/ShutdownThread.java services/java/com/android/server/SystemServer.java Conflicts: services/java/com/android/server/SystemServer.java services/java/com/android/server/pm/ShutdownThread.java --- .../java/android/bluetooth/BluetoothAdapter.java | 147 ++++++++++++++++----- 1 file changed, 117 insertions(+), 30 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index c822754311..75ef3dd3aa 100755 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -73,7 +73,7 @@ import java.util.UUID; */ public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; - private static final boolean DBG = false; + private static final boolean DBG = true; /** * Sentinel error value for this class. Guaranteed to not equal any other @@ -343,7 +343,7 @@ public final class BluetoothAdapter { public static final int STATE_DISCONNECTING = 3; /** @hide */ - public static final String BLUETOOTH_SERVICE = "bluetooth"; + public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; private static final int ADDRESS_LENGTH = 17; @@ -353,7 +353,8 @@ public final class BluetoothAdapter { */ private static BluetoothAdapter sAdapter; - private final IBluetooth mService; + private final IBluetoothManager mManagerService; + private IBluetooth mService; private Handler mServiceRecordHandler; @@ -367,10 +368,10 @@ public final class BluetoothAdapter { */ public static synchronized BluetoothAdapter getDefaultAdapter() { if (sAdapter == null) { - IBinder b = ServiceManager.getService("bluetooth"); + IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE); if (b != null) { - IBluetooth service = IBluetooth.Stub.asInterface(b); - sAdapter = new BluetoothAdapter(service); + IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b); + sAdapter = new BluetoothAdapter(managerService); } else { Log.e(TAG, "Bluetooth binder is null"); } @@ -381,11 +382,15 @@ public final class BluetoothAdapter { /** * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. */ - BluetoothAdapter(IBluetooth service) { - if (service == null) { - throw new IllegalArgumentException("service is null"); + BluetoothAdapter(IBluetoothManager managerService) { + + if (managerService == null) { + throw new IllegalArgumentException("bluetooth manager service is null"); } - mService = service; + try { + mService = managerService.registerAdapter(mManagerCallback); + } catch (RemoteException e) {Log.e(TAG, "", e);} + mManagerService = managerService; mServiceRecordHandler = null; } @@ -402,6 +407,10 @@ public final class BluetoothAdapter { * @throws IllegalArgumentException if address is invalid */ public BluetoothDevice getRemoteDevice(String address) { + if (mService == null) { + Log.e(TAG, "BT not enabled. Cannot create Remote Device"); + return null; + } return new BluetoothDevice(address); } @@ -433,8 +442,11 @@ public final class BluetoothAdapter { * @return true if the local adapter is turned on */ public boolean isEnabled() { + try { - return mService.isEnabled(); + synchronized(mManagerCallback) { + if (mService != null) return mService.isEnabled(); + } } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -451,9 +463,15 @@ public final class BluetoothAdapter { * @return current state of Bluetooth adapter */ public int getState() { - if (mService == null) return STATE_OFF; try { - return mService.getState(); + synchronized(mManagerCallback) { + if (mService != null) + { + return mService.getState(); + } + // TODO(BT) there might be a small gap during STATE_TURNING_ON that + // mService is null, handle that case + } } catch (RemoteException e) {Log.e(TAG, "", e);} return STATE_OFF; } @@ -486,8 +504,13 @@ public final class BluetoothAdapter { * immediate error */ public boolean enable() { + + boolean enabled = false; try { - return mService.enable(); + enabled = mManagerService.enable(); + if (enabled) { + // TODO(BT) + } } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -518,7 +541,7 @@ public final class BluetoothAdapter { */ public boolean disable() { try { - return mService.disable(true); + return mManagerService.disable(true); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -534,8 +557,9 @@ public final class BluetoothAdapter { * @hide */ public boolean disable(boolean persist) { + try { - return mService.disable(persist); + return mManagerService.disable(persist); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -549,7 +573,7 @@ public final class BluetoothAdapter { */ public String getAddress() { try { - return mService.getAddress(); + return mManagerService.getAddress(); } catch (RemoteException e) {Log.e(TAG, "", e);} return null; } @@ -563,7 +587,7 @@ public final class BluetoothAdapter { */ public String getName() { try { - return mService.getName(); + return mManagerService.getName(); } catch (RemoteException e) {Log.e(TAG, "", e);} return null; } @@ -579,7 +603,9 @@ public final class BluetoothAdapter { public ParcelUuid[] getUuids() { if (getState() != STATE_ON) return null; try { - return mService.getUuids(); + synchronized(mManagerCallback) { + if (mService != null) return mService.getUuids(); + } } catch (RemoteException e) {Log.e(TAG, "", e);} return null; } @@ -602,7 +628,9 @@ public final class BluetoothAdapter { public boolean setName(String name) { if (getState() != STATE_ON) return false; try { - return mService.setName(name); + synchronized(mManagerCallback) { + if (mService != null) return mService.setName(name); + } } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -626,7 +654,9 @@ public final class BluetoothAdapter { public int getScanMode() { if (getState() != STATE_ON) return SCAN_MODE_NONE; try { - return mService.getScanMode(); + synchronized(mManagerCallback) { + if (mService != null) return mService.getScanMode(); + } } catch (RemoteException e) {Log.e(TAG, "", e);} return SCAN_MODE_NONE; } @@ -662,7 +692,9 @@ public final class BluetoothAdapter { public boolean setScanMode(int mode, int duration) { if (getState() != STATE_ON) return false; try { - return mService.setScanMode(mode, duration); + synchronized(mManagerCallback) { + if (mService != null) return mService.setScanMode(mode, duration); + } } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -678,7 +710,9 @@ public final class BluetoothAdapter { public int getDiscoverableTimeout() { if (getState() != STATE_ON) return -1; try { - return mService.getDiscoverableTimeout(); + synchronized(mManagerCallback) { + if (mService != null) return mService.getDiscoverableTimeout(); + } } catch (RemoteException e) {Log.e(TAG, "", e);} return -1; } @@ -687,7 +721,9 @@ public final class BluetoothAdapter { public void setDiscoverableTimeout(int timeout) { if (getState() != STATE_ON) return; try { - mService.setDiscoverableTimeout(timeout); + synchronized(mManagerCallback) { + if (mService != null) mService.setDiscoverableTimeout(timeout); + } } catch (RemoteException e) {Log.e(TAG, "", e);} } @@ -724,7 +760,9 @@ public final class BluetoothAdapter { public boolean startDiscovery() { if (getState() != STATE_ON) return false; try { - return mService.startDiscovery(); + synchronized(mManagerCallback) { + if (mService != null) return mService.startDiscovery(); + } } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -749,7 +787,9 @@ public final class BluetoothAdapter { public boolean cancelDiscovery() { if (getState() != STATE_ON) return false; try { - return mService.cancelDiscovery(); + synchronized(mManagerCallback) { + if (mService != null) return mService.cancelDiscovery(); + } } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -776,7 +816,9 @@ public final class BluetoothAdapter { public boolean isDiscovering() { if (getState() != STATE_ON) return false; try { - return mService.isDiscovering(); + synchronized(mManagerCallback) { + if (mService != null ) return mService.isDiscovering(); + } } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -797,7 +839,10 @@ public final class BluetoothAdapter { return toDeviceSet(new BluetoothDevice[0]); } try { - return toDeviceSet(mService.getBondedDevices()); + synchronized(mManagerCallback) { + if (mService != null) return toDeviceSet(mService.getBondedDevices()); + } + return toDeviceSet(new BluetoothDevice[0]); } catch (RemoteException e) {Log.e(TAG, "", e);} return null; } @@ -818,7 +863,9 @@ public final class BluetoothAdapter { public int getConnectionState() { if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED; try { - return mService.getAdapterConnectionState(); + synchronized(mManagerCallback) { + if (mService != null) return mService.getAdapterConnectionState(); + } } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);} return BluetoothAdapter.STATE_DISCONNECTED; } @@ -841,7 +888,9 @@ public final class BluetoothAdapter { public int getProfileConnectionState(int profile) { if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED; try { - return mService.getProfileConnectionState(profile); + synchronized(mManagerCallback) { + if (mService != null) return mService.getProfileConnectionState(profile); + } } catch (RemoteException e) { Log.e(TAG, "getProfileConnectionState:", e); } @@ -1160,6 +1209,23 @@ public final class BluetoothAdapter { } } + final private IBluetoothManagerCallback mManagerCallback = + new IBluetoothManagerCallback.Stub() { + public void onBluetoothServiceUp(IBluetooth bluetoothService) { + if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); + synchronized (mManagerCallback) { + mService = bluetoothService; + } + } + + public void onBluetoothServiceDown() { + if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); + synchronized (mManagerCallback) { + mService = null; + } + } + }; + /** * Enable the Bluetooth Adapter, but don't auto-connect devices * and don't persist state. Only for use by system applications. @@ -1245,6 +1311,17 @@ public final class BluetoothAdapter { return Collections.unmodifiableSet(deviceSet); } + protected void finalize() throws Throwable { + try { + mManagerService.unregisterAdapter(mManagerCallback); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + super.finalize(); + } + } + + /** * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0" *

Alphabetic characters must be uppercase to be valid. @@ -1275,4 +1352,14 @@ public final class BluetoothAdapter { } return true; } + + /*package*/ IBluetoothManager getBluetoothManager() { + return mManagerService; + } + + /*package*/ IBluetooth getBluetoothService() { + synchronized (mManagerCallback) { + return mService; + } + } } -- cgit v1.2.3 From 08e6ff77c4f82e97df5e8a8ab060c51b51a561db Mon Sep 17 00:00:00 2001 From: Kausik Sinnaswamy Date: Mon, 16 Apr 2012 16:38:27 +0530 Subject: BT enable adapter API should return TRUE or FALSE. Change-Id: Iaef14c51d3407b69505c55a0bbdaf902213402cf --- framework/java/android/bluetooth/BluetoothAdapter.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 75ef3dd3aa..bde52eedbc 100755 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -507,10 +507,7 @@ public final class BluetoothAdapter { boolean enabled = false; try { - enabled = mManagerService.enable(); - if (enabled) { - // TODO(BT) - } + return mManagerService.enable(); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } -- cgit v1.2.3 From 95a8d72c03118a11736212380b3497285b7bcf53 Mon Sep 17 00:00:00 2001 From: Sreenidhi T Date: Wed, 18 Apr 2012 04:24:33 -0700 Subject: Change done in BluetoothAdapter to use the same API for interacting with the Bluetooth Service. setName was being done using mService while getName was using mManagerService. As a result, the device name was not being updated in Localadapter getname call. Modified to use mService in both cases. Change-Id: I2e900a782df11fd511319fbb42d94324e50ae89b --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index bde52eedbc..867ab64331 100755 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -584,7 +584,7 @@ public final class BluetoothAdapter { */ public String getName() { try { - return mManagerService.getName(); + return mService.getName(); } catch (RemoteException e) {Log.e(TAG, "", e);} return null; } -- cgit v1.2.3 From 50ef8e028d458ce29664d3ec3b3d9a320bade6ff Mon Sep 17 00:00:00 2001 From: fredc Date: Fri, 20 Apr 2012 14:47:08 -0700 Subject: Fixed issue with getting Bluetooth adapter's name and airplane mode Change-Id: I18b632223574aa41b09ba30de8e35417fad86cbe --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 867ab64331..bde52eedbc 100755 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -584,7 +584,7 @@ public final class BluetoothAdapter { */ public String getName() { try { - return mService.getName(); + return mManagerService.getName(); } catch (RemoteException e) {Log.e(TAG, "", e);} return null; } -- cgit v1.2.3 From f1f5dde555c09019c0cedb05e844adf288677bc5 Mon Sep 17 00:00:00 2001 From: fredc Date: Tue, 24 Apr 2012 03:59:57 -0700 Subject: Fixed issue with Settings app crashing after during on/off and unpair. Fixed issue with BluetoothAdapter.getRemoteDevice() returning null. Change-Id: Ie86813532530a6b57bde1c430c7b4875ecc7354c --- .../java/android/bluetooth/BluetoothAdapter.java | 31 +++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index bde52eedbc..9f50c54276 100755 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -31,6 +31,7 @@ import android.util.Log; import android.util.Pair; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; @@ -407,10 +408,6 @@ public final class BluetoothAdapter { * @throws IllegalArgumentException if address is invalid */ public BluetoothDevice getRemoteDevice(String address) { - if (mService == null) { - Log.e(TAG, "BT not enabled. Cannot create Remote Device"); - return null; - } return new BluetoothDevice(address); } @@ -504,7 +501,6 @@ public final class BluetoothAdapter { * immediate error */ public boolean enable() { - boolean enabled = false; try { return mManagerService.enable(); @@ -1212,6 +1208,11 @@ public final class BluetoothAdapter { if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); synchronized (mManagerCallback) { mService = bluetoothService; + for (IBluetoothManagerCallback cb : mBluetoothManagerCallbackList ){ + try { + cb.onBluetoothServiceUp(bluetoothService); + } catch (Exception e) { Log.e(TAG,"",e);} + } } } @@ -1219,6 +1220,11 @@ public final class BluetoothAdapter { if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); synchronized (mManagerCallback) { mService = null; + for (IBluetoothManagerCallback cb : mBluetoothManagerCallbackList ){ + try { + cb.onBluetoothServiceDown(); + } catch (Exception e) { Log.e(TAG,"",e);} + } } } }; @@ -1354,9 +1360,20 @@ public final class BluetoothAdapter { return mManagerService; } - /*package*/ IBluetooth getBluetoothService() { + private ArrayList mBluetoothManagerCallbackList = new ArrayList(); + //private IBluetoothStateChangeCallback mBluetoothStateChangeCallback; + /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { + synchronized (mManagerCallback) { + if (!mBluetoothManagerCallbackList.contains(cb)) { + mBluetoothManagerCallbackList.add(cb); + } + } + return mService; + } + + /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) { synchronized (mManagerCallback) { - return mService; + mBluetoothManagerCallbackList.remove(cb); } } } -- cgit v1.2.3 From e8d151968574b4ec435e5b133d07fe67888ca22f Mon Sep 17 00:00:00 2001 From: fredc Date: Wed, 25 Apr 2012 17:46:13 -0700 Subject: Fixed socket not closing on BT off. Used RemoteCallbackList to monitor binder deaths in BluetoothManagerService. Change-Id: I524964bd2836d8c5a4bae095b93ac9481337941d --- framework/java/android/bluetooth/BluetoothAdapter.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 9f50c54276..c08705cf7f 100755 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1210,7 +1210,11 @@ public final class BluetoothAdapter { mService = bluetoothService; for (IBluetoothManagerCallback cb : mBluetoothManagerCallbackList ){ try { - cb.onBluetoothServiceUp(bluetoothService); + if (cb != null) { + cb.onBluetoothServiceUp(bluetoothService); + } else { + Log.d(TAG, "onBluetoothServiceUp: cb is null!!!"); + } } catch (Exception e) { Log.e(TAG,"",e);} } } @@ -1222,7 +1226,11 @@ public final class BluetoothAdapter { mService = null; for (IBluetoothManagerCallback cb : mBluetoothManagerCallbackList ){ try { - cb.onBluetoothServiceDown(); + if (cb != null) { + cb.onBluetoothServiceDown(); + } else { + Log.d(TAG, "onBluetoothServiceDown: cb is null!!!"); + } } catch (Exception e) { Log.e(TAG,"",e);} } } @@ -1361,10 +1369,12 @@ public final class BluetoothAdapter { } private ArrayList mBluetoothManagerCallbackList = new ArrayList(); - //private IBluetoothStateChangeCallback mBluetoothStateChangeCallback; + /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { synchronized (mManagerCallback) { - if (!mBluetoothManagerCallbackList.contains(cb)) { + if (cb == null) { + Log.w(TAG, "Unable to register null state change callback", new Exception()); + } else if (!mBluetoothManagerCallbackList.contains(cb)) { mBluetoothManagerCallbackList.add(cb); } } -- cgit v1.2.3 From d07368a662080b25ab357c6ffbe57ea030d00a56 Mon Sep 17 00:00:00 2001 From: fredc Date: Wed, 9 May 2012 16:52:50 -0700 Subject: Moved BluetoothAdapter.ACTION_STATE_CHANGED broadcast from AdapterService to BluetoothManagerService Change-Id: I88e5f3fe050cf11eae9c5cf1b7c393a178b8f9b1 --- .../java/android/bluetooth/BluetoothAdapter.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index c08705cf7f..dc1802929a 100755 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -464,12 +464,15 @@ public final class BluetoothAdapter { synchronized(mManagerCallback) { if (mService != null) { - return mService.getState(); + int state= mService.getState(); + if (DBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state); + return state; } // TODO(BT) there might be a small gap during STATE_TURNING_ON that // mService is null, handle that case } } catch (RemoteException e) {Log.e(TAG, "", e);} + if (DBG) Log.d(TAG, "" + hashCode() + ": getState() : mService = null. Returning STATE_OFF"); return STATE_OFF; } @@ -1208,7 +1211,7 @@ public final class BluetoothAdapter { if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); synchronized (mManagerCallback) { mService = bluetoothService; - for (IBluetoothManagerCallback cb : mBluetoothManagerCallbackList ){ + for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ try { if (cb != null) { cb.onBluetoothServiceUp(bluetoothService); @@ -1224,7 +1227,7 @@ public final class BluetoothAdapter { if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); synchronized (mManagerCallback) { mService = null; - for (IBluetoothManagerCallback cb : mBluetoothManagerCallbackList ){ + for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ try { if (cb != null) { cb.onBluetoothServiceDown(); @@ -1368,14 +1371,14 @@ public final class BluetoothAdapter { return mManagerService; } - private ArrayList mBluetoothManagerCallbackList = new ArrayList(); + private ArrayList mProxyServiceStateCallbacks = new ArrayList(); /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { synchronized (mManagerCallback) { if (cb == null) { - Log.w(TAG, "Unable to register null state change callback", new Exception()); - } else if (!mBluetoothManagerCallbackList.contains(cb)) { - mBluetoothManagerCallbackList.add(cb); + Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback"); + } else if (!mProxyServiceStateCallbacks.contains(cb)) { + mProxyServiceStateCallbacks.add(cb); } } return mService; @@ -1383,7 +1386,7 @@ public final class BluetoothAdapter { /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) { synchronized (mManagerCallback) { - mBluetoothManagerCallbackList.remove(cb); + mProxyServiceStateCallbacks.remove(cb); } } } -- cgit v1.2.3 From 0d6d9f8765c3eb2a602a6bf1809eef4b2a66d1de Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 3 Aug 2012 08:36:02 -0700 Subject: Bluetooth: fix enableNoAutoConnect() call. For now, just do a regular connect. Change-Id: Ibc43098d45c82177298cb17d72a32c7904924021 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index dc1802929a..ceaf17ee62 100755 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1246,10 +1246,8 @@ public final class BluetoothAdapter { * @hide */ public boolean enableNoAutoConnect() { - try { - return mService.enableNoAutoConnect(); - } catch (RemoteException e) {Log.e(TAG, "", e);} - return false; + // TODO avoid auto-connect in the new stack. + return enable(); } /** -- cgit v1.2.3 From fa1a5278a9412da532f397de49bad3db3ebf1965 Mon Sep 17 00:00:00 2001 From: Ganesh Ganapathi Batta Date: Wed, 8 Aug 2012 15:35:49 -0700 Subject: Implement enableNoAutoconnect() Adding enableNoAutoconnect() API support in Bluetooth service to let BT enable in quiet mode Change-Id: I546f3ceb298082a9c9a698f406379470e3cc0d4f --- framework/java/android/bluetooth/BluetoothAdapter.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ceaf17ee62..17d404d2d7 100755 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -504,7 +504,10 @@ public final class BluetoothAdapter { * immediate error */ public boolean enable() { - boolean enabled = false; + if (isEnabled() == true){ + if (DBG) Log.d(TAG, "enable(): BT is already enabled..!"); + return true; + } try { return mManagerService.enable(); } catch (RemoteException e) {Log.e(TAG, "", e);} @@ -1246,8 +1249,14 @@ public final class BluetoothAdapter { * @hide */ public boolean enableNoAutoConnect() { - // TODO avoid auto-connect in the new stack. - return enable(); + if (isEnabled() == true){ + if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT is already enabled..!"); + return true; + } + try { + return mManagerService.enableNoAutoConnect(); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; } /** -- cgit v1.2.3 From 80b7fb44e7613838b2162df33b64fd0a7b7ac2e5 Mon Sep 17 00:00:00 2001 From: Matthew Xie Date: Wed, 29 Aug 2012 00:12:29 -0700 Subject: Turn off verbose debug message in BluetoothAdapter Change-Id: I30245ab911b5428f7af38f195b941db02d36b18f --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 17d404d2d7..f817fb48d2 100755 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -75,6 +75,7 @@ import java.util.UUID; public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; private static final boolean DBG = true; + private static final boolean VDBG = false; /** * Sentinel error value for this class. Guaranteed to not equal any other @@ -465,7 +466,7 @@ public final class BluetoothAdapter { if (mService != null) { int state= mService.getState(); - if (DBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state); + if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state); return state; } // TODO(BT) there might be a small gap during STATE_TURNING_ON that -- cgit v1.2.3 From a466c6c72a7dee9c1abf0f95cb3e3412072ffa94 Mon Sep 17 00:00:00 2001 From: Matthew Xie Date: Thu, 29 Nov 2012 20:26:19 -0800 Subject: Clean up debug messages bug 7626174 Change-Id: I65cdcaf2c48a78468b6cef0b8591289435068b24 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index f817fb48d2..6367e16049 100755 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1212,7 +1212,7 @@ public final class BluetoothAdapter { final private IBluetoothManagerCallback mManagerCallback = new IBluetoothManagerCallback.Stub() { public void onBluetoothServiceUp(IBluetooth bluetoothService) { - if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); + if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); synchronized (mManagerCallback) { mService = bluetoothService; for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ @@ -1228,7 +1228,7 @@ public final class BluetoothAdapter { } public void onBluetoothServiceDown() { - if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); + if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); synchronized (mManagerCallback) { mService = null; for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ -- cgit v1.2.3 From 40b98951361157933c2084e855f7cffef0ca7fb7 Mon Sep 17 00:00:00 2001 From: Ganesh Ganapathi Batta Date: Tue, 5 Feb 2013 15:28:33 -0800 Subject: Initial version of BLE support for Bluedroid The API classes are hidden for now. Will unhide after API console approval. Change-Id: I8283dd562fd6189fdd15c866ef2efb8bbdbc4109 --- .../java/android/bluetooth/BluetoothAdapter.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) mode change 100755 => 100644 framework/java/android/bluetooth/BluetoothAdapter.java (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java old mode 100755 new mode 100644 index 6367e16049..1bbfb5dfb3 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1136,8 +1136,9 @@ public final class BluetoothAdapter { /** * Get the profile proxy object associated with the profile. * - *

Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or - * {@link BluetoothProfile#A2DP}. Clients must implements + *

Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, + * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, + * or {@link BluetoothProfile#GATT_SERVER}. Clients must implements * {@link BluetoothProfile.ServiceListener} to get notified of * the connection status and to get the proxy object. * @@ -1166,6 +1167,12 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.HEALTH) { BluetoothHealth health = new BluetoothHealth(context, listener); return true; + } else if (profile == BluetoothProfile.GATT) { + BluetoothGatt gatt = new BluetoothGatt(context, listener); + return true; + } else if (profile == BluetoothProfile.GATT_SERVER) { + BluetoothGattServer gattServer = new BluetoothGattServer(context, listener); + return true; } else { return false; } @@ -1206,6 +1213,14 @@ public final class BluetoothAdapter { BluetoothHealth health = (BluetoothHealth)proxy; health.close(); break; + case BluetoothProfile.GATT: + BluetoothGatt gatt = (BluetoothGatt)proxy; + gatt.close(); + break; + case BluetoothProfile.GATT_SERVER: + BluetoothGattServer gattServer = (BluetoothGattServer)proxy; + gattServer.close(); + break; } } -- cgit v1.2.3 From d6f9701119db423333a50bfa286968cdb880512f Mon Sep 17 00:00:00 2001 From: Stephen Hines Date: Thu, 28 Feb 2013 14:23:00 -0800 Subject: Fix docs bug. Change-Id: I8c69963b339d703757bf1cd8f43161175783566d --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 1bbfb5dfb3..b00bf09598 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1137,8 +1137,7 @@ public final class BluetoothAdapter { * Get the profile proxy object associated with the profile. * *

Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, - * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, - * or {@link BluetoothProfile#GATT_SERVER}. Clients must implements + * or {@link BluetoothProfile#A2DP}. Clients must implement * {@link BluetoothProfile.ServiceListener} to get notified of * the connection status and to get the proxy object. * -- cgit v1.2.3 From 9afa274491ca272dc30f6f6211ef2719b7a2226e Mon Sep 17 00:00:00 2001 From: Matthew Xie Date: Fri, 1 Mar 2013 18:41:02 -0800 Subject: Unhide Bluetooth Low Energy public APIs Updated API headers. Add BluetoothManager to be retrieved by context.getSystemService(Context.BLUETOOTH_SERVICE). LE scan functions are placed in BluetoothAdapter The GATT API are device driven instead of a profile-driver. bug 8450158 Change-Id: I424a4cedaac3ef8120a05996500008dd210d2553 --- .../java/android/bluetooth/BluetoothAdapter.java | 238 ++++++++++++++++++++- 1 file changed, 230 insertions(+), 8 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b00bf09598..2e9c9e334d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -22,7 +22,6 @@ import android.content.Context; import android.os.Binder; import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.os.Message; import android.os.ParcelUuid; import android.os.RemoteException; @@ -359,6 +358,8 @@ public final class BluetoothAdapter { private IBluetooth mService; private Handler mServiceRecordHandler; + private BluetoothAdapterCallback mCallback; + private int mClientIf; /** * Get a handle to the default local Bluetooth adapter. @@ -1137,7 +1138,8 @@ public final class BluetoothAdapter { * Get the profile proxy object associated with the profile. * *

Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, - * or {@link BluetoothProfile#A2DP}. Clients must implement + * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or + * {@link BluetoothProfile#GATT_SERVER}. Clients must implement * {@link BluetoothProfile.ServiceListener} to get notified of * the connection status and to get the proxy object. * @@ -1166,12 +1168,6 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.HEALTH) { BluetoothHealth health = new BluetoothHealth(context, listener); return true; - } else if (profile == BluetoothProfile.GATT) { - BluetoothGatt gatt = new BluetoothGatt(context, listener); - return true; - } else if (profile == BluetoothProfile.GATT_SERVER) { - BluetoothGattServer gattServer = new BluetoothGattServer(context, listener); - return true; } else { return false; } @@ -1411,4 +1407,230 @@ public final class BluetoothAdapter { mProxyServiceStateCallbacks.remove(cb); } } + + /** + * Register an callback to receive async results, such as LE scan result. + * + *

This is an asynchronous call. The callback + * {@link BluetoothAdapterCallback#onCallbackRegistration} + * is used to notify success or failure if the function returns true. + * + *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param callback BluetootAdapter callback handler that will receive asynchronous callbacks. + * @return If true, the callback will be called to notify success or failure, + * false on immediate error + */ + public boolean registerCallback(BluetoothAdapterCallback callback) { + try { + IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); + mCallback = callback; + UUID uuid = UUID.randomUUID(); + if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid); + + iGatt.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback); + return true; + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + } + + /** + * Unregister the registered callback. + */ + public boolean unRegisterCallback(BluetoothAdapterCallback callback) { + if (callback != mCallback) return false; + try { + IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); + + iGatt.unregisterClient(mClientIf); + return true; + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + } + + /** + * Starts a scan for Bluetooth LE devices. + * + *

Results of the scan are reported using the + * {@link BluetoothAdapterCallback#onLeScan} callback. + * + *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @return true, if the scan was started successfully + */ + public boolean startLeScan() { + if (DBG) Log.d(TAG, "startLeScan()"); + if (mClientIf == 0) return false; + + try { + IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); + iGatt.startScan(mClientIf, false); + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + + return true; + } + + /** + * Starts a scan for Bluetooth LE devices, looking for devices that + * advertise given services. + * + *

Devices which advertise all specified services are reported using the + * {@link BluetoothAdapterCallback#onLeScan} callback. + * + *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param serviceUuids Array of services to look for + * @return true, if the scan was started successfully + */ + public boolean startLeScan(UUID[] serviceUuids) { + if (DBG) Log.d(TAG, "startLeScan() - with UUIDs"); + if (mClientIf == 0) return false; + + try { + IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); + ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length]; + for(int i = 0; i != uuids.length; ++i) { + uuids[i] = new ParcelUuid(serviceUuids[i]); + } + iGatt.startScanWithUuids(mClientIf, false, uuids); + } catch (RemoteException e) { + Log.e(TAG,"",e); + return false; + } + + return true; + } + + /** + * Stops an ongoing Bluetooth LE device scan. + * + *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. + */ + public void stopLeScan() { + if (DBG) Log.d(TAG, "stopScan()"); + if (mClientIf == 0) return; + + try { + IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); + iGatt.stopScan(mClientIf, false); + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + + /** + * Bluetooth GATT interface callbacks + */ + private final IBluetoothGattCallback mBluetoothGattCallback = + new IBluetoothGattCallback.Stub() { + /** + * Application interface registered - app is ready to go + */ + public void onClientRegistered(int status, int clientIf) { + if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status + + " clientIf=" + clientIf); + mClientIf = clientIf; + mCallback.onCallbackRegistration(status == BluetoothGatt.GATT_SUCCESS ? + BluetoothAdapterCallback.CALLBACK_REGISTERED : + BluetoothAdapterCallback.CALLBACK_REGISTRATION_FAILURE); + } + + public void onClientConnectionState(int status, int clientIf, + boolean connected, String address) { + // no op + } + + /** + * Callback reporting an LE scan result. + * @hide + */ + public void onScanResult(String address, int rssi, byte[] advData) { + if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); + + try { + mCallback.onLeScan(getRemoteDevice(address), rssi, advData); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); + } + } + + public void onGetService(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid) { + // no op + } + + public void onGetIncludedService(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int inclSrvcType, int inclSrvcInstId, + ParcelUuid inclSrvcUuid) { + // no op + } + + public void onGetCharacteristic(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + int charProps) { + // no op + } + + public void onGetDescriptor(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descUuid) { + // no op + } + + public void onSearchComplete(String address, int status) { + // no op + } + + public void onCharacteristicRead(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, byte[] value) { + // no op + } + + public void onCharacteristicWrite(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid) { + // no op + } + + public void onNotify(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + byte[] value) { + // no op + } + + public void onDescriptorRead(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descrUuid, byte[] value) { + // no op + } + + public void onDescriptorWrite(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descrUuid) { + // no op + } + + public void onExecuteWrite(String address, int status) { + // no op + } + + public void onReadRemoteRssi(String address, int rssi, int status) { + // no op + } + }; + } -- cgit v1.2.3 From 01e8e2ac8e6994921b811f741b2d4dbe99b50b19 Mon Sep 17 00:00:00 2001 From: Matthew Xie Date: Thu, 11 Apr 2013 16:36:26 -0700 Subject: Remove BluetoothAdapterCallback. Simplify leScan Api App does not need to explicitly register/unregister callback bug 8599881 Change-Id: I18cfef14d7ddb344722945e657dcb959823b412b --- .../java/android/bluetooth/BluetoothAdapter.java | 422 +++++++++++++-------- 1 file changed, 257 insertions(+), 165 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 2e9c9e334d..3498bb8e47 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -20,7 +20,6 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.os.Binder; -import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.ParcelUuid; @@ -30,11 +29,14 @@ import android.util.Log; import android.util.Pair; import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.HashMap; import java.util.LinkedList; +import java.util.Map; import java.util.Random; import java.util.Set; import java.util.UUID; @@ -357,9 +359,7 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; private IBluetooth mService; - private Handler mServiceRecordHandler; - private BluetoothAdapterCallback mCallback; - private int mClientIf; + private final Map mLeScanClients; /** * Get a handle to the default local Bluetooth adapter. @@ -394,7 +394,7 @@ public final class BluetoothAdapter { mService = managerService.registerAdapter(mManagerCallback); } catch (RemoteException e) {Log.e(TAG, "", e);} mManagerService = managerService; - mServiceRecordHandler = null; + mLeScanClients = new HashMap(); } /** @@ -1409,72 +1409,38 @@ public final class BluetoothAdapter { } /** - * Register an callback to receive async results, such as LE scan result. + * Callback interface used to deliver LE scan results. * - *

This is an asynchronous call. The callback - * {@link BluetoothAdapterCallback#onCallbackRegistration} - * is used to notify success or failure if the function returns true. - * - *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param callback BluetootAdapter callback handler that will receive asynchronous callbacks. - * @return If true, the callback will be called to notify success or failure, - * false on immediate error - */ - public boolean registerCallback(BluetoothAdapterCallback callback) { - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - mCallback = callback; - UUID uuid = UUID.randomUUID(); - if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid); - - iGatt.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback); - return true; - } catch (RemoteException e) { - Log.e(TAG,"",e); - return false; - } - } - - /** - * Unregister the registered callback. - */ - public boolean unRegisterCallback(BluetoothAdapterCallback callback) { - if (callback != mCallback) return false; - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - - iGatt.unregisterClient(mClientIf); - return true; - } catch (RemoteException e) { - Log.e(TAG,"",e); - return false; - } + * @see #startLeScan(LeScanCallback) + * @see #startLeScan(UUID[], LeScanCallback) + */ + public interface LeScanCallback { + /** + * Callback reporting an LE device found during a device scan initiated + * by the {@link BluetoothAdapter#startLeScan} function. + * + * @param device Identifies the remote device + * @param rssi The RSSI value for the remote device as reported by the + * Bluetooth hardware. 0 if no RSSI value is available. + * @param scanRecord The content of the advertisement record offered by + * the remote device. + */ + public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); } /** * Starts a scan for Bluetooth LE devices. * *

Results of the scan are reported using the - * {@link BluetoothAdapterCallback#onLeScan} callback. + * {@link LeScanCallback#onLeScan} callback. * *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. * + * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully */ - public boolean startLeScan() { - if (DBG) Log.d(TAG, "startLeScan()"); - if (mClientIf == 0) return false; - - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - iGatt.startScan(mClientIf, false); - } catch (RemoteException e) { - Log.e(TAG,"",e); - return false; - } - - return true; + public boolean startLeScan(LeScanCallback callback) { + return startLeScan(null, callback); } /** @@ -1482,155 +1448,281 @@ public final class BluetoothAdapter { * advertise given services. * *

Devices which advertise all specified services are reported using the - * {@link BluetoothAdapterCallback#onLeScan} callback. + * {@link LeScanCallback#onLeScan} callback. * *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. * * @param serviceUuids Array of services to look for + * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully */ - public boolean startLeScan(UUID[] serviceUuids) { - if (DBG) Log.d(TAG, "startLeScan() - with UUIDs"); - if (mClientIf == 0) return false; + public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) { + if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids); - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length]; - for(int i = 0; i != uuids.length; ++i) { - uuids[i] = new ParcelUuid(serviceUuids[i]); - } - iGatt.startScanWithUuids(mClientIf, false, uuids); - } catch (RemoteException e) { - Log.e(TAG,"",e); + if (callback == null) { + if (DBG) Log.e(TAG, "startLeScan: null callback"); return false; } - return true; + synchronized(mLeScanClients) { + if (mLeScanClients.containsKey(callback)) { + if (DBG) Log.e(TAG, "LE Scan has already started"); + return false; + } + + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + UUID uuid = UUID.randomUUID(); + GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids); + + iGatt.registerClient(new ParcelUuid(uuid), wrapper); + if (wrapper.scanStarted()) { + mLeScanClients.put(callback, wrapper); + return true; + } + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + return false; } /** * Stops an ongoing Bluetooth LE device scan. * *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. - */ - public void stopLeScan() { - if (DBG) Log.d(TAG, "stopScan()"); - if (mClientIf == 0) return; - - try { - IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt(); - iGatt.stopScan(mClientIf, false); - } catch (RemoteException e) { - Log.e(TAG,"",e); + * + * @param callback used to identify which scan to stop + * must be the same handle used to start the scan + */ + public void stopLeScan(LeScanCallback callback) { + if (DBG) Log.d(TAG, "stopLeScan()"); + GattCallbackWrapper wrapper; + synchronized(mLeScanClients) { + wrapper = mLeScanClients.remove(callback); + if (wrapper == null) return; } + wrapper.stopLeScan(); } /** * Bluetooth GATT interface callbacks */ - private final IBluetoothGattCallback mBluetoothGattCallback = - new IBluetoothGattCallback.Stub() { - /** - * Application interface registered - app is ready to go - */ - public void onClientRegistered(int status, int clientIf) { - if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status - + " clientIf=" + clientIf); - mClientIf = clientIf; - mCallback.onCallbackRegistration(status == BluetoothGatt.GATT_SUCCESS ? - BluetoothAdapterCallback.CALLBACK_REGISTERED : - BluetoothAdapterCallback.CALLBACK_REGISTRATION_FAILURE); - } + private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub { + private static final int LE_CALLBACK_REG_TIMEOUT = 2000; + private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; + + private final LeScanCallback mLeScanCb; + // mLeHandle 0: not registered + // -1: scan stopped + // >0: registered and scan started + private int mLeHandle; + private final UUID[] mScanFilter; + private WeakReference mBluetoothAdapter; + + public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, + LeScanCallback leScanCb, UUID[] uuid) { + mBluetoothAdapter = new WeakReference(bluetoothAdapter); + mLeScanCb = leScanCb; + mScanFilter = uuid; + mLeHandle = 0; + } - public void onClientConnectionState(int status, int clientIf, - boolean connected, String address) { - // no op + public boolean scanStarted() { + boolean started = false; + synchronized(this) { + if (mLeHandle == -1) return false; + + int count = 0; + // wait for callback registration and LE scan to start + while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) { + try { + wait(LE_CALLBACK_REG_TIMEOUT); + } catch (InterruptedException e) { + Log.e(TAG, "Callback reg wait interrupted: " + e); + } + count++; + } + started = (mLeHandle > 0); } + return started; + } - /** - * Callback reporting an LE scan result. - * @hide - */ - public void onScanResult(String address, int rssi, byte[] advData) { - if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); - - try { - mCallback.onLeScan(getRemoteDevice(address), rssi, advData); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception: " + ex); + public void stopLeScan() { + synchronized(this) { + if (mLeHandle <= 0) { + Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); + return; + } + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + try { + IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); + iGatt.stopScan(mLeHandle, false); + iGatt.unregisterClient(mLeHandle); + } catch (RemoteException e) { + Log.e(TAG, "Failed to stop scan and unregister" + e); + } + } else { + Log.e(TAG, "stopLeScan, BluetoothAdapter is null"); } + mLeHandle = -1; + notifyAll(); } + } - public void onGetService(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid) { - // no op - } + /** + * Application interface registered - app is ready to go + */ + public void onClientRegistered(int status, int clientIf) { + if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status + + " clientIf=" + clientIf); + synchronized(this) { + if (mLeHandle == -1) { + if (DBG) Log.d(TAG, "onClientRegistered LE scan canceled"); + } - public void onGetIncludedService(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int inclSrvcType, int inclSrvcInstId, - ParcelUuid inclSrvcUuid) { - // no op + if (status == BluetoothGatt.GATT_SUCCESS) { + mLeHandle = clientIf; + IBluetoothGatt iGatt = null; + try { + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + iGatt = adapter.getBluetoothManager().getBluetoothGatt(); + if (mScanFilter == null) { + iGatt.startScan(mLeHandle, false); + } else { + ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; + for(int i = 0; i != uuids.length; ++i) { + uuids[i] = new ParcelUuid(mScanFilter[i]); + } + iGatt.startScanWithUuids(mLeHandle, false, uuids); + } + } else { + Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); + mLeHandle = -1; + } + } catch (RemoteException e) { + Log.e(TAG, "fail to start le scan: " + e); + mLeHandle = -1; + } + if (mLeHandle == -1) { + // registration succeeded but start scan failed + if (iGatt != null) { + try { + iGatt.unregisterClient(mLeHandle); + } catch (RemoteException e) { + Log.e(TAG, "fail to unregister callback: " + mLeHandle + + " error: " + e); + } + } + } + } else { + // registration failed + mLeHandle = -1; + } + notifyAll(); } + } - public void onGetCharacteristic(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - int charProps) { - // no op - } + public void onClientConnectionState(int status, int clientIf, + boolean connected, String address) { + // no op + } - public void onGetDescriptor(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - ParcelUuid descUuid) { - // no op - } + /** + * Callback reporting an LE scan result. + * @hide + */ + public void onScanResult(String address, int rssi, byte[] advData) { + if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); - public void onSearchComplete(String address, int status) { - // no op + // Check null in case the scan has been stopped + synchronized(this) { + if (mLeHandle <= 0) return; } - - public void onCharacteristicRead(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, byte[] value) { - // no op + try { + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter == null) { + Log.d(TAG, "onScanResult, BluetoothAdapter null"); + return; + } + mLeScanCb.onLeScan(adapter.getRemoteDevice(address), rssi, advData); + } catch (Exception ex) { + Log.w(TAG, "Unhandled exception: " + ex); } + } - public void onCharacteristicWrite(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid) { - // no op - } + public void onGetService(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid) { + // no op + } + + public void onGetIncludedService(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int inclSrvcType, int inclSrvcInstId, + ParcelUuid inclSrvcUuid) { + // no op + } - public void onNotify(String address, int srvcType, + public void onGetCharacteristic(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + int charProps) { + // no op + } + + public void onGetDescriptor(String address, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descUuid) { + // no op + } + + public void onSearchComplete(String address, int status) { + // no op + } + + public void onCharacteristicRead(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, byte[] value) { + // no op + } + + public void onCharacteristicWrite(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid) { + // no op + } + + public void onNotify(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, byte[] value) { - // no op - } + // no op + } - public void onDescriptorRead(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - ParcelUuid descrUuid, byte[] value) { - // no op - } + public void onDescriptorRead(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descrUuid, byte[] value) { + // no op + } - public void onDescriptorWrite(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - ParcelUuid descrUuid) { - // no op - } + public void onDescriptorWrite(String address, int status, int srvcType, + int srvcInstId, ParcelUuid srvcUuid, + int charInstId, ParcelUuid charUuid, + ParcelUuid descrUuid) { + // no op + } - public void onExecuteWrite(String address, int status) { - // no op - } + public void onExecuteWrite(String address, int status) { + // no op + } - public void onReadRemoteRssi(String address, int rssi, int status) { - // no op - } - }; + public void onReadRemoteRssi(String address, int rssi, int status) { + // no op + } + } } -- cgit v1.2.3 From 1438e9ec8b03589b2b9ec133f0bc298bcd49b72d Mon Sep 17 00:00:00 2001 From: Matthew Xie Date: Wed, 24 Apr 2013 17:51:37 -0700 Subject: Change permission of LE scan APIs from BLUETOOTH to BLUETOOTH_ADMIN bug 8667898 Change-Id: Iaff19fe72b16a96a6cf2f5b9140e369098567d2b --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3498bb8e47..cfbfb48d4a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1434,7 +1434,7 @@ public final class BluetoothAdapter { *

Results of the scan are reported using the * {@link LeScanCallback#onLeScan} callback. * - *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. * * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully @@ -1450,7 +1450,7 @@ public final class BluetoothAdapter { *

Devices which advertise all specified services are reported using the * {@link LeScanCallback#onLeScan} callback. * - *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. * * @param serviceUuids Array of services to look for * @param callback the callback LE scan results are delivered @@ -1490,7 +1490,7 @@ public final class BluetoothAdapter { /** * Stops an ongoing Bluetooth LE device scan. * - *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. * * @param callback used to identify which scan to stop * must be the same handle used to start the scan -- cgit v1.2.3 From c3ef4fc08a0381c13161d681fe7364d82876216a Mon Sep 17 00:00:00 2001 From: Matthew Xie Date: Wed, 8 May 2013 19:26:57 -0700 Subject: Donot bind to GATT service when BLE is not supported bug 8664724 Change-Id: I9b9222cd5877babcded73798a5d1ff13fd10e791 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index cfbfb48d4a..7ec73ef741 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1472,9 +1472,13 @@ public final class BluetoothAdapter { try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + return false; + } + UUID uuid = UUID.randomUUID(); GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids); - iGatt.registerClient(new ParcelUuid(uuid), wrapper); if (wrapper.scanStarted()) { mLeScanClients.put(callback, wrapper); -- cgit v1.2.3 From abb655872f7a950d640bbb78d14a0660f458db62 Mon Sep 17 00:00:00 2001 From: Matthew Xie Date: Wed, 29 May 2013 10:19:06 -0700 Subject: Update javadoc to give app write better guidence Update javadoc of close methods of GATT cliet and server Update javadoc of BluetoothAdapter bug 8963528 Change-Id: I45ec618fd495225ed11a6171f33bfdc218397d4c --- framework/java/android/bluetooth/BluetoothAdapter.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 7ec73ef741..79bb476cb2 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -47,17 +47,22 @@ import java.util.UUID; * device discovery, query a list of bonded (paired) devices, * instantiate a {@link BluetoothDevice} using a known MAC address, and create * a {@link BluetoothServerSocket} to listen for connection requests from other - * devices. + * devices, and start a scan for Bluetooth LE devices. * *

To get a {@link BluetoothAdapter} representing the local Bluetooth - * adapter, call the static {@link #getDefaultAdapter} method. + * adapter, when running on JELLY_BEAN_MR1 and below, call the + * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and + * higher, retrieve it through + * {@link android.content.Context#getSystemService} with + * {@link android.content.Context#BLUETOOTH_SERVICE}. * Fundamentally, this is your starting point for all * Bluetooth actions. Once you have the local adapter, you can get a set of * {@link BluetoothDevice} objects representing all paired devices with * {@link #getBondedDevices()}; start device discovery with * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to * listen for incoming connection requests with - * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}. + * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}; or start a scan for + * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. * *

Note: * Most methods require the {@link android.Manifest.permission#BLUETOOTH} -- cgit v1.2.3 From c27359e696d9dd4aa89d77d3eb85c79348a206b5 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 11 Jun 2013 14:13:09 -0700 Subject: Explicit locale when formatting machine strings. Bug: 9390451 Change-Id: I3581c53407554a1dffd541fb42b06d68f20a7be0 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 79bb476cb2..72ecda1211 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -36,6 +36,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.HashMap; import java.util.LinkedList; +import java.util.Locale; import java.util.Map; import java.util.Random; import java.util.Set; @@ -433,7 +434,7 @@ public final class BluetoothAdapter { if (address == null || address.length != 6) { throw new IllegalArgumentException("Bluetooth address must have 6 bytes"); } - return new BluetoothDevice(String.format("%02X:%02X:%02X:%02X:%02X:%02X", + return new BluetoothDevice(String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1], address[2], address[3], address[4], address[5])); } -- cgit v1.2.3 From ee66af1a828c8eaba3605d73c3d0cdae4ba7c1c2 Mon Sep 17 00:00:00 2001 From: Zhihai Xu Date: Mon, 10 Jun 2013 20:28:31 -0700 Subject: Add debug menu to enable btsnoop bug: 8059358 Change-Id: I2d5f13e68defefb92e0b11b749fe77ad67215f36 --- .../java/android/bluetooth/BluetoothAdapter.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 79bb476cb2..507554402c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -598,6 +598,25 @@ public final class BluetoothAdapter { return null; } + /** + * enable or disable Bluetooth HCI snoop log. + * + *

Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission + * + * @return true to indicate configure HCI log successfully, or false on + * immediate error + * @hide + */ + public boolean configHciSnoopLog(boolean enable) { + try { + synchronized(mManagerCallback) { + if (mService != null) return mService.configHciSnoopLog(enable); + } + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + /** * Get the UUIDs supported by the local Bluetooth adapter. * -- cgit v1.2.3 From 93aa2e43a01a8d908ad34c4de6bfcd037e4fbfee Mon Sep 17 00:00:00 2001 From: Andre Eisenbach Date: Mon, 8 Jul 2013 23:58:16 -0700 Subject: LE: Add instance ID to descriptors (1/4) If a remote devices offers multiple descriptors with the same UUID, the instance ID is used to differentiate between them. Change-Id: I0c36494c980c86abd23f9647196af8d59ef663e9 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 1ea13e1026..74d85c3080 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1704,7 +1704,7 @@ public final class BluetoothAdapter { public void onGetDescriptor(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, - ParcelUuid descUuid) { + int descInstId, ParcelUuid descUuid) { // no op } @@ -1734,14 +1734,14 @@ public final class BluetoothAdapter { public void onDescriptorRead(String address, int status, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, - ParcelUuid descrUuid, byte[] value) { + int descInstId, ParcelUuid descrUuid, byte[] value) { // no op } public void onDescriptorWrite(String address, int status, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, - ParcelUuid descrUuid) { + int descInstId, ParcelUuid descrUuid) { // no op } -- cgit v1.2.3 From 3b486eb57a332036e9c779020e1fc5921658b0a5 Mon Sep 17 00:00:00 2001 From: Andre Eisenbach Date: Tue, 6 Aug 2013 19:57:48 -0700 Subject: LE: Add peripheral role support (1/4) Initial stack support for the LE peripheral role. Change-Id: I6222493488822b4289b90888ccc97ad9306f54d1 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 74d85c3080..e062fa8b4e 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1752,6 +1752,10 @@ public final class BluetoothAdapter { public void onReadRemoteRssi(String address, int rssi, int status) { // no op } + + public void onListen(int status) { + // no op + } } } -- cgit v1.2.3 From 008ce9e07b5e58c5ab31c5d73ec3d1ad1a6cf605 Mon Sep 17 00:00:00 2001 From: Dmitry Grinberg Date: Fri, 9 Aug 2013 15:22:59 -0700 Subject: Allow L2CAP sockets Change-Id: Icb498e6c0430789b6168bec3beb1d4650e4f1238 --- .../java/android/bluetooth/BluetoothAdapter.java | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e062fa8b4e..676fd1f329 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -923,6 +923,42 @@ public final class BluetoothAdapter { return BluetoothProfile.STATE_DISCONNECTED; } + /** + * Create a listening, L2CAP Bluetooth socket. + *

A remote device connecting to this socket will optionally be + * authenticated and communication on this socket will optionally be + * encrypted. + *

Use {@link BluetoothServerSocket#accept} to retrieve incoming + * connections from a listening {@link BluetoothServerSocket}. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * @param secure whether security and authentication are required + * @param fixedChannel whether we're looking for a PSM-based connection or a fixed channel + * @param channel L2CAP PSM or channel to use + * @return a listening L2CAP BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or + * insufficient permissions, or channel in use. + * @hide + */ + public BluetoothServerSocket listenUsingL2CapOn(boolean secure, boolean fixedChannel, + int channel) throws IOException { + BluetoothServerSocket socket; + + if (fixedChannel) { + channel |= BluetoothSocket.PORT_MASK_FIXED_CHAN; + } + + socket = new BluetoothServerSocket( + BluetoothSocket.TYPE_L2CAP, secure, secure, channel); + int errno = socket.mSocket.bindListen(); + if (errno != 0) { + //TODO(BT): Throw the same exception error code + // that the previous code was using. + //socket.mSocket.throwErrnoNative(errno); + throw new IOException("Error: " + errno); + } + return socket; + } + /** * Create a listening, secure RFCOMM Bluetooth socket. *

A remote device connecting to this socket will be authenticated and -- cgit v1.2.3 From 6816ee2b6d6820a727b59d78b6892473efd42f98 Mon Sep 17 00:00:00 2001 From: Kim Schulz Date: Thu, 22 Aug 2013 11:18:02 +0200 Subject: Fixed review comments - fixed review comments (internal+google) - corrected tabs/spaces - Add connection id header for obex client operations - added support for implementing ProfileService class Change-Id: Idab8b4fa54a0f31bec4ffa263a69a9850a07f858 Bug:10692365 --- framework/java/android/bluetooth/BluetoothAdapter.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 676fd1f329..2172a7b206 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -27,7 +27,6 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Pair; - import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -51,7 +50,7 @@ import java.util.UUID; * devices, and start a scan for Bluetooth LE devices. * *

To get a {@link BluetoothAdapter} representing the local Bluetooth - * adapter, when running on JELLY_BEAN_MR1 and below, call the + * adapter, when running on JELLY_BEAN_MR1 and below, call the * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and * higher, retrieve it through * {@link android.content.Context#getSystemService} with @@ -1229,6 +1228,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.HEALTH) { BluetoothHealth health = new BluetoothHealth(context, listener); return true; + } else if (profile == BluetoothProfile.MAP) { + BluetoothMap map = new BluetoothMap(context, listener); + return true; } else { return false; } @@ -1277,6 +1279,10 @@ public final class BluetoothAdapter { BluetoothGattServer gattServer = (BluetoothGattServer)proxy; gattServer.close(); break; + case BluetoothProfile.MAP: + BluetoothMap map = (BluetoothMap)proxy; + map.close(); + break; } } -- cgit v1.2.3 From 9cffff7bd584bf1a49298dc645aa640f2c989a54 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 2 Oct 2013 07:56:46 -0700 Subject: Revert "Allow L2CAP sockets" This reverts commit 008ce9e07b5e58c5ab31c5d73ec3d1ad1a6cf605. --- .../java/android/bluetooth/BluetoothAdapter.java | 36 ---------------------- 1 file changed, 36 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 2172a7b206..e2bc80aad6 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -922,42 +922,6 @@ public final class BluetoothAdapter { return BluetoothProfile.STATE_DISCONNECTED; } - /** - * Create a listening, L2CAP Bluetooth socket. - *

A remote device connecting to this socket will optionally be - * authenticated and communication on this socket will optionally be - * encrypted. - *

Use {@link BluetoothServerSocket#accept} to retrieve incoming - * connections from a listening {@link BluetoothServerSocket}. - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * @param secure whether security and authentication are required - * @param fixedChannel whether we're looking for a PSM-based connection or a fixed channel - * @param channel L2CAP PSM or channel to use - * @return a listening L2CAP BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or - * insufficient permissions, or channel in use. - * @hide - */ - public BluetoothServerSocket listenUsingL2CapOn(boolean secure, boolean fixedChannel, - int channel) throws IOException { - BluetoothServerSocket socket; - - if (fixedChannel) { - channel |= BluetoothSocket.PORT_MASK_FIXED_CHAN; - } - - socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_L2CAP, secure, secure, channel); - int errno = socket.mSocket.bindListen(); - if (errno != 0) { - //TODO(BT): Throw the same exception error code - // that the previous code was using. - //socket.mSocket.throwErrnoNative(errno); - throw new IOException("Error: " + errno); - } - return socket; - } - /** * Create a listening, secure RFCOMM Bluetooth socket. *

A remote device connecting to this socket will be authenticated and -- cgit v1.2.3 From 9c530c2e37aa238af783db1f1715a60b4b74b02d Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Tue, 19 Nov 2013 16:54:46 -0500 Subject: Remove unused imports from frameworks/base. Change-Id: Ia1f99bd2c1105b0b0f70aa614f1f4a67b2840906 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ---- 1 file changed, 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e2bc80aad6..7ee231338f 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -19,9 +19,7 @@ package android.bluetooth; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; -import android.os.Binder; import android.os.IBinder; -import android.os.Message; import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceManager; @@ -34,10 +32,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.HashMap; -import java.util.LinkedList; import java.util.Locale; import java.util.Map; -import java.util.Random; import java.util.Set; import java.util.UUID; -- cgit v1.2.3 From 2f7544ce3f0c2e0697318e9961c4ced457b71d5f Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 29 Oct 2013 21:05:37 -0700 Subject: BLE peripheral mode (3/4): Add peripheral mode API. Change-Id: Id9d2f566b6d9ed0fffe73b67efad2e3d045360b4 Conflicts: core/java/android/bluetooth/BluetoothAdapter.java core/java/android/bluetooth/BluetoothGatt.java --- .../java/android/bluetooth/BluetoothAdapter.java | 209 ++++++++++++++++++++- 1 file changed, 199 insertions(+), 10 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 7ee231338f..38a71aaa25 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -25,13 +25,14 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Pair; + import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.HashMap; +import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -178,6 +179,43 @@ public final class BluetoothAdapter { public static final String EXTRA_DISCOVERABLE_DURATION = "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; + /** + * Activity Action: Show a system activity to request BLE advertising.
+ * If the device is not doing BLE advertising, this activity will start BLE advertising for the + * device, otherwise it will continue BLE advertising using the current + * {@link BluetoothAdvScanData}.
+ * Note this activity will also request the user to turn on Bluetooth if it's not currently + * enabled. + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_START_ADVERTISING = + "android.bluetooth.adapter.action.START_ADVERTISING"; + + /** + * Activity Action: Stop the current BLE advertising. + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_STOP_ADVERTISING = + "android.bluetooth.adapter.action.STOP_ADVERTISING"; + + /** + * Broadcast Action: Indicate BLE Advertising is started. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STARTED = + "android.bluetooth.adapter.action.ADVERTISING_STARTED"; + + /** + * Broadcast Action: Indicated BLE Advertising is stopped. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STOPPED = + "android.bluetooth.adapter.action.ADVERTISING_STOPPED"; + /** * Activity Action: Show a system activity that allows the user to turn on * Bluetooth. @@ -247,7 +285,6 @@ public final class BluetoothAdapter { */ public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; - /** * Broadcast Action: The local Bluetooth adapter has started the remote * device discovery process. @@ -361,6 +398,8 @@ public final class BluetoothAdapter { private IBluetooth mService; private final Map mLeScanClients; + private BluetoothAdvScanData mBluetoothAdvScanData = null; + private GattCallbackWrapper mAdvertisingCallback; /** * Get a handle to the default local Bluetooth adapter. @@ -433,6 +472,97 @@ public final class BluetoothAdapter { address[0], address[1], address[2], address[3], address[4], address[5])); } + /** + * Returns a {@link BluetoothAdvScanData} object representing advertising data. + * @hide + */ + public BluetoothAdvScanData getAdvScanData() { + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + Log.e(TAG, "failed to start, iGatt null"); + return null; + } + if (mBluetoothAdvScanData == null) { + mBluetoothAdvScanData = new BluetoothAdvScanData(iGatt, BluetoothAdvScanData.AD); + } + return mBluetoothAdvScanData; + } catch (RemoteException e) { + Log.e(TAG, "failed to get advScanData, error: " + e); + return null; + } + } + + + /** + * Start BLE advertising using current {@link BluetoothAdvScanData}. + * An app should start advertising by requesting + * {@link BluetoothAdapter#ACTION_START_ADVERTISING} instead of calling this method directly. + *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * + * @return true if BLE avertising succeeds, false otherwise. + * @hide + */ + public boolean startAdvertising() { + if (getState() != STATE_ON) return false; + + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported. + return false; + } + // Restart/reset advertising packets if advertising is in progress. + if (isAdvertising()) { + // Invalid advertising callback. + if (mAdvertisingCallback == null || mAdvertisingCallback.mLeHandle == -1) { + Log.e(TAG, "failed to restart advertising, invalid callback"); + return false; + } + iGatt.startAdvertising(mAdvertisingCallback.mLeHandle); + return true; + } + UUID uuid = UUID.randomUUID(); + GattCallbackWrapper wrapper = + new GattCallbackWrapper(this, null, null, GattCallbackWrapper.CALLBACK_TYPE_ADV); + iGatt.registerClient(new ParcelUuid(uuid), wrapper); + mAdvertisingCallback = wrapper; + return true; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + + /** + * Stop BLE advertising. + * An app should stop advertising by requesting + * {@link BluetoothAdapter#ACTION_STOP_ADVERTISING} instead of calling this method directly. + *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * @return true if BLE advertising stops, false otherwise. + * @hide + */ + public boolean stopAdvertisting() { + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + return false; + } + if (mAdvertisingCallback == null) { + // no callback. + return false; + } + mAdvertisingCallback.stopAdvertising(); + mAdvertisingCallback = null; + return true; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + /** * Return true if Bluetooth is currently enabled and ready for use. *

Equivalent to: @@ -844,6 +974,23 @@ public final class BluetoothAdapter { return false; } + /** + * Returns whether BLE is currently advertising. + *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. + * + * @hide + */ + public boolean isAdvertising() { + if (getState() != STATE_ON) return false; + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + return iGatt.isAdvertising(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + return false; + } + /** * Return the set of {@link BluetoothDevice} objects that are bonded * (paired) to the local adapter. @@ -1542,8 +1689,12 @@ public final class BluetoothAdapter { private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub { private static final int LE_CALLBACK_REG_TIMEOUT = 2000; private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; + private static final int CALLBACK_TYPE_SCAN = 0; + private static final int CALLBACK_TYPE_ADV = 1; private final LeScanCallback mLeScanCb; + private int mCallbackType; + // mLeHandle 0: not registered // -1: scan stopped // >0: registered and scan started @@ -1557,6 +1708,16 @@ public final class BluetoothAdapter { mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; + mCallbackType = CALLBACK_TYPE_SCAN; + } + + public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, LeScanCallback leScanCb, + UUID[] uuid, int type) { + mBluetoothAdapter = new WeakReference(bluetoothAdapter); + mLeScanCb = leScanCb; + mScanFilter = uuid; + mLeHandle = 0; + mCallbackType = type; } public boolean scanStarted() { @@ -1579,6 +1740,30 @@ public final class BluetoothAdapter { return started; } + public void stopAdvertising() { + synchronized (this) { + if (mLeHandle <= 0) { + Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); + return; + } + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + try { + IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); + iGatt.stopAdvertising(); + Log.d(TAG, "unregeistering client " + mLeHandle); + iGatt.unregisterClient(mLeHandle); + } catch (RemoteException e) { + Log.e(TAG, "Failed to stop advertising and unregister" + e); + } + } else { + Log.e(TAG, "stopAdvertising, BluetoothAdapter is null"); + } + mLeHandle = -1; + notifyAll(); + } + } + public void stopLeScan() { synchronized(this) { if (mLeHandle <= 0) { @@ -1620,14 +1805,18 @@ public final class BluetoothAdapter { BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - if (mScanFilter == null) { - iGatt.startScan(mLeHandle, false); + if (mCallbackType == CALLBACK_TYPE_ADV) { + iGatt.startAdvertising(mLeHandle); } else { - ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; - for(int i = 0; i != uuids.length; ++i) { - uuids[i] = new ParcelUuid(mScanFilter[i]); - } - iGatt.startScanWithUuids(mLeHandle, false, uuids); + if (mScanFilter == null) { + iGatt.startScan(mLeHandle, false); + } else { + ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; + for(int i = 0; i != uuids.length; ++i) { + uuids[i] = new ParcelUuid(mScanFilter[i]); + } + iGatt.startScanWithUuids(mLeHandle, false, uuids); + } } } else { Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); @@ -1638,7 +1827,7 @@ public final class BluetoothAdapter { mLeHandle = -1; } if (mLeHandle == -1) { - // registration succeeded but start scan failed + // registration succeeded but start scan or advertise failed if (iGatt != null) { try { iGatt.unregisterClient(mLeHandle); -- cgit v1.2.3 From 3364fc19ce4cb908b4e157a76297b29da8b7d927 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 29 Oct 2013 21:05:37 -0700 Subject: DO NOT MERGE BLE peripheral mode (3/4): Add peripheral mode API. Add bluetooth adv data, APIs in BluetoothAdpater etc. Cherry picking ble advertising changes from master to KLP MR2. b/13137996 Change-Id: Id9d2f566b6d9ed0fffe73b67efad2e3d045360b4 Conflicts: core/java/android/bluetooth/BluetoothAdapter.java core/java/android/bluetooth/BluetoothGatt.java Conflicts: core/java/android/bluetooth/BluetoothAdapter.java --- .../java/android/bluetooth/BluetoothAdapter.java | 210 +++++++++++++++++++-- 1 file changed, 199 insertions(+), 11 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e2bc80aad6..d1f1f2af44 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -27,14 +27,14 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Pair; + import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.HashMap; -import java.util.LinkedList; +import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Random; @@ -182,6 +182,43 @@ public final class BluetoothAdapter { public static final String EXTRA_DISCOVERABLE_DURATION = "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; + /** + * Activity Action: Show a system activity to request BLE advertising.
+ * If the device is not doing BLE advertising, this activity will start BLE advertising for the + * device, otherwise it will continue BLE advertising using the current + * {@link BluetoothAdvScanData}.
+ * Note this activity will also request the user to turn on Bluetooth if it's not currently + * enabled. + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_START_ADVERTISING = + "android.bluetooth.adapter.action.START_ADVERTISING"; + + /** + * Activity Action: Stop the current BLE advertising. + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_STOP_ADVERTISING = + "android.bluetooth.adapter.action.STOP_ADVERTISING"; + + /** + * Broadcast Action: Indicate BLE Advertising is started. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STARTED = + "android.bluetooth.adapter.action.ADVERTISING_STARTED"; + + /** + * Broadcast Action: Indicated BLE Advertising is stopped. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STOPPED = + "android.bluetooth.adapter.action.ADVERTISING_STOPPED"; + /** * Activity Action: Show a system activity that allows the user to turn on * Bluetooth. @@ -251,7 +288,6 @@ public final class BluetoothAdapter { */ public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; - /** * Broadcast Action: The local Bluetooth adapter has started the remote * device discovery process. @@ -365,6 +401,8 @@ public final class BluetoothAdapter { private IBluetooth mService; private final Map mLeScanClients; + private BluetoothAdvScanData mBluetoothAdvScanData = null; + private GattCallbackWrapper mAdvertisingCallback; /** * Get a handle to the default local Bluetooth adapter. @@ -437,6 +475,97 @@ public final class BluetoothAdapter { address[0], address[1], address[2], address[3], address[4], address[5])); } + /** + * Returns a {@link BluetoothAdvScanData} object representing advertising data. + * @hide + */ + public BluetoothAdvScanData getAdvScanData() { + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + Log.e(TAG, "failed to start, iGatt null"); + return null; + } + if (mBluetoothAdvScanData == null) { + mBluetoothAdvScanData = new BluetoothAdvScanData(iGatt, BluetoothAdvScanData.AD); + } + return mBluetoothAdvScanData; + } catch (RemoteException e) { + Log.e(TAG, "failed to get advScanData, error: " + e); + return null; + } + } + + + /** + * Start BLE advertising using current {@link BluetoothAdvScanData}. + * An app should start advertising by requesting + * {@link BluetoothAdapter#ACTION_START_ADVERTISING} instead of calling this method directly. + *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * + * @return true if BLE avertising succeeds, false otherwise. + * @hide + */ + public boolean startAdvertising() { + if (getState() != STATE_ON) return false; + + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported. + return false; + } + // Restart/reset advertising packets if advertising is in progress. + if (isAdvertising()) { + // Invalid advertising callback. + if (mAdvertisingCallback == null || mAdvertisingCallback.mLeHandle == -1) { + Log.e(TAG, "failed to restart advertising, invalid callback"); + return false; + } + iGatt.startAdvertising(mAdvertisingCallback.mLeHandle); + return true; + } + UUID uuid = UUID.randomUUID(); + GattCallbackWrapper wrapper = + new GattCallbackWrapper(this, null, null, GattCallbackWrapper.CALLBACK_TYPE_ADV); + iGatt.registerClient(new ParcelUuid(uuid), wrapper); + mAdvertisingCallback = wrapper; + return true; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + + /** + * Stop BLE advertising. + * An app should stop advertising by requesting + * {@link BluetoothAdapter#ACTION_STOP_ADVERTISING} instead of calling this method directly. + *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * @return true if BLE advertising stops, false otherwise. + * @hide + */ + public boolean stopAdvertisting() { + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + return false; + } + if (mAdvertisingCallback == null) { + // no callback. + return false; + } + mAdvertisingCallback.stopAdvertising(); + mAdvertisingCallback = null; + return true; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + /** * Return true if Bluetooth is currently enabled and ready for use. *

Equivalent to: @@ -848,6 +977,23 @@ public final class BluetoothAdapter { return false; } + /** + * Returns whether BLE is currently advertising. + *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. + * + * @hide + */ + public boolean isAdvertising() { + if (getState() != STATE_ON) return false; + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + return iGatt.isAdvertising(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + return false; + } + /** * Return the set of {@link BluetoothDevice} objects that are bonded * (paired) to the local adapter. @@ -1546,8 +1692,12 @@ public final class BluetoothAdapter { private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub { private static final int LE_CALLBACK_REG_TIMEOUT = 2000; private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; + private static final int CALLBACK_TYPE_SCAN = 0; + private static final int CALLBACK_TYPE_ADV = 1; private final LeScanCallback mLeScanCb; + private int mCallbackType; + // mLeHandle 0: not registered // -1: scan stopped // >0: registered and scan started @@ -1561,6 +1711,16 @@ public final class BluetoothAdapter { mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; + mCallbackType = CALLBACK_TYPE_SCAN; + } + + public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, LeScanCallback leScanCb, + UUID[] uuid, int type) { + mBluetoothAdapter = new WeakReference(bluetoothAdapter); + mLeScanCb = leScanCb; + mScanFilter = uuid; + mLeHandle = 0; + mCallbackType = type; } public boolean scanStarted() { @@ -1583,6 +1743,30 @@ public final class BluetoothAdapter { return started; } + public void stopAdvertising() { + synchronized (this) { + if (mLeHandle <= 0) { + Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); + return; + } + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + try { + IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); + iGatt.stopAdvertising(); + Log.d(TAG, "unregeistering client " + mLeHandle); + iGatt.unregisterClient(mLeHandle); + } catch (RemoteException e) { + Log.e(TAG, "Failed to stop advertising and unregister" + e); + } + } else { + Log.e(TAG, "stopAdvertising, BluetoothAdapter is null"); + } + mLeHandle = -1; + notifyAll(); + } + } + public void stopLeScan() { synchronized(this) { if (mLeHandle <= 0) { @@ -1624,14 +1808,18 @@ public final class BluetoothAdapter { BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - if (mScanFilter == null) { - iGatt.startScan(mLeHandle, false); + if (mCallbackType == CALLBACK_TYPE_ADV) { + iGatt.startAdvertising(mLeHandle); } else { - ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; - for(int i = 0; i != uuids.length; ++i) { - uuids[i] = new ParcelUuid(mScanFilter[i]); - } - iGatt.startScanWithUuids(mLeHandle, false, uuids); + if (mScanFilter == null) { + iGatt.startScan(mLeHandle, false); + } else { + ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; + for(int i = 0; i != uuids.length; ++i) { + uuids[i] = new ParcelUuid(mScanFilter[i]); + } + iGatt.startScanWithUuids(mLeHandle, false, uuids); + } } } else { Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); @@ -1642,7 +1830,7 @@ public final class BluetoothAdapter { mLeHandle = -1; } if (mLeHandle == -1) { - // registration succeeded but start scan failed + // registration succeeded but start scan or advertise failed if (iGatt != null) { try { iGatt.unregisterClient(mLeHandle); -- cgit v1.2.3 From ff51763220f24d110fdf5f48565219410fe02670 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 11 Mar 2014 22:22:41 -0700 Subject: Add status callback for start/stop advertising. Fixes b/13289050, b/13418851, also fixes 13418671. Change-Id: I231ba51aaa67b1f917e476ef0f2c8f82c762df77 --- .../java/android/bluetooth/BluetoothAdapter.java | 183 +++++++++++++-------- 1 file changed, 115 insertions(+), 68 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 38a71aaa25..8aee4db08c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -19,7 +19,9 @@ package android.bluetooth; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceManager; @@ -179,43 +181,6 @@ public final class BluetoothAdapter { public static final String EXTRA_DISCOVERABLE_DURATION = "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; - /** - * Activity Action: Show a system activity to request BLE advertising.
- * If the device is not doing BLE advertising, this activity will start BLE advertising for the - * device, otherwise it will continue BLE advertising using the current - * {@link BluetoothAdvScanData}.
- * Note this activity will also request the user to turn on Bluetooth if it's not currently - * enabled. - * @hide - */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_START_ADVERTISING = - "android.bluetooth.adapter.action.START_ADVERTISING"; - - /** - * Activity Action: Stop the current BLE advertising. - * @hide - */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_STOP_ADVERTISING = - "android.bluetooth.adapter.action.STOP_ADVERTISING"; - - /** - * Broadcast Action: Indicate BLE Advertising is started. - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_BLUETOOTH_ADVERTISING_STARTED = - "android.bluetooth.adapter.action.ADVERTISING_STARTED"; - - /** - * Broadcast Action: Indicated BLE Advertising is stopped. - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_BLUETOOTH_ADVERTISING_STOPPED = - "android.bluetooth.adapter.action.ADVERTISING_STOPPED"; - /** * Activity Action: Show a system activity that allows the user to turn on * Bluetooth. @@ -247,6 +212,22 @@ public final class BluetoothAdapter { public static final String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; + /** + * Broadcast Action: Indicate BLE Advertising is started. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STARTED = + "android.bluetooth.adapter.action.ADVERTISING_STARTED"; + + /** + * Broadcast Action: Indicated BLE Advertising is stopped. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STOPPED = + "android.bluetooth.adapter.action.ADVERTISING_STOPPED"; + /** * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} * intents to request the current scan mode. Possible values are: @@ -383,9 +364,27 @@ public final class BluetoothAdapter { /** The profile is in disconnecting state */ public static final int STATE_DISCONNECTING = 3; + /** States for Bluetooth LE advertising */ + /** @hide */ + public static final int STATE_ADVERTISE_STARTING = 0; + /** @hide */ + public static final int STATE_ADVERTISE_STARTED = 1; + /** @hide */ + public static final int STATE_ADVERTISE_STOPPING = 2; + /** @hide */ + public static final int STATE_ADVERTISE_STOPPED = 3; + /** + * Force stopping advertising without callback in case the advertising app dies. + * @hide + */ + public static final int STATE_ADVERTISE_FORCE_STOPPING = 4; + /** @hide */ public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; + /** @hide */ + public static final int ADVERTISE_CALLBACK_SUCCESS = 0; + private static final int ADDRESS_LENGTH = 17; /** @@ -399,7 +398,9 @@ public final class BluetoothAdapter { private final Map mLeScanClients; private BluetoothAdvScanData mBluetoothAdvScanData = null; - private GattCallbackWrapper mAdvertisingCallback; + private GattCallbackWrapper mAdvertisingGattCallback; + private final Handler mHandler; // Handler to post the advertise callback to run on main thread. + private final Object mLock = new Object(); /** * Get a handle to the default local Bluetooth adapter. @@ -435,6 +436,7 @@ public final class BluetoothAdapter { } catch (RemoteException e) {Log.e(TAG, "", e);} mManagerService = managerService; mLeScanClients = new HashMap(); + mHandler = new Handler(Looper.getMainLooper()); } /** @@ -474,6 +476,7 @@ public final class BluetoothAdapter { /** * Returns a {@link BluetoothAdvScanData} object representing advertising data. + * Data will be reset when bluetooth service is turned off. * @hide */ public BluetoothAdvScanData getAdvScanData() { @@ -494,19 +497,34 @@ public final class BluetoothAdapter { } } + /** + * Interface for BLE advertising callback. + * + * @hide + */ + public interface AdvertiseCallback { + /** + * Callback when advertise starts. + * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure. + */ + void onAdvertiseStart(int status); + /** + * Callback when advertise stops. + * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure. + */ + void onAdvertiseStop(int status); + } /** * Start BLE advertising using current {@link BluetoothAdvScanData}. - * An app should start advertising by requesting - * {@link BluetoothAdapter#ACTION_START_ADVERTISING} instead of calling this method directly. *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} * - * @return true if BLE avertising succeeds, false otherwise. + * @param callback - {@link AdvertiseCallback} + * @return true if BLE advertising succeeds, false otherwise. * @hide */ - public boolean startAdvertising() { + public boolean startAdvertising(final AdvertiseCallback callback) { if (getState() != STATE_ON) return false; - try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); if (iGatt == null) { @@ -516,18 +534,31 @@ public final class BluetoothAdapter { // Restart/reset advertising packets if advertising is in progress. if (isAdvertising()) { // Invalid advertising callback. - if (mAdvertisingCallback == null || mAdvertisingCallback.mLeHandle == -1) { + if (mAdvertisingGattCallback == null || mAdvertisingGattCallback.mLeHandle == -1) { Log.e(TAG, "failed to restart advertising, invalid callback"); return false; } - iGatt.startAdvertising(mAdvertisingCallback.mLeHandle); + iGatt.startAdvertising(mAdvertisingGattCallback.mLeHandle); + // Run the callback from main thread. + mHandler.post(new Runnable() { + @Override + public void run() { + // callback with status success. + callback.onAdvertiseStart(ADVERTISE_CALLBACK_SUCCESS); + } + }); return true; } UUID uuid = UUID.randomUUID(); GattCallbackWrapper wrapper = - new GattCallbackWrapper(this, null, null, GattCallbackWrapper.CALLBACK_TYPE_ADV); + new GattCallbackWrapper(this, null, null, callback); iGatt.registerClient(new ParcelUuid(uuid), wrapper); - mAdvertisingCallback = wrapper; + if (!wrapper.advertiseStarted()) { + return false; + } + synchronized (mLock) { + mAdvertisingGattCallback = wrapper; + } return true; } catch (RemoteException e) { Log.e(TAG, "", e); @@ -537,25 +568,29 @@ public final class BluetoothAdapter { /** * Stop BLE advertising. - * An app should stop advertising by requesting - * {@link BluetoothAdapter#ACTION_STOP_ADVERTISING} instead of calling this method directly. - *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * + * @param callback - {@link AdvertiseCallback} * @return true if BLE advertising stops, false otherwise. * @hide */ - public boolean stopAdvertisting() { + public boolean stopAdvertising(AdvertiseCallback callback) { try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); if (iGatt == null) { // BLE is not supported return false; } - if (mAdvertisingCallback == null) { + if (mAdvertisingGattCallback == null) { // no callback. return false; } - mAdvertisingCallback.stopAdvertising(); - mAdvertisingCallback = null; + // Make sure same callback is used for start and stop advertising. + if (callback != mAdvertisingGattCallback.mAdvertiseCallback) { + Log.e(TAG, "must use the same callback for star/stop advertising"); + return false; + } + mAdvertisingGattCallback.stopAdvertising(); + mAdvertisingGattCallback = null; return true; } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1415,6 +1450,8 @@ public final class BluetoothAdapter { if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); synchronized (mManagerCallback) { mService = null; + // Reset bluetooth adv scan data when Gatt service is down. + mBluetoothAdvScanData = null; for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ try { if (cb != null) { @@ -1689,11 +1726,9 @@ public final class BluetoothAdapter { private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub { private static final int LE_CALLBACK_REG_TIMEOUT = 2000; private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; - private static final int CALLBACK_TYPE_SCAN = 0; - private static final int CALLBACK_TYPE_ADV = 1; + private final AdvertiseCallback mAdvertiseCallback; private final LeScanCallback mLeScanCb; - private int mCallbackType; // mLeHandle 0: not registered // -1: scan stopped @@ -1708,26 +1743,34 @@ public final class BluetoothAdapter { mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; - mCallbackType = CALLBACK_TYPE_SCAN; + mAdvertiseCallback = null; } public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, LeScanCallback leScanCb, - UUID[] uuid, int type) { + UUID[] uuid, AdvertiseCallback callback) { mBluetoothAdapter = new WeakReference(bluetoothAdapter); mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; - mCallbackType = type; + mAdvertiseCallback = callback; } public boolean scanStarted() { + return waitForRegisteration(LE_CALLBACK_REG_WAIT_COUNT); + } + + public boolean advertiseStarted() { + // Wait for registeration callback. + return waitForRegisteration(1); + } + + private boolean waitForRegisteration(int maxWaitCount) { boolean started = false; synchronized(this) { if (mLeHandle == -1) return false; - int count = 0; // wait for callback registration and LE scan to start - while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) { + while (mLeHandle == 0 && count < maxWaitCount) { try { wait(LE_CALLBACK_REG_TIMEOUT); } catch (InterruptedException e) { @@ -1751,7 +1794,7 @@ public final class BluetoothAdapter { try { IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); iGatt.stopAdvertising(); - Log.d(TAG, "unregeistering client " + mLeHandle); + Log.d(TAG, "unregistering client " + mLeHandle); iGatt.unregisterClient(mLeHandle); } catch (RemoteException e) { Log.e(TAG, "Failed to stop advertising and unregister" + e); @@ -1805,7 +1848,7 @@ public final class BluetoothAdapter { BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - if (mCallbackType == CALLBACK_TYPE_ADV) { + if (mAdvertiseCallback != null) { iGatt.startAdvertising(mLeHandle); } else { if (mScanFilter == null) { @@ -1855,7 +1898,7 @@ public final class BluetoothAdapter { * @hide */ public void onScanResult(String address, int rssi, byte[] advData) { - if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); + if (VDBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); // Check null in case the scan has been stopped synchronized(this) { @@ -1944,9 +1987,13 @@ public final class BluetoothAdapter { // no op } - public void onListen(int status) { - // no op + public void onAdvertiseStateChange(int advertiseState, int status) { + Log.d(TAG, "on advertise call back, state: " + advertiseState + " status: " + status); + if (advertiseState == STATE_ADVERTISE_STARTED) { + mAdvertiseCallback.onAdvertiseStart(status); + } else { + mAdvertiseCallback.onAdvertiseStop(status); + } } } - } -- cgit v1.2.3 From a00d04bb647962db3dcdfc891cbc58b4bc00a708 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 19 Mar 2014 15:47:12 -0700 Subject: Move advetise clean up to callback code. fixes b/13289050 Change-Id: Ibf3c772561125821817c947730cf21defafd4cb2 --- .../java/android/bluetooth/BluetoothAdapter.java | 26 +++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8aee4db08c..a4374b86f1 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -590,7 +590,6 @@ public final class BluetoothAdapter { return false; } mAdvertisingGattCallback.stopAdvertising(); - mAdvertisingGattCallback = null; return true; } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1794,15 +1793,12 @@ public final class BluetoothAdapter { try { IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); iGatt.stopAdvertising(); - Log.d(TAG, "unregistering client " + mLeHandle); - iGatt.unregisterClient(mLeHandle); } catch (RemoteException e) { - Log.e(TAG, "Failed to stop advertising and unregister" + e); + Log.e(TAG, "Failed to stop advertising" + e); } } else { Log.e(TAG, "stopAdvertising, BluetoothAdapter is null"); } - mLeHandle = -1; notifyAll(); } } @@ -1992,6 +1988,26 @@ public final class BluetoothAdapter { if (advertiseState == STATE_ADVERTISE_STARTED) { mAdvertiseCallback.onAdvertiseStart(status); } else { + synchronized (this) { + if (status == ADVERTISE_CALLBACK_SUCCESS) { + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + try { + IBluetoothGatt iGatt = + adapter.getBluetoothManager().getBluetoothGatt(); + Log.d(TAG, "unregistering client " + mLeHandle); + iGatt.unregisterClient(mLeHandle); + // Reset advertise app handle. + mLeHandle = -1; + adapter.mAdvertisingGattCallback = null; + } catch (RemoteException e) { + Log.e(TAG, "Failed to unregister client" + e); + } + } else { + Log.e(TAG, "cannot unregister client, BluetoothAdapter is null"); + } + } + } mAdvertiseCallback.onAdvertiseStop(status); } } -- cgit v1.2.3 From abbeba65561fa82434c82964dc06e5fdb5b4d307 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 11 Mar 2014 22:22:41 -0700 Subject: DO NOT MERGE: Add status callback for start/stop advertising. Cherrypick from master to fix b/13289050 Change-Id: I231ba51aaa67b1f917e476ef0f2c8f82c762df77 Conflicts: core/java/android/bluetooth/BluetoothAdapter.java core/java/android/bluetooth/BluetoothGatt.java --- .../java/android/bluetooth/BluetoothAdapter.java | 183 +++++++++++++-------- 1 file changed, 115 insertions(+), 68 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index d1f1f2af44..f973d843ea 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -20,7 +20,9 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.ParcelUuid; import android.os.RemoteException; @@ -182,43 +184,6 @@ public final class BluetoothAdapter { public static final String EXTRA_DISCOVERABLE_DURATION = "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; - /** - * Activity Action: Show a system activity to request BLE advertising.
- * If the device is not doing BLE advertising, this activity will start BLE advertising for the - * device, otherwise it will continue BLE advertising using the current - * {@link BluetoothAdvScanData}.
- * Note this activity will also request the user to turn on Bluetooth if it's not currently - * enabled. - * @hide - */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_START_ADVERTISING = - "android.bluetooth.adapter.action.START_ADVERTISING"; - - /** - * Activity Action: Stop the current BLE advertising. - * @hide - */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_STOP_ADVERTISING = - "android.bluetooth.adapter.action.STOP_ADVERTISING"; - - /** - * Broadcast Action: Indicate BLE Advertising is started. - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_BLUETOOTH_ADVERTISING_STARTED = - "android.bluetooth.adapter.action.ADVERTISING_STARTED"; - - /** - * Broadcast Action: Indicated BLE Advertising is stopped. - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_BLUETOOTH_ADVERTISING_STOPPED = - "android.bluetooth.adapter.action.ADVERTISING_STOPPED"; - /** * Activity Action: Show a system activity that allows the user to turn on * Bluetooth. @@ -250,6 +215,22 @@ public final class BluetoothAdapter { public static final String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; + /** + * Broadcast Action: Indicate BLE Advertising is started. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STARTED = + "android.bluetooth.adapter.action.ADVERTISING_STARTED"; + + /** + * Broadcast Action: Indicated BLE Advertising is stopped. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STOPPED = + "android.bluetooth.adapter.action.ADVERTISING_STOPPED"; + /** * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} * intents to request the current scan mode. Possible values are: @@ -386,9 +367,27 @@ public final class BluetoothAdapter { /** The profile is in disconnecting state */ public static final int STATE_DISCONNECTING = 3; + /** States for Bluetooth LE advertising */ + /** @hide */ + public static final int STATE_ADVERTISE_STARTING = 0; + /** @hide */ + public static final int STATE_ADVERTISE_STARTED = 1; + /** @hide */ + public static final int STATE_ADVERTISE_STOPPING = 2; + /** @hide */ + public static final int STATE_ADVERTISE_STOPPED = 3; + /** + * Force stopping advertising without callback in case the advertising app dies. + * @hide + */ + public static final int STATE_ADVERTISE_FORCE_STOPPING = 4; + /** @hide */ public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; + /** @hide */ + public static final int ADVERTISE_CALLBACK_SUCCESS = 0; + private static final int ADDRESS_LENGTH = 17; /** @@ -402,7 +401,9 @@ public final class BluetoothAdapter { private final Map mLeScanClients; private BluetoothAdvScanData mBluetoothAdvScanData = null; - private GattCallbackWrapper mAdvertisingCallback; + private GattCallbackWrapper mAdvertisingGattCallback; + private final Handler mHandler; // Handler to post the advertise callback to run on main thread. + private final Object mLock = new Object(); /** * Get a handle to the default local Bluetooth adapter. @@ -438,6 +439,7 @@ public final class BluetoothAdapter { } catch (RemoteException e) {Log.e(TAG, "", e);} mManagerService = managerService; mLeScanClients = new HashMap(); + mHandler = new Handler(Looper.getMainLooper()); } /** @@ -477,6 +479,7 @@ public final class BluetoothAdapter { /** * Returns a {@link BluetoothAdvScanData} object representing advertising data. + * Data will be reset when bluetooth service is turned off. * @hide */ public BluetoothAdvScanData getAdvScanData() { @@ -497,19 +500,34 @@ public final class BluetoothAdapter { } } + /** + * Interface for BLE advertising callback. + * + * @hide + */ + public interface AdvertiseCallback { + /** + * Callback when advertise starts. + * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure. + */ + void onAdvertiseStart(int status); + /** + * Callback when advertise stops. + * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure. + */ + void onAdvertiseStop(int status); + } /** * Start BLE advertising using current {@link BluetoothAdvScanData}. - * An app should start advertising by requesting - * {@link BluetoothAdapter#ACTION_START_ADVERTISING} instead of calling this method directly. *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} * - * @return true if BLE avertising succeeds, false otherwise. + * @param callback - {@link AdvertiseCallback} + * @return true if BLE advertising succeeds, false otherwise. * @hide */ - public boolean startAdvertising() { + public boolean startAdvertising(final AdvertiseCallback callback) { if (getState() != STATE_ON) return false; - try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); if (iGatt == null) { @@ -519,18 +537,31 @@ public final class BluetoothAdapter { // Restart/reset advertising packets if advertising is in progress. if (isAdvertising()) { // Invalid advertising callback. - if (mAdvertisingCallback == null || mAdvertisingCallback.mLeHandle == -1) { + if (mAdvertisingGattCallback == null || mAdvertisingGattCallback.mLeHandle == -1) { Log.e(TAG, "failed to restart advertising, invalid callback"); return false; } - iGatt.startAdvertising(mAdvertisingCallback.mLeHandle); + iGatt.startAdvertising(mAdvertisingGattCallback.mLeHandle); + // Run the callback from main thread. + mHandler.post(new Runnable() { + @Override + public void run() { + // callback with status success. + callback.onAdvertiseStart(ADVERTISE_CALLBACK_SUCCESS); + } + }); return true; } UUID uuid = UUID.randomUUID(); GattCallbackWrapper wrapper = - new GattCallbackWrapper(this, null, null, GattCallbackWrapper.CALLBACK_TYPE_ADV); + new GattCallbackWrapper(this, null, null, callback); iGatt.registerClient(new ParcelUuid(uuid), wrapper); - mAdvertisingCallback = wrapper; + if (!wrapper.advertiseStarted()) { + return false; + } + synchronized (mLock) { + mAdvertisingGattCallback = wrapper; + } return true; } catch (RemoteException e) { Log.e(TAG, "", e); @@ -540,25 +571,29 @@ public final class BluetoothAdapter { /** * Stop BLE advertising. - * An app should stop advertising by requesting - * {@link BluetoothAdapter#ACTION_STOP_ADVERTISING} instead of calling this method directly. - *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * + * @param callback - {@link AdvertiseCallback} * @return true if BLE advertising stops, false otherwise. * @hide */ - public boolean stopAdvertisting() { + public boolean stopAdvertising(AdvertiseCallback callback) { try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); if (iGatt == null) { // BLE is not supported return false; } - if (mAdvertisingCallback == null) { + if (mAdvertisingGattCallback == null) { // no callback. return false; } - mAdvertisingCallback.stopAdvertising(); - mAdvertisingCallback = null; + // Make sure same callback is used for start and stop advertising. + if (callback != mAdvertisingGattCallback.mAdvertiseCallback) { + Log.e(TAG, "must use the same callback for star/stop advertising"); + return false; + } + mAdvertisingGattCallback.stopAdvertising(); + mAdvertisingGattCallback = null; return true; } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1418,6 +1453,8 @@ public final class BluetoothAdapter { if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); synchronized (mManagerCallback) { mService = null; + // Reset bluetooth adv scan data when Gatt service is down. + mBluetoothAdvScanData = null; for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ try { if (cb != null) { @@ -1692,11 +1729,9 @@ public final class BluetoothAdapter { private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub { private static final int LE_CALLBACK_REG_TIMEOUT = 2000; private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; - private static final int CALLBACK_TYPE_SCAN = 0; - private static final int CALLBACK_TYPE_ADV = 1; + private final AdvertiseCallback mAdvertiseCallback; private final LeScanCallback mLeScanCb; - private int mCallbackType; // mLeHandle 0: not registered // -1: scan stopped @@ -1711,26 +1746,34 @@ public final class BluetoothAdapter { mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; - mCallbackType = CALLBACK_TYPE_SCAN; + mAdvertiseCallback = null; } public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, LeScanCallback leScanCb, - UUID[] uuid, int type) { + UUID[] uuid, AdvertiseCallback callback) { mBluetoothAdapter = new WeakReference(bluetoothAdapter); mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; - mCallbackType = type; + mAdvertiseCallback = callback; } public boolean scanStarted() { + return waitForRegisteration(LE_CALLBACK_REG_WAIT_COUNT); + } + + public boolean advertiseStarted() { + // Wait for registeration callback. + return waitForRegisteration(1); + } + + private boolean waitForRegisteration(int maxWaitCount) { boolean started = false; synchronized(this) { if (mLeHandle == -1) return false; - int count = 0; // wait for callback registration and LE scan to start - while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) { + while (mLeHandle == 0 && count < maxWaitCount) { try { wait(LE_CALLBACK_REG_TIMEOUT); } catch (InterruptedException e) { @@ -1754,7 +1797,7 @@ public final class BluetoothAdapter { try { IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); iGatt.stopAdvertising(); - Log.d(TAG, "unregeistering client " + mLeHandle); + Log.d(TAG, "unregistering client " + mLeHandle); iGatt.unregisterClient(mLeHandle); } catch (RemoteException e) { Log.e(TAG, "Failed to stop advertising and unregister" + e); @@ -1808,7 +1851,7 @@ public final class BluetoothAdapter { BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - if (mCallbackType == CALLBACK_TYPE_ADV) { + if (mAdvertiseCallback != null) { iGatt.startAdvertising(mLeHandle); } else { if (mScanFilter == null) { @@ -1858,7 +1901,7 @@ public final class BluetoothAdapter { * @hide */ public void onScanResult(String address, int rssi, byte[] advData) { - if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); + if (VDBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); // Check null in case the scan has been stopped synchronized(this) { @@ -1947,9 +1990,13 @@ public final class BluetoothAdapter { // no op } - public void onListen(int status) { - // no op + public void onAdvertiseStateChange(int advertiseState, int status) { + Log.d(TAG, "on advertise call back, state: " + advertiseState + " status: " + status); + if (advertiseState == STATE_ADVERTISE_STARTED) { + mAdvertiseCallback.onAdvertiseStart(status); + } else { + mAdvertiseCallback.onAdvertiseStop(status); + } } } - } -- cgit v1.2.3 From da4a111edbd716f8b27831b4975d772bca8ac4d7 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 19 Mar 2014 15:47:12 -0700 Subject: DO NOT MERGE: Move advetise clean up to callback code. fixes b/13289050 Cherrypick from master to fix b/13289050 Change-Id: Ibf3c772561125821817c947730cf21defafd4cb2 --- .../java/android/bluetooth/BluetoothAdapter.java | 26 +++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index f973d843ea..75b007c75c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -593,7 +593,6 @@ public final class BluetoothAdapter { return false; } mAdvertisingGattCallback.stopAdvertising(); - mAdvertisingGattCallback = null; return true; } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1797,15 +1796,12 @@ public final class BluetoothAdapter { try { IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); iGatt.stopAdvertising(); - Log.d(TAG, "unregistering client " + mLeHandle); - iGatt.unregisterClient(mLeHandle); } catch (RemoteException e) { - Log.e(TAG, "Failed to stop advertising and unregister" + e); + Log.e(TAG, "Failed to stop advertising" + e); } } else { Log.e(TAG, "stopAdvertising, BluetoothAdapter is null"); } - mLeHandle = -1; notifyAll(); } } @@ -1995,6 +1991,26 @@ public final class BluetoothAdapter { if (advertiseState == STATE_ADVERTISE_STARTED) { mAdvertiseCallback.onAdvertiseStart(status); } else { + synchronized (this) { + if (status == ADVERTISE_CALLBACK_SUCCESS) { + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + try { + IBluetoothGatt iGatt = + adapter.getBluetoothManager().getBluetoothGatt(); + Log.d(TAG, "unregistering client " + mLeHandle); + iGatt.unregisterClient(mLeHandle); + // Reset advertise app handle. + mLeHandle = -1; + adapter.mAdvertisingGattCallback = null; + } catch (RemoteException e) { + Log.e(TAG, "Failed to unregister client" + e); + } + } else { + Log.e(TAG, "cannot unregister client, BluetoothAdapter is null"); + } + } + } mAdvertiseCallback.onAdvertiseStop(status); } } -- cgit v1.2.3 From 91057ef842c47e70f4b97fafc950bed6c4382f03 Mon Sep 17 00:00:00 2001 From: Andre Eisenbach Date: Tue, 25 Mar 2014 06:31:50 -0700 Subject: LE: Add API to configure MTU for a given connection (3/4) bug:13571470 Change-Id: I3619617eaf864701a35f7802bc71805784d768d0 --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 75b007c75c..182ef03c59 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2014,5 +2014,13 @@ public final class BluetoothAdapter { mAdvertiseCallback.onAdvertiseStop(status); } } + + /** + * Callback reporting LE ATT MTU. + * @hide + */ + public void onConfigureMTU(String address, int mtu, int status) { + // no op + } } } -- cgit v1.2.3 From d02986b29fa12e91de202f185de1f718a1c2ad7d Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 27 Mar 2014 19:34:46 -0700 Subject: Add comment of using same callback for start/stop advertising. Change-Id: Ice268e83e4f2ceb5053a0e03f73b877f548bd13b --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 75b007c75c..229bcbffec 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -570,7 +570,7 @@ public final class BluetoothAdapter { } /** - * Stop BLE advertising. + * Stop BLE advertising. The callback has to be the same one used for start advertising. * * @param callback - {@link AdvertiseCallback} * @return true if BLE advertising stops, false otherwise. -- cgit v1.2.3 From e0811cc380dbe9c2bb34c54af7848a3f1b3b81af Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Fri, 28 Mar 2014 18:40:29 -0700 Subject: Callback on correct method when status is unsuccessful. Change-Id: I63c07bbae559765af1aecb492379ab18268336d8 --- framework/java/android/bluetooth/BluetoothAdapter.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 229bcbffec..63ebb63944 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1989,7 +1989,13 @@ public final class BluetoothAdapter { public void onAdvertiseStateChange(int advertiseState, int status) { Log.d(TAG, "on advertise call back, state: " + advertiseState + " status: " + status); if (advertiseState == STATE_ADVERTISE_STARTED) { - mAdvertiseCallback.onAdvertiseStart(status); + if (status == ADVERTISE_CALLBACK_SUCCESS) { + mAdvertiseCallback.onAdvertiseStart(status); + } else { + // If status is unsuccessful and advertise state is started, it means stop + // advertising fails. + mAdvertiseCallback.onAdvertiseStop(status); + } } else { synchronized (this) { if (status == ADVERTISE_CALLBACK_SUCCESS) { @@ -2011,7 +2017,13 @@ public final class BluetoothAdapter { } } } - mAdvertiseCallback.onAdvertiseStop(status); + if (status == ADVERTISE_CALLBACK_SUCCESS) { + mAdvertiseCallback.onAdvertiseStop(status); + } else{ + // If status is unsuccesful and advertise state is stopped, it means start + // advertising fails. + mAdvertiseCallback.onAdvertiseStart(status); + } } } } -- cgit v1.2.3 From 46ff4e6f7056d16bb83c094bbf287208dd9b8b55 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 16 Apr 2014 18:49:18 -0700 Subject: APIs for BLE scan, scan filter, batch scan, onFound/onLost and multiple advertising. Change-Id: I1655eb9cffa890b6fe38108bf51078662e90bc03 --- .../java/android/bluetooth/BluetoothAdapter.java | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e79deeccbd..9e1c995bbb 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -497,6 +497,34 @@ public final class BluetoothAdapter { } } + /** + * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations. + */ + public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { + // TODO: Return null if this feature is not supported by hardware. + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + return new BluetoothLeAdvertiser(iGatt); + } catch (RemoteException e) { + Log.e(TAG, "failed to get BluetoothLeAdvertiser, error: " + e); + return null; + } + } + + /** + * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. + */ + public BluetoothLeScanner getBluetoothLeScanner() { + // TODO: Return null if BLE scan is not supported by hardware. + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + return new BluetoothLeScanner(iGatt); + } catch (RemoteException e) { + Log.e(TAG, "failed to get BluetoothLeScanner, error: " + e); + return null; + } + } + /** * Interface for BLE advertising callback. * @@ -2024,6 +2052,10 @@ public final class BluetoothAdapter { } } + @Override + public void onMultiAdvertiseCallback(int status) { + // no op + } /** * Callback reporting LE ATT MTU. * @hide -- cgit v1.2.3 From 39eb6801bb37a327a7460d9c830571448de19319 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 20 May 2014 04:52:35 +0000 Subject: Revert "APIs for BLE scan, scan filter, batch scan, onFound/onLost and multiple advertising." This reverts commit 2c4e68a86b7a9b9f760a8907b93ff40ccad56c80. Change-Id: I98c91343d886ebe22d0bf75a710fa0b0abf738b6 --- .../java/android/bluetooth/BluetoothAdapter.java | 32 ---------------------- 1 file changed, 32 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 9e1c995bbb..e79deeccbd 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -497,34 +497,6 @@ public final class BluetoothAdapter { } } - /** - * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations. - */ - public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { - // TODO: Return null if this feature is not supported by hardware. - try { - IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); - return new BluetoothLeAdvertiser(iGatt); - } catch (RemoteException e) { - Log.e(TAG, "failed to get BluetoothLeAdvertiser, error: " + e); - return null; - } - } - - /** - * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. - */ - public BluetoothLeScanner getBluetoothLeScanner() { - // TODO: Return null if BLE scan is not supported by hardware. - try { - IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); - return new BluetoothLeScanner(iGatt); - } catch (RemoteException e) { - Log.e(TAG, "failed to get BluetoothLeScanner, error: " + e); - return null; - } - } - /** * Interface for BLE advertising callback. * @@ -2052,10 +2024,6 @@ public final class BluetoothAdapter { } } - @Override - public void onMultiAdvertiseCallback(int status) { - // no op - } /** * Callback reporting LE ATT MTU. * @hide -- cgit v1.2.3 From b464cfd7ac9eb108f89356a3764a6dfe247ce3b6 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 20 May 2014 06:30:20 +0000 Subject: Revert "Revert "APIs for BLE scan, scan filter, batch scan, onFound/onLost and multiple advertising."" This reverts commit b1d9fbc0f8dea0c77ed810190b325bfdaaf21789. Change-Id: Ic8dec9385a7c763170ebeb1bcddd221c72f46e88 --- .../java/android/bluetooth/BluetoothAdapter.java | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e79deeccbd..9e1c995bbb 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -497,6 +497,34 @@ public final class BluetoothAdapter { } } + /** + * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations. + */ + public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { + // TODO: Return null if this feature is not supported by hardware. + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + return new BluetoothLeAdvertiser(iGatt); + } catch (RemoteException e) { + Log.e(TAG, "failed to get BluetoothLeAdvertiser, error: " + e); + return null; + } + } + + /** + * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. + */ + public BluetoothLeScanner getBluetoothLeScanner() { + // TODO: Return null if BLE scan is not supported by hardware. + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + return new BluetoothLeScanner(iGatt); + } catch (RemoteException e) { + Log.e(TAG, "failed to get BluetoothLeScanner, error: " + e); + return null; + } + } + /** * Interface for BLE advertising callback. * @@ -2024,6 +2052,10 @@ public final class BluetoothAdapter { } } + @Override + public void onMultiAdvertiseCallback(int status) { + // no op + } /** * Callback reporting LE ATT MTU. * @hide -- cgit v1.2.3 From 7df2e527176028029fdf07e85a8fb3377111b4b8 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 22 May 2014 12:10:25 -0700 Subject: Address API review comments. 1. Moved le stuff to it's subpackage. Remove BluetoothLe for all classes except *Scanner, *ScanSetting, *Advertiser and *AdvertiseSettings. 2. Make all callbacks abstract classes instead of interfaces. 3. Moved AdvertisementData and ScanRecord out and removed AdvertiseBaseData 4. Removed newBuild and use new Builder for all builders. 5. Using setxxx in builders. 6. Misc other changes. Fixes b/15140940 Change-Id: I32ae3d24a9491baf96048040b5ac78f6f731e468 NO_SQ: multi-project submit --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 9e1c995bbb..42c2aebead 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -18,6 +18,8 @@ package android.bluetooth; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.bluetooth.le.BluetoothLeAdvertiser; +import android.bluetooth.le.BluetoothLeScanner; import android.content.Context; import android.os.Handler; import android.os.IBinder; -- cgit v1.2.3 From 67a995ada9ae181651c436130a56d46699a120c1 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Mon, 19 Aug 2013 19:03:51 +0530 Subject: Bluetooth: Add support for HFP Client role. Implementation changes in frameworks to support HFP Client role. Change-Id: Ifb10527cd6c1301297cae4f923b20734af672034 --- framework/java/android/bluetooth/BluetoothAdapter.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 42c2aebead..8b8629ea75 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2009-2014 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. @@ -1402,6 +1402,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.MAP) { BluetoothMap map = new BluetoothMap(context, listener); return true; + } else if (profile == BluetoothProfile.HANDSFREE_CLIENT) { + BluetoothHandsfreeClient hfpclient = new BluetoothHandsfreeClient(context, listener); + return true; } else { return false; } @@ -1454,6 +1457,10 @@ public final class BluetoothAdapter { BluetoothMap map = (BluetoothMap)proxy; map.close(); break; + case BluetoothProfile.HANDSFREE_CLIENT: + BluetoothHandsfreeClient hfpclient = (BluetoothHandsfreeClient)proxy; + hfpclient.close(); + break; } } -- cgit v1.2.3 From f48a72776380b9691c85aba73012bd3d69cebe01 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Thu, 12 Jun 2014 11:23:40 -0700 Subject: Rename BluetoothHandsfreeClient to BluetoothHeadsetClient This makes our terminology consistent with the existing BluetoothHeadset profile Also updated arguments to Context.bindService() Change-Id: I27cc5a6fde256b1f5dccca53a7a15ec8f58691c2 --- framework/java/android/bluetooth/BluetoothAdapter.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8b8629ea75..6daa61d79a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1402,8 +1402,8 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.MAP) { BluetoothMap map = new BluetoothMap(context, listener); return true; - } else if (profile == BluetoothProfile.HANDSFREE_CLIENT) { - BluetoothHandsfreeClient hfpclient = new BluetoothHandsfreeClient(context, listener); + } else if (profile == BluetoothProfile.HEADSET_CLIENT) { + BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener); return true; } else { return false; @@ -1457,9 +1457,9 @@ public final class BluetoothAdapter { BluetoothMap map = (BluetoothMap)proxy; map.close(); break; - case BluetoothProfile.HANDSFREE_CLIENT: - BluetoothHandsfreeClient hfpclient = (BluetoothHandsfreeClient)proxy; - hfpclient.close(); + case BluetoothProfile.HEADSET_CLIENT: + BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy; + headsetClient.close(); break; } } -- cgit v1.2.3 From f0de508aeaac6686cb132c73e224980fede48727 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 14 May 2014 09:51:30 -0700 Subject: BluetoothA2dpSink: Add new BluetoothProfile subclass for A2DP sink Change-Id: I09d5cb8fdaea4c4828f333949b7c18deffd22722 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 6daa61d79a..ee0da22cdc 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1390,6 +1390,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.A2DP) { BluetoothA2dp a2dp = new BluetoothA2dp(context, listener); return true; + } else if (profile == BluetoothProfile.A2DP_SINK) { + BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener); + return true; } else if (profile == BluetoothProfile.INPUT_DEVICE) { BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener); return true; @@ -1433,6 +1436,10 @@ public final class BluetoothAdapter { BluetoothA2dp a2dp = (BluetoothA2dp)proxy; a2dp.close(); break; + case BluetoothProfile.A2DP_SINK: + BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink)proxy; + a2dpSink.close(); + break; case BluetoothProfile.INPUT_DEVICE: BluetoothInputDevice iDev = (BluetoothInputDevice)proxy; iDev.close(); -- cgit v1.2.3 From 517b04f1485e17c93ad21bb303e8d1acade86ba6 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 2 Jun 2014 16:20:37 -0700 Subject: BluetoothAvrcpController: Move AVRCP controller support to new BluetoothProfile subclass Change-Id: Id988040a7ce623ed68e0349920301ff48db1fbce --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ee0da22cdc..ba42f51b62 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1393,6 +1393,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.A2DP_SINK) { BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener); return true; + } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) { + BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener); + return true; } else if (profile == BluetoothProfile.INPUT_DEVICE) { BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener); return true; @@ -1440,6 +1443,10 @@ public final class BluetoothAdapter { BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink)proxy; a2dpSink.close(); break; + case BluetoothProfile.AVRCP_CONTROLLER: + BluetoothAvrcpController avrcp = (BluetoothAvrcpController)proxy; + avrcp.close(); + break; case BluetoothProfile.INPUT_DEVICE: BluetoothInputDevice iDev = (BluetoothInputDevice)proxy; iDev.close(); -- cgit v1.2.3 From 745ef9e3f3793abf0f0a14ab8765f17be153ece0 Mon Sep 17 00:00:00 2001 From: Andre Eisenbach Date: Fri, 28 Mar 2014 14:54:53 -0700 Subject: LE: Add notification sent and congestion callbacks (3/4) This change introduces two new callbacks for applications to better handle LE notification flow control and transport congestion. The notification callback is invoked when the remote platform confirms an indication or when a local notification has been passed to the controller. No new notifications should be sent until a callback is received. Congestion callbacks are triggered when a GATT operation cannot be sent to the local Bluetooth controller. Repeatedly calling writeCharacteristic() for example will eventually trigger a congestion callback. Applications cannot send additional data until a further callback is received, indicating that the congestion has cleared up. Also made server callbacks "oneway" in the AIDL definition file. Change-Id: I7fa3324712205c79efce58e5e3df8b80a265a442 --- framework/java/android/bluetooth/BluetoothAdapter.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ba42f51b62..22872465b7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2079,12 +2079,15 @@ public final class BluetoothAdapter { public void onMultiAdvertiseCallback(int status) { // no op } - /** - * Callback reporting LE ATT MTU. - * @hide - */ + + @Override public void onConfigureMTU(String address, int mtu, int status) { // no op } + + @Override + public void onConnectionCongested(String address, boolean congested) { + // no op + } } } -- cgit v1.2.3 From d9b0b0eb7f08f129f461013b8a7a00e7ec55769d Mon Sep 17 00:00:00 2001 From: Prerepa Viswanadham Date: Wed, 2 Jul 2014 12:30:38 -0700 Subject: Obtain capabilities from chipset for it's support of various features Change-Id: I01bdb31136be63e4e46fb4e054c902eddc5647ab --- .../java/android/bluetooth/BluetoothAdapter.java | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 22872465b7..d75304feef 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1038,6 +1038,54 @@ public final class BluetoothAdapter { return false; } + /** + * Return true if the multi advertisement is supported by the chipset + * + * @hide + * @return true if Multiple Advertisement feature is supported + */ + public boolean isMultipleAdvertisementSupported() { + if (getState() != STATE_ON) return false; + try { + return mService.isMultiAdvertisementSupported(); + } catch (RemoteException e) { + Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e); + } + return false; + } + + /** + * Return true if offloaded filters are supported + * + * @hide + * @return true if chipset supports on-chip filtering + */ + public boolean isOffloadedFilteringSupported() { + if (getState() != STATE_ON) return false; + try { + return mService.isOffloadedFilteringSupported(); + } catch (RemoteException e) { + Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); + } + return false; + } + + /** + * Return true if offloaded scan batching is supported + * + * @hide + * @return true if chipset supports on-chip scan batching + */ + public boolean isOffloadedScanBatchingSupported() { + if (getState() != STATE_ON) return false; + try { + return mService.isOffloadedScanBatchingSupported(); + } catch (RemoteException e) { + Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e); + } + return false; + } + /** * Returns whether BLE is currently advertising. *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. -- cgit v1.2.3 From 7dbe2ac8c144bc6c05f07ded3fa146066c4c148b Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 1 Jul 2014 15:10:06 -0700 Subject: Implement batch scan API Change-Id: Ibb527280a221fbdd0fc6b805a7527c29079294b4 --- .../java/android/bluetooth/BluetoothAdapter.java | 23 +++++++++------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index d75304feef..35e5050067 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -20,6 +20,7 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.ScanResult; import android.content.Context; import android.os.Handler; import android.os.IBinder; @@ -37,6 +38,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -504,13 +506,7 @@ public final class BluetoothAdapter { */ public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { // TODO: Return null if this feature is not supported by hardware. - try { - IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); - return new BluetoothLeAdvertiser(iGatt); - } catch (RemoteException e) { - Log.e(TAG, "failed to get BluetoothLeAdvertiser, error: " + e); - return null; - } + return new BluetoothLeAdvertiser(mManagerService); } /** @@ -518,13 +514,7 @@ public final class BluetoothAdapter { */ public BluetoothLeScanner getBluetoothLeScanner() { // TODO: Return null if BLE scan is not supported by hardware. - try { - IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); - return new BluetoothLeScanner(iGatt); - } catch (RemoteException e) { - Log.e(TAG, "failed to get BluetoothLeScanner, error: " + e); - return null; - } + return new BluetoothLeScanner(mManagerService); } /** @@ -2137,5 +2127,10 @@ public final class BluetoothAdapter { public void onConnectionCongested(String address, boolean congested) { // no op } + + @Override + public void onBatchScanResults(List results) { + // no op + } } } -- cgit v1.2.3 From 5daedc1e0c3eab37a8dae3dc4ce739e6cafcfdc6 Mon Sep 17 00:00:00 2001 From: Prerepa Viswanadham Date: Wed, 9 Jul 2014 12:51:59 -0700 Subject: OnFound and Onlost callback integration Change-Id: I23473b18484f041c4dd808c85bb92545a77e20c2 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 35e5050067..4bc9cfc647 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2132,5 +2132,11 @@ public final class BluetoothAdapter { public void onBatchScanResults(List results) { // no op } + + @Override + public void onFoundOrLost(boolean onFound, String address,int rssi, + byte[] advData) { + // no op + } } } -- cgit v1.2.3 From 0649e964a14ffea79689a81fdcb5546ee6ad4553 Mon Sep 17 00:00:00 2001 From: Prerepa Viswanadham Date: Wed, 9 Jul 2014 14:23:24 -0700 Subject: Unhide the Bluetooth(BLE) offload capability apis Change-Id: Ice3f4f5ff4b8318bf6afe7021b253fe9ea4661d3 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 4bc9cfc647..be14504449 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1031,7 +1031,6 @@ public final class BluetoothAdapter { /** * Return true if the multi advertisement is supported by the chipset * - * @hide * @return true if Multiple Advertisement feature is supported */ public boolean isMultipleAdvertisementSupported() { @@ -1047,7 +1046,6 @@ public final class BluetoothAdapter { /** * Return true if offloaded filters are supported * - * @hide * @return true if chipset supports on-chip filtering */ public boolean isOffloadedFilteringSupported() { @@ -1063,7 +1061,6 @@ public final class BluetoothAdapter { /** * Return true if offloaded scan batching is supported * - * @hide * @return true if chipset supports on-chip scan batching */ public boolean isOffloadedScanBatchingSupported() { -- cgit v1.2.3 From 7faed2f183c09307b398c22e1b92ac52f1d93a7e Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 9 Jul 2014 14:03:42 -0700 Subject: Unhide Bluetooth batch APIs. Deprecate BluetoothAdpater scan APIs. (1/2) Change-Id: Ib0c4ea6c8372a15473269660355fb5ccf4284457 --- framework/java/android/bluetooth/BluetoothAdapter.java | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index be14504449..97e3fc510d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -20,7 +20,9 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanResult; +import android.bluetooth.le.ScanSettings; import android.content.Context; import android.os.Handler; import android.os.IBinder; @@ -1734,7 +1736,10 @@ public final class BluetoothAdapter { * * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully + * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)} + * instead. */ + @Deprecated public boolean startLeScan(LeScanCallback callback) { return startLeScan(null, callback); } @@ -1751,7 +1756,10 @@ public final class BluetoothAdapter { * @param serviceUuids Array of services to look for * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully + * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)} + * instead. */ + @Deprecated public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) { if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids); @@ -1794,7 +1802,9 @@ public final class BluetoothAdapter { * * @param callback used to identify which scan to stop * must be the same handle used to start the scan + * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead. */ + @Deprecated public void stopLeScan(LeScanCallback callback) { if (DBG) Log.d(TAG, "stopLeScan()"); GattCallbackWrapper wrapper; -- cgit v1.2.3 From 1ceb01210f9ee5c2df90e0c0a1f058eede42a03f Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 10 Jul 2014 15:28:02 -0700 Subject: Remove MR2 BLE Advertising hidden API from L codebase (1/2). Change-Id: I78bb8b89de56bddb7422da1d1d4468c88a68ea11 --- .../java/android/bluetooth/BluetoothAdapter.java | 253 +-------------------- 1 file changed, 7 insertions(+), 246 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 97e3fc510d..faf864550d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -218,22 +218,6 @@ public final class BluetoothAdapter { public static final String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; - /** - * Broadcast Action: Indicate BLE Advertising is started. - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_BLUETOOTH_ADVERTISING_STARTED = - "android.bluetooth.adapter.action.ADVERTISING_STARTED"; - - /** - * Broadcast Action: Indicated BLE Advertising is stopped. - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_BLUETOOTH_ADVERTISING_STOPPED = - "android.bluetooth.adapter.action.ADVERTISING_STOPPED"; - /** * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} * intents to request the current scan mode. Possible values are: @@ -403,8 +387,6 @@ public final class BluetoothAdapter { private IBluetooth mService; private final Map mLeScanClients; - private BluetoothAdvScanData mBluetoothAdvScanData = null; - private GattCallbackWrapper mAdvertisingGattCallback; private final Handler mHandler; // Handler to post the advertise callback to run on main thread. private final Object mLock = new Object(); @@ -480,29 +462,6 @@ public final class BluetoothAdapter { address[0], address[1], address[2], address[3], address[4], address[5])); } - /** - * Returns a {@link BluetoothAdvScanData} object representing advertising data. - * Data will be reset when bluetooth service is turned off. - * @hide - */ - public BluetoothAdvScanData getAdvScanData() { - try { - IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); - if (iGatt == null) { - // BLE is not supported - Log.e(TAG, "failed to start, iGatt null"); - return null; - } - if (mBluetoothAdvScanData == null) { - mBluetoothAdvScanData = new BluetoothAdvScanData(iGatt, BluetoothAdvScanData.AD); - } - return mBluetoothAdvScanData; - } catch (RemoteException e) { - Log.e(TAG, "failed to get advScanData, error: " + e); - return null; - } - } - /** * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations. */ @@ -519,106 +478,6 @@ public final class BluetoothAdapter { return new BluetoothLeScanner(mManagerService); } - /** - * Interface for BLE advertising callback. - * - * @hide - */ - public interface AdvertiseCallback { - /** - * Callback when advertise starts. - * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure. - */ - void onAdvertiseStart(int status); - /** - * Callback when advertise stops. - * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure. - */ - void onAdvertiseStop(int status); - } - - /** - * Start BLE advertising using current {@link BluetoothAdvScanData}. - *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} - * - * @param callback - {@link AdvertiseCallback} - * @return true if BLE advertising succeeds, false otherwise. - * @hide - */ - public boolean startAdvertising(final AdvertiseCallback callback) { - if (getState() != STATE_ON) return false; - try { - IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); - if (iGatt == null) { - // BLE is not supported. - return false; - } - // Restart/reset advertising packets if advertising is in progress. - if (isAdvertising()) { - // Invalid advertising callback. - if (mAdvertisingGattCallback == null || mAdvertisingGattCallback.mLeHandle == -1) { - Log.e(TAG, "failed to restart advertising, invalid callback"); - return false; - } - iGatt.startAdvertising(mAdvertisingGattCallback.mLeHandle); - // Run the callback from main thread. - mHandler.post(new Runnable() { - @Override - public void run() { - // callback with status success. - callback.onAdvertiseStart(ADVERTISE_CALLBACK_SUCCESS); - } - }); - return true; - } - UUID uuid = UUID.randomUUID(); - GattCallbackWrapper wrapper = - new GattCallbackWrapper(this, null, null, callback); - iGatt.registerClient(new ParcelUuid(uuid), wrapper); - if (!wrapper.advertiseStarted()) { - return false; - } - synchronized (mLock) { - mAdvertisingGattCallback = wrapper; - } - return true; - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - } - - /** - * Stop BLE advertising. The callback has to be the same one used for start advertising. - * - * @param callback - {@link AdvertiseCallback} - * @return true if BLE advertising stops, false otherwise. - * @hide - */ - public boolean stopAdvertising(AdvertiseCallback callback) { - try { - IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); - if (iGatt == null) { - // BLE is not supported - return false; - } - if (mAdvertisingGattCallback == null) { - // no callback. - return false; - } - // Make sure same callback is used for start and stop advertising. - if (callback != mAdvertisingGattCallback.mAdvertiseCallback) { - Log.e(TAG, "must use the same callback for star/stop advertising"); - return false; - } - mAdvertisingGattCallback.stopAdvertising(); - return true; - } catch (RemoteException e) { - Log.e(TAG, "", e); - return false; - } - } - /** * Return true if Bluetooth is currently enabled and ready for use. *

Equivalent to: @@ -1075,23 +934,6 @@ public final class BluetoothAdapter { return false; } - /** - * Returns whether BLE is currently advertising. - *

Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. - * - * @hide - */ - public boolean isAdvertising() { - if (getState() != STATE_ON) return false; - try { - IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); - return iGatt.isAdvertising(); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return false; - } - /** * Return the set of {@link BluetoothDevice} objects that are bonded * (paired) to the local adapter. @@ -1537,8 +1379,6 @@ public final class BluetoothAdapter { if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); synchronized (mManagerCallback) { mService = null; - // Reset bluetooth adv scan data when Gatt service is down. - mBluetoothAdvScanData = null; for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ try { if (cb != null) { @@ -1822,7 +1662,6 @@ public final class BluetoothAdapter { private static final int LE_CALLBACK_REG_TIMEOUT = 2000; private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; - private final AdvertiseCallback mAdvertiseCallback; private final LeScanCallback mLeScanCb; // mLeHandle 0: not registered @@ -1838,27 +1677,12 @@ public final class BluetoothAdapter { mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; - mAdvertiseCallback = null; - } - - public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, LeScanCallback leScanCb, - UUID[] uuid, AdvertiseCallback callback) { - mBluetoothAdapter = new WeakReference(bluetoothAdapter); - mLeScanCb = leScanCb; - mScanFilter = uuid; - mLeHandle = 0; - mAdvertiseCallback = callback; } public boolean scanStarted() { return waitForRegisteration(LE_CALLBACK_REG_WAIT_COUNT); } - public boolean advertiseStarted() { - // Wait for registeration callback. - return waitForRegisteration(1); - } - private boolean waitForRegisteration(int maxWaitCount) { boolean started = false; synchronized(this) { @@ -1878,27 +1702,6 @@ public final class BluetoothAdapter { return started; } - public void stopAdvertising() { - synchronized (this) { - if (mLeHandle <= 0) { - Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); - return; - } - BluetoothAdapter adapter = mBluetoothAdapter.get(); - if (adapter != null) { - try { - IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - iGatt.stopAdvertising(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to stop advertising" + e); - } - } else { - Log.e(TAG, "stopAdvertising, BluetoothAdapter is null"); - } - notifyAll(); - } - } - public void stopLeScan() { synchronized(this) { if (mLeHandle <= 0) { @@ -1940,18 +1743,14 @@ public final class BluetoothAdapter { BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - if (mAdvertiseCallback != null) { - iGatt.startAdvertising(mLeHandle); + if (mScanFilter == null) { + iGatt.startScan(mLeHandle, false); } else { - if (mScanFilter == null) { - iGatt.startScan(mLeHandle, false); - } else { - ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; - for(int i = 0; i != uuids.length; ++i) { - uuids[i] = new ParcelUuid(mScanFilter[i]); - } - iGatt.startScanWithUuids(mLeHandle, false, uuids); - } + ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; + for(int i = 0; i != uuids.length; ++i) { + uuids[i] = new ParcelUuid(mScanFilter[i]); + } + iGatt.startScanWithUuids(mLeHandle, false, uuids); } } else { Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); @@ -2080,44 +1879,6 @@ public final class BluetoothAdapter { } public void onAdvertiseStateChange(int advertiseState, int status) { - Log.d(TAG, "on advertise call back, state: " + advertiseState + " status: " + status); - if (advertiseState == STATE_ADVERTISE_STARTED) { - if (status == ADVERTISE_CALLBACK_SUCCESS) { - mAdvertiseCallback.onAdvertiseStart(status); - } else { - // If status is unsuccessful and advertise state is started, it means stop - // advertising fails. - mAdvertiseCallback.onAdvertiseStop(status); - } - } else { - synchronized (this) { - if (status == ADVERTISE_CALLBACK_SUCCESS) { - BluetoothAdapter adapter = mBluetoothAdapter.get(); - if (adapter != null) { - try { - IBluetoothGatt iGatt = - adapter.getBluetoothManager().getBluetoothGatt(); - Log.d(TAG, "unregistering client " + mLeHandle); - iGatt.unregisterClient(mLeHandle); - // Reset advertise app handle. - mLeHandle = -1; - adapter.mAdvertisingGattCallback = null; - } catch (RemoteException e) { - Log.e(TAG, "Failed to unregister client" + e); - } - } else { - Log.e(TAG, "cannot unregister client, BluetoothAdapter is null"); - } - } - } - if (status == ADVERTISE_CALLBACK_SUCCESS) { - mAdvertiseCallback.onAdvertiseStop(status); - } else{ - // If status is unsuccesful and advertise state is stopped, it means start - // advertising fails. - mAdvertiseCallback.onAdvertiseStart(status); - } - } } @Override -- cgit v1.2.3 From 53c97aee16c15ca9a3932bde283e604812d74fc4 Mon Sep 17 00:00:00 2001 From: Prerepa Viswanadham Date: Tue, 22 Jul 2014 17:00:09 -0700 Subject: Bug 15564216: Report Bluetooth tx/rx/idle activity info and energy reporting Change-Id: I66fd83d8d59fbd93dec8886dfd313a81575e38a5 --- .../java/android/bluetooth/BluetoothAdapter.java | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index faf864550d..453d60c6cd 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -377,6 +377,12 @@ public final class BluetoothAdapter { private static final int ADDRESS_LENGTH = 17; + private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30; + /** @hide */ + public static final int ACTIVITY_ENERGY_INFO_CACHED = 0; + /** @hide */ + public static final int ACTIVITY_ENERGY_INFO_REFRESHED = 1; + /** * Lazily initialized singleton. Guaranteed final after first object * constructed. @@ -934,6 +940,43 @@ public final class BluetoothAdapter { return false; } + /** + * Return the record of {@link BluetoothActivityEnergyInfo} object that + * has the activity and energy info. This can be used to ascertain what + * the controller has been up to, since the last sample. + * @param updateType Type of info, cached vs refreshed. + * + * @return a record with {@link BluetoothActivityEnergyInfo} or null if + * report is unavailable or unsupported + * @hide + */ + public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { + if (getState() != STATE_ON) return null; + try { + BluetoothActivityEnergyInfo record; + if (!mService.isActivityAndEnergyReportingSupported()) { + return null; + } + synchronized(this) { + if (updateType == ACTIVITY_ENERGY_INFO_REFRESHED) { + mService.getActivityEnergyInfoFromController(); + wait(CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS); + } + record = mService.reportActivityInfo(); + if (record.isValid()) { + return record; + } else { + return null; + } + } + } catch (InterruptedException e) { + Log.e(TAG, "getControllerActivityEnergyInfoCallback wait interrupted: " + e); + } catch (RemoteException e) { + Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e); + } + return null; + } + /** * Return the set of {@link BluetoothDevice} objects that are bonded * (paired) to the local adapter. -- cgit v1.2.3 From 010675f9b7b2879c78ba8042ec9edf3137b1349c Mon Sep 17 00:00:00 2001 From: Prerepa Viswanadham Date: Thu, 24 Jul 2014 12:22:24 -0700 Subject: cleanup : delete BLE advertising related hidden state references in Bluetooth Adapter Change-Id: Ia58a46392157e274f8fc4696e8e25af480eb2d2a --- framework/java/android/bluetooth/BluetoothAdapter.java | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 453d60c6cd..b1cbb13323 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -354,27 +354,9 @@ public final class BluetoothAdapter { /** The profile is in disconnecting state */ public static final int STATE_DISCONNECTING = 3; - /** States for Bluetooth LE advertising */ - /** @hide */ - public static final int STATE_ADVERTISE_STARTING = 0; - /** @hide */ - public static final int STATE_ADVERTISE_STARTED = 1; - /** @hide */ - public static final int STATE_ADVERTISE_STOPPING = 2; - /** @hide */ - public static final int STATE_ADVERTISE_STOPPED = 3; - /** - * Force stopping advertising without callback in case the advertising app dies. - * @hide - */ - public static final int STATE_ADVERTISE_FORCE_STOPPING = 4; - /** @hide */ public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; - /** @hide */ - public static final int ADVERTISE_CALLBACK_SUCCESS = 0; - private static final int ADDRESS_LENGTH = 17; private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30; -- cgit v1.2.3 From 4c2da32c9fc3ce1ef25ff3f91906722e66c831d9 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 23 Jul 2014 23:34:00 -0700 Subject: Use Scanner for legacy LE scans(1/2). Also removed different scan methods from IBluetoothGatt and make BluetoothLeScanner and BluetoothLEAdvertiser singleton. Change-Id: Ifa2e950b50f100f5507a6dace3bd70db18d7f9ca --- .../java/android/bluetooth/BluetoothAdapter.java | 364 ++++++--------------- 1 file changed, 91 insertions(+), 273 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b1cbb13323..42b8dbf1a7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -21,6 +21,8 @@ import android.annotation.SdkConstant.SdkConstantType; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; +import android.bluetooth.le.ScanFilter; +import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.content.Context; @@ -371,12 +373,14 @@ public final class BluetoothAdapter { */ private static BluetoothAdapter sAdapter; + private static BluetoothLeScanner sBluetoothLeScanner; + private static BluetoothLeAdvertiser sBluetoothLeAdvertiser; + private final IBluetoothManager mManagerService; private IBluetooth mService; - private final Map mLeScanClients; - private final Handler mHandler; // Handler to post the advertise callback to run on main thread. private final Object mLock = new Object(); + private final Map mLeScanClients; /** * Get a handle to the default local Bluetooth adapter. @@ -411,8 +415,7 @@ public final class BluetoothAdapter { mService = managerService.registerAdapter(mManagerCallback); } catch (RemoteException e) {Log.e(TAG, "", e);} mManagerService = managerService; - mLeScanClients = new HashMap(); - mHandler = new Handler(Looper.getMainLooper()); + mLeScanClients = new HashMap(); } /** @@ -451,19 +454,40 @@ public final class BluetoothAdapter { } /** - * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations. + * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations, or + * null if Bluetooth LE Advertising is not support on this device. + *

+ * Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported + * on this device before calling this method. */ public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { - // TODO: Return null if this feature is not supported by hardware. - return new BluetoothLeAdvertiser(mManagerService); + if (getState() != STATE_ON) { + return null; + } + if (!isMultipleAdvertisementSupported()) { + return null; + } + synchronized(mLock) { + if (sBluetoothLeAdvertiser == null) { + sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); + } + } + return sBluetoothLeAdvertiser; } /** * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. */ public BluetoothLeScanner getBluetoothLeScanner() { - // TODO: Return null if BLE scan is not supported by hardware. - return new BluetoothLeScanner(mManagerService); + if (getState() != STATE_ON) { + return null; + } + synchronized(mLock) { + if (sBluetoothLeScanner == null) { + sBluetoothLeScanner = new BluetoothLeScanner(mManagerService); + } + } + return sBluetoothLeScanner; } /** @@ -1625,13 +1649,17 @@ public final class BluetoothAdapter { * instead. */ @Deprecated - public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) { + public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) { if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids); - if (callback == null) { if (DBG) Log.e(TAG, "startLeScan: null callback"); return false; } + BluetoothLeScanner scanner = getBluetoothLeScanner(); + if (scanner == null) { + if (DBG) Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner"); + return false; + } synchronized(mLeScanClients) { if (mLeScanClients.containsKey(callback)) { @@ -1646,13 +1674,50 @@ public final class BluetoothAdapter { return false; } - UUID uuid = UUID.randomUUID(); - GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids); - iGatt.registerClient(new ParcelUuid(uuid), wrapper); - if (wrapper.scanStarted()) { - mLeScanClients.put(callback, wrapper); - return true; + ScanCallback scanCallback = new ScanCallback() { + @Override + public void onScanResult(int callbackType, ScanResult result) { + if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { + // Should not happen. + Log.e(TAG, "LE Scan has already started"); + return; + } + ScanRecord scanRecord = result.getScanRecord(); + if (scanRecord == null) { + return; + } + if (serviceUuids != null) { + List uuids = new ArrayList(); + for (UUID uuid : serviceUuids) { + uuids.add(new ParcelUuid(uuid)); + } + List scanServiceUuids = scanRecord.getServiceUuids(); + if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) { + if (DBG) Log.d(TAG, "uuids does not match"); + return; + } + } + callback.onLeScan(result.getDevice(), result.getRssi(), + scanRecord.getBytes()); + } + }; + ScanSettings settings = new ScanSettings.Builder() + .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); + + List filters = new ArrayList(); + if (serviceUuids != null && serviceUuids.length > 0) { + // Note scan filter does not support matching an UUID array so we put one + // UUID to hardware and match the whole array in callback. + ScanFilter filter = new ScanFilter.Builder().setServiceUuid( + new ParcelUuid(serviceUuids[0])).build(); + filters.add(filter); } + scanner.startScan(filters, settings, scanCallback); + + mLeScanClients.put(callback, scanCallback); + return true; + } catch (RemoteException e) { Log.e(TAG,"",e); } @@ -1672,264 +1737,17 @@ public final class BluetoothAdapter { @Deprecated public void stopLeScan(LeScanCallback callback) { if (DBG) Log.d(TAG, "stopLeScan()"); - GattCallbackWrapper wrapper; - synchronized(mLeScanClients) { - wrapper = mLeScanClients.remove(callback); - if (wrapper == null) return; - } - wrapper.stopLeScan(); - } - - /** - * Bluetooth GATT interface callbacks - */ - private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub { - private static final int LE_CALLBACK_REG_TIMEOUT = 2000; - private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; - - private final LeScanCallback mLeScanCb; - - // mLeHandle 0: not registered - // -1: scan stopped - // >0: registered and scan started - private int mLeHandle; - private final UUID[] mScanFilter; - private WeakReference mBluetoothAdapter; - - public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, - LeScanCallback leScanCb, UUID[] uuid) { - mBluetoothAdapter = new WeakReference(bluetoothAdapter); - mLeScanCb = leScanCb; - mScanFilter = uuid; - mLeHandle = 0; - } - - public boolean scanStarted() { - return waitForRegisteration(LE_CALLBACK_REG_WAIT_COUNT); - } - - private boolean waitForRegisteration(int maxWaitCount) { - boolean started = false; - synchronized(this) { - if (mLeHandle == -1) return false; - int count = 0; - // wait for callback registration and LE scan to start - while (mLeHandle == 0 && count < maxWaitCount) { - try { - wait(LE_CALLBACK_REG_TIMEOUT); - } catch (InterruptedException e) { - Log.e(TAG, "Callback reg wait interrupted: " + e); - } - count++; - } - started = (mLeHandle > 0); - } - return started; - } - - public void stopLeScan() { - synchronized(this) { - if (mLeHandle <= 0) { - Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); - return; - } - BluetoothAdapter adapter = mBluetoothAdapter.get(); - if (adapter != null) { - try { - IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - iGatt.stopScan(mLeHandle, false); - iGatt.unregisterClient(mLeHandle); - } catch (RemoteException e) { - Log.e(TAG, "Failed to stop scan and unregister" + e); - } - } else { - Log.e(TAG, "stopLeScan, BluetoothAdapter is null"); - } - mLeHandle = -1; - notifyAll(); - } - } - - /** - * Application interface registered - app is ready to go - */ - public void onClientRegistered(int status, int clientIf) { - if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status + - " clientIf=" + clientIf); - synchronized(this) { - if (mLeHandle == -1) { - if (DBG) Log.d(TAG, "onClientRegistered LE scan canceled"); - } - - if (status == BluetoothGatt.GATT_SUCCESS) { - mLeHandle = clientIf; - IBluetoothGatt iGatt = null; - try { - BluetoothAdapter adapter = mBluetoothAdapter.get(); - if (adapter != null) { - iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - if (mScanFilter == null) { - iGatt.startScan(mLeHandle, false); - } else { - ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; - for(int i = 0; i != uuids.length; ++i) { - uuids[i] = new ParcelUuid(mScanFilter[i]); - } - iGatt.startScanWithUuids(mLeHandle, false, uuids); - } - } else { - Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); - mLeHandle = -1; - } - } catch (RemoteException e) { - Log.e(TAG, "fail to start le scan: " + e); - mLeHandle = -1; - } - if (mLeHandle == -1) { - // registration succeeded but start scan or advertise failed - if (iGatt != null) { - try { - iGatt.unregisterClient(mLeHandle); - } catch (RemoteException e) { - Log.e(TAG, "fail to unregister callback: " + mLeHandle + - " error: " + e); - } - } - } - } else { - // registration failed - mLeHandle = -1; - } - notifyAll(); - } - } - - public void onClientConnectionState(int status, int clientIf, - boolean connected, String address) { - // no op + BluetoothLeScanner scanner = getBluetoothLeScanner(); + if (scanner == null) { + return; } - - /** - * Callback reporting an LE scan result. - * @hide - */ - public void onScanResult(String address, int rssi, byte[] advData) { - if (VDBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); - - // Check null in case the scan has been stopped - synchronized(this) { - if (mLeHandle <= 0) return; + synchronized (mLeScanClients) { + ScanCallback scanCallback = mLeScanClients.remove(callback); + if (scanCallback == null) { + if (DBG) Log.d(TAG, "scan not started yet"); + return; } - try { - BluetoothAdapter adapter = mBluetoothAdapter.get(); - if (adapter == null) { - Log.d(TAG, "onScanResult, BluetoothAdapter null"); - return; - } - mLeScanCb.onLeScan(adapter.getRemoteDevice(address), rssi, advData); - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception: " + ex); - } - } - - public void onGetService(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid) { - // no op - } - - public void onGetIncludedService(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int inclSrvcType, int inclSrvcInstId, - ParcelUuid inclSrvcUuid) { - // no op - } - - public void onGetCharacteristic(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - int charProps) { - // no op - } - - public void onGetDescriptor(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - int descInstId, ParcelUuid descUuid) { - // no op - } - - public void onSearchComplete(String address, int status) { - // no op - } - - public void onCharacteristicRead(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, byte[] value) { - // no op - } - - public void onCharacteristicWrite(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid) { - // no op - } - - public void onNotify(String address, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - byte[] value) { - // no op - } - - public void onDescriptorRead(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - int descInstId, ParcelUuid descrUuid, byte[] value) { - // no op - } - - public void onDescriptorWrite(String address, int status, int srvcType, - int srvcInstId, ParcelUuid srvcUuid, - int charInstId, ParcelUuid charUuid, - int descInstId, ParcelUuid descrUuid) { - // no op - } - - public void onExecuteWrite(String address, int status) { - // no op - } - - public void onReadRemoteRssi(String address, int rssi, int status) { - // no op - } - - public void onAdvertiseStateChange(int advertiseState, int status) { - } - - @Override - public void onMultiAdvertiseCallback(int status) { - // no op - } - - @Override - public void onConfigureMTU(String address, int mtu, int status) { - // no op - } - - @Override - public void onConnectionCongested(String address, boolean congested) { - // no op - } - - @Override - public void onBatchScanResults(List results) { - // no op - } - - @Override - public void onFoundOrLost(boolean onFound, String address,int rssi, - byte[] advData) { - // no op + scanner.stopScan(scanCallback); } } } -- cgit v1.2.3 From e13f66a39c4f04457646c4ad238fbbe26062a6bd Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Tue, 12 Aug 2014 22:16:32 -0700 Subject: Clean up advertise and scan clients upon bluetooth down. Fixes b/16528460 This allows Advertiser and Scanner to be reused after bluetooth recycle, which follows same behavior for BluetoothAdapter. Also prints manufacturer data array for ScanRecord. Change-Id: I78bca40ac294433782a054bf2a00a775dac02d96 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 42b8dbf1a7..f0b609aec1 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1428,6 +1428,9 @@ public final class BluetoothAdapter { if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); synchronized (mManagerCallback) { mService = null; + mLeScanClients.clear(); + if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); + if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ try { if (cb != null) { -- cgit v1.2.3 From 52babc2fd3d3010760ef04f02e034919d8997e24 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 25 Sep 2014 19:05:03 -0700 Subject: Add support of advertising through standard instance.(1/4) Use config overlay to check whether peripheral mode is supported. Bug: 17552672 Change-Id: I1081bc84da9fe033426f82ece2ec74c2d663e3aa --- framework/java/android/bluetooth/BluetoothAdapter.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index f0b609aec1..210bbdf054 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -464,7 +464,8 @@ public final class BluetoothAdapter { if (getState() != STATE_ON) { return null; } - if (!isMultipleAdvertisementSupported()) { + if (!isMultipleAdvertisementSupported() && !isPeripheralModeSupported()) { + Log.e(TAG, "bluetooth le advertising not supported"); return null; } synchronized(mLock) { @@ -916,6 +917,21 @@ public final class BluetoothAdapter { return false; } + /** + * Returns whether peripheral mode is supported. + * + * @hide + */ + public boolean isPeripheralModeSupported() { + if (getState() != STATE_ON) return false; + try { + return mService.isPeripheralModeSupported(); + } catch (RemoteException e) { + Log.e(TAG, "failed to get peripheral mode capability: ", e); + } + return false; + } + /** * Return true if offloaded filters are supported * -- cgit v1.2.3 From 1afd3f4e1a3abdceeb9faa38f8445063612897ff Mon Sep 17 00:00:00 2001 From: Prerepa Viswanadham Date: Wed, 15 Oct 2014 16:36:01 -0700 Subject: Update javadoc comments for getBluetoothLeAdvertiser() To clarify that BluetoothLeAdvertiser object will return null when BT is off OR if the hw doesn't support these capabilities bug: 18006072 Change-Id: I635d7971711a3cae7c58f7a0636faf9a03f19970 --- framework/java/android/bluetooth/BluetoothAdapter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index f0b609aec1..5564af789e 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -454,8 +454,9 @@ public final class BluetoothAdapter { } /** - * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations, or - * null if Bluetooth LE Advertising is not support on this device. + * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations. + * Will return null if Bluetooth is turned off or if Bluetooth LE Advertising is not + * supported on this device. *

* Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported * on this device before calling this method. -- cgit v1.2.3 From 716c1fbbe13bb8188c8de7dd9e6da0c86eb389b9 Mon Sep 17 00:00:00 2001 From: Andre Eisenbach Date: Wed, 29 Oct 2014 12:13:38 -0700 Subject: Fix crash during Bluetooth on/off stress test Bug: 18106938 Change-Id: Icdeb736d89d5926264f2043455ccbc3760fd5d29 --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index f2e03cf892..c262baed4f 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1445,7 +1445,7 @@ public final class BluetoothAdapter { if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); synchronized (mManagerCallback) { mService = null; - mLeScanClients.clear(); + if (mLeScanClients != null) mLeScanClients.clear(); if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ -- cgit v1.2.3 From b6600692fed1b9b6275443d8fdd1160fbe155d09 Mon Sep 17 00:00:00 2001 From: Matthew Xie Date: Fri, 6 Feb 2015 14:09:54 -0800 Subject: Separate the protection of mProxyServiceStateCallbacks from that of mService The overuse of mManagerCallback caused a deaklock. Bug: 19264190 Change-Id: Iff20019ff0c99bb5f36435feb15e43e280a8e102 --- .../java/android/bluetooth/BluetoothAdapter.java | 42 ++++++++++++---------- 1 file changed, 23 insertions(+), 19 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index c262baed4f..b8f4bf8f04 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1429,14 +1429,16 @@ public final class BluetoothAdapter { if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); synchronized (mManagerCallback) { mService = bluetoothService; - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ - try { - if (cb != null) { - cb.onBluetoothServiceUp(bluetoothService); - } else { - Log.d(TAG, "onBluetoothServiceUp: cb is null!!!"); - } - } catch (Exception e) { Log.e(TAG,"",e);} + synchronized (mProxyServiceStateCallbacks) { + for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ + try { + if (cb != null) { + cb.onBluetoothServiceUp(bluetoothService); + } else { + Log.d(TAG, "onBluetoothServiceUp: cb is null!!!"); + } + } catch (Exception e) { Log.e(TAG,"",e);} + } } } } @@ -1448,14 +1450,16 @@ public final class BluetoothAdapter { if (mLeScanClients != null) mLeScanClients.clear(); if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ - try { - if (cb != null) { - cb.onBluetoothServiceDown(); - } else { - Log.d(TAG, "onBluetoothServiceDown: cb is null!!!"); - } - } catch (Exception e) { Log.e(TAG,"",e);} + synchronized (mProxyServiceStateCallbacks) { + for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ + try { + if (cb != null) { + cb.onBluetoothServiceDown(); + } else { + Log.d(TAG, "onBluetoothServiceDown: cb is null!!!"); + } + } catch (Exception e) { Log.e(TAG,"",e);} + } } } } @@ -1596,10 +1600,10 @@ public final class BluetoothAdapter { return mManagerService; } - private ArrayList mProxyServiceStateCallbacks = new ArrayList(); + final private ArrayList mProxyServiceStateCallbacks = new ArrayList(); /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { - synchronized (mManagerCallback) { + synchronized (mProxyServiceStateCallbacks) { if (cb == null) { Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback"); } else if (!mProxyServiceStateCallbacks.contains(cb)) { @@ -1610,7 +1614,7 @@ public final class BluetoothAdapter { } /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) { - synchronized (mManagerCallback) { + synchronized (mProxyServiceStateCallbacks) { mProxyServiceStateCallbacks.remove(cb); } } -- cgit v1.2.3 From a758133e0b011657977776b1c649915799112a45 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Sat, 28 Feb 2015 13:12:17 -0500 Subject: Remove unused imports in frameworks/base. Change-Id: I031443de83f93eb57a98863001826671b18f3b17 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b8f4bf8f04..be26eac31d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -26,9 +26,7 @@ import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.content.Context; -import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceManager; @@ -36,7 +34,6 @@ import android.util.Log; import android.util.Pair; import java.io.IOException; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -- cgit v1.2.3 From 43c66e29b0fe8ddaffea21a1ba178a8c8f0e8d75 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 19 Mar 2015 15:09:56 -0700 Subject: Add API for BLE_SCAN_ALWAYS_AVAILABLE feature. Change-Id: I83e966d4db076db367ded71bfb50c39e57568156 --- .../java/android/bluetooth/BluetoothAdapter.java | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b8f4bf8f04..ee055a5d50 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -18,6 +18,7 @@ package android.bluetooth; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemApi; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; @@ -208,6 +209,23 @@ public final class BluetoothAdapter { public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"; + /** + * Activity Action: Show a system activity that allows user to enable BLE scans even when + * Bluetooth is turned off.

+ * + * Notification of result of this activity is posted using + * {@link android.app.Activity#onActivityResult}. The resultCode will be + * {@link android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or + * {@link android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an + * error occurred. + * + * @hide + */ + @SystemApi + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = + "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE"; + /** * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter * has changed. @@ -918,6 +936,22 @@ public final class BluetoothAdapter { return false; } + /** + * Returns {@code true} if BLE scan is always available, {@code false} otherwise.

+ * + * If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan} and + * fetch scan results even when Bluetooth is turned off.

+ * + * To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}. + * + * @hide + */ + @SystemApi + public boolean isBleScanAlwaysAvailable() { + // TODO: implement after Settings UI change. + return false; + } + /** * Returns whether peripheral mode is supported. * -- cgit v1.2.3 From 98d25c5f895ac94d6af09309bd45553b2e8d7510 Mon Sep 17 00:00:00 2001 From: Prerepa Viswanadham Date: Tue, 7 Apr 2015 14:36:53 -0700 Subject: Onfound onlost feature. Change-Id: I5475cb21183abab8cf04af486ff7692396801b92 Signed-off-by: Prerepa Viswanadham --- framework/java/android/bluetooth/BluetoothAdapter.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ee055a5d50..0442d09440 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -997,6 +997,24 @@ public final class BluetoothAdapter { return false; } + /** + * Return true if hardware has entries available for matching beacons + * + * @return true if there are hw entries available for matching beacons + * @hide + */ + public boolean isHardwareTrackingFiltersAvailable() { + if (getState() != STATE_ON) return false; + try { + synchronized(mManagerCallback) { + if(mService != null) return (mService.numOfHwTrackFiltersAvailable() != 0); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + return false; + } + /** * Return the record of {@link BluetoothActivityEnergyInfo} object that * has the activity and energy info. This can be used to ascertain what -- cgit v1.2.3 From c0a7c93812c39589a1c90a18c93ddb3a4e36205a Mon Sep 17 00:00:00 2001 From: Casper Bonde Date: Thu, 9 Apr 2015 09:24:48 +0200 Subject: OBEX Over L2CAP + SDP search API for BT profiles - Updated OBEX to support SRM - Added support for OBEX over l2cap and SRM. - Minor bugfixes, and reduce CPU load ALOT - Added support to send responses without body data. - Extend BluetoothSocket to support L2CAP - Added functionality to get the channel number needed to be able to create an SDP record with the channel number. - Added interface to get socket type and max packet sizes. - Added interface to perform SDP search and get the resulting SDP record data. Change-Id: I9d37a00ce73dfffc0e3ce03eab5511ba3a86e5b8 --- .../java/android/bluetooth/BluetoothAdapter.java | 48 +++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 0442d09440..ac74a621a7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1,5 +1,6 @@ /* - * Copyright (C) 2009-2014 The Android Open Source Project + * Copyright (C) 2009-2015 The Android Open Source Project + * Copyright (C) 2015 Samsung LSI * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -377,6 +378,18 @@ public final class BluetoothAdapter { /** @hide */ public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; + + /** When creating a ServerSocket using listenUsingRfcommOn() or + * listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create + * a ServerSocket that auto assigns a channel number to the first + * bluetooth socket. + * The channel number assigned to this first Bluetooth Socket will + * be stored in the ServerSocket, and reused for subsequent Bluetooth + * sockets. + * @hide */ + public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2; + + private static final int ADDRESS_LENGTH = 17; private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30; @@ -1144,6 +1157,9 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, true, true, channel); int errno = socket.mSocket.bindListen(); + if(channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + socket.setChannel(socket.mSocket.getPort()); + } if (errno != 0) { //TODO(BT): Throw the same exception error code // that the previous code was using. @@ -1278,6 +1294,9 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, false, false, port); int errno = socket.mSocket.bindListen(); + if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + socket.setChannel(socket.mSocket.getPort()); + } if (errno != 0) { //TODO(BT): Throw the same exception error code // that the previous code was using. @@ -1300,6 +1319,9 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, false, true, port); int errno = socket.mSocket.bindListen(); + if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + socket.setChannel(socket.mSocket.getPort()); + } if (errno < 0) { //TODO(BT): Throw the same exception error code // that the previous code was using. @@ -1329,6 +1351,30 @@ public final class BluetoothAdapter { return socket; } + /** + * Construct an encrypted, authenticated, L2CAP server socket. + * Call #accept to retrieve connections to this socket. + * @return An L2CAP BluetoothServerSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + * @hide + */ + public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { + BluetoothServerSocket socket = new BluetoothServerSocket( + BluetoothSocket.TYPE_L2CAP, true, true, port); + int errno = socket.mSocket.bindListen(); + if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + socket.setChannel(socket.mSocket.getPort()); + } + if (errno != 0) { + //TODO(BT): Throw the same exception error code + // that the previous code was using. + //socket.mSocket.throwErrnoNative(errno); + throw new IOException("Error: " + errno); + } + return socket; + } + /** * Read the local Out of Band Pairing Data *

Requires {@link android.Manifest.permission#BLUETOOTH} -- cgit v1.2.3 From 5e8cdc7f00265c4adb2b22935eb28708fdbf29ae Mon Sep 17 00:00:00 2001 From: Nitin Arora Date: Mon, 2 Mar 2015 15:03:51 -0800 Subject: 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 --- .../java/android/bluetooth/BluetoothAdapter.java | 312 ++++++++++++++++++++- 1 file changed, 304 insertions(+), 8 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ac74a621a7..88bb626bfd 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/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"; @@ -155,6 +164,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 @@ -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(); + 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(); @@ -541,6 +598,178 @@ public final class BluetoothAdapter { return false; } + /** + * Return true if Bluetooth LE(Always BLE On feature) is currently + * enabled and ready for use + *

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(). + * + *

If the internal Adapter state is STATE_BLE_ON, this would trigger the transition + * to STATE_OFF and completely shut-down Bluetooth + * + *

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 + * + *

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. + *

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. + * + *

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. *

Possible return values are @@ -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 @@ -569,6 +805,49 @@ public final class BluetoothAdapter { return STATE_OFF; } + /** + * Get the current state of the local Bluetooth adapter + *

This returns current internal state of Adapter including LE ON/OFF + * + *

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}. + *

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—do not use without explicit * user action to turn on Bluetooth. @@ -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: "); + } }; /** -- cgit v1.2.3 From 82fb4059b7d431b1be9c5a044da37c87283af17a Mon Sep 17 00:00:00 2001 From: Casper Bonde Date: Thu, 19 Mar 2015 10:36:45 +0100 Subject: Add support for Bluetooth Sim Access Profile (2/4) Change-Id: I6c634aa38d31a7b5a98c9089840557257fd58209 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 88bb626bfd..d7705a4026 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1746,6 +1746,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.HEADSET_CLIENT) { BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener); return true; + } else if (profile == BluetoothProfile.SAP) { + BluetoothSap sap = new BluetoothSap(context, listener); + return true; } else { return false; } @@ -1810,6 +1813,10 @@ public final class BluetoothAdapter { BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy; headsetClient.close(); break; + case BluetoothProfile.SAP: + BluetoothSap sap = (BluetoothSap)proxy; + sap.close(); + break; } } -- cgit v1.2.3 From 20843f715f14d250063c0b0786b8019fcc2365d6 Mon Sep 17 00:00:00 2001 From: Yorke Lee Date: Wed, 15 Apr 2015 11:55:20 -0700 Subject: Fix make update-api Change-Id: Iaee002c64096fbd6ba05d6484cc50840146a4af0 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 ------ 1 file changed, 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index d7705a4026..875aef6264 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -124,9 +124,6 @@ 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"; @@ -137,9 +134,6 @@ 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"; -- cgit v1.2.3 From 7688f220e1dd3457c608aabf39ab900606a387a8 Mon Sep 17 00:00:00 2001 From: Nitin Arora Date: Mon, 2 Mar 2015 15:03:51 -0800 Subject: 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 --- .../java/android/bluetooth/BluetoothAdapter.java | 312 ++++++++++++++++++++- 1 file changed, 304 insertions(+), 8 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 87d5bb030e..dd030f8538 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -32,6 +32,9 @@ import android.os.IBinder; 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; @@ -118,6 +121,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"; @@ -128,6 +134,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"; @@ -152,6 +161,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 @@ -363,6 +390,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 */ @@ -374,6 +434,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 @@ -444,6 +505,7 @@ public final class BluetoothAdapter { } catch (RemoteException e) {Log.e(TAG, "", e);} mManagerService = managerService; mLeScanClients = new HashMap(); + mToken = new Binder(); } /** @@ -490,11 +552,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) { @@ -509,9 +569,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); @@ -529,7 +587,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(); @@ -538,6 +595,178 @@ public final class BluetoothAdapter { return false; } + /** + * Return true if Bluetooth LE(Always BLE On feature) is currently + * enabled and ready for use + *

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(). + * + *

If the internal Adapter state is STATE_BLE_ON, this would trigger the transition + * to STATE_OFF and completely shut-down Bluetooth + * + *

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 + * + *

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. + *

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. + * + *

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. *

Possible return values are @@ -556,6 +785,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 @@ -566,6 +802,49 @@ public final class BluetoothAdapter { return STATE_OFF; } + /** + * Get the current state of the local Bluetooth adapter + *

This returns current internal state of Adapter including LE ON/OFF + * + *

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}. + *

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—do not use without explicit * user action to turn on Bluetooth. @@ -594,10 +873,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);} @@ -1558,6 +1850,10 @@ public final class BluetoothAdapter { } } } + + public void onBrEdrDown() { + if (VDBG) Log.i(TAG, "on QBrEdrDown: "); + } }; /** -- cgit v1.2.3 From d8355fbc2eebadece0ee3beae25361be32d9ee34 Mon Sep 17 00:00:00 2001 From: Casper Bonde Date: Thu, 19 Mar 2015 10:36:45 +0100 Subject: Add support for Bluetooth Sim Access Profile (2/4) Change-Id: I6c634aa38d31a7b5a98c9089840557257fd58209 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index dd030f8538..10ee21d2fd 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1743,6 +1743,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.HEADSET_CLIENT) { BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener); return true; + } else if (profile == BluetoothProfile.SAP) { + BluetoothSap sap = new BluetoothSap(context, listener); + return true; } else { return false; } @@ -1807,6 +1810,10 @@ public final class BluetoothAdapter { BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy; headsetClient.close(); break; + case BluetoothProfile.SAP: + BluetoothSap sap = (BluetoothSap)proxy; + sap.close(); + break; } } -- cgit v1.2.3 From ed9c9583f3e5249c77973f22d7387847f601bfb3 Mon Sep 17 00:00:00 2001 From: Yorke Lee Date: Wed, 15 Apr 2015 11:55:20 -0700 Subject: Fix make update-api Change-Id: Iaee002c64096fbd6ba05d6484cc50840146a4af0 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 ------ 1 file changed, 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 10ee21d2fd..2418e82425 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -121,9 +121,6 @@ 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"; @@ -134,9 +131,6 @@ 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"; -- cgit v1.2.3 From 7968421c32372cc12019c16d533b4b8ac1f38698 Mon Sep 17 00:00:00 2001 From: Prerepa Viswanadham Date: Thu, 9 Apr 2015 17:14:50 -0700 Subject: Manage onfound/lost resources (1/2) Provide error callback to app if advertisement tracking resources can't be reserved Change-Id: Ie66b2ec7a64b24bbdf3bb22003a4a7eb46623792 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 875aef6264..3efbc2da37 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1305,9 +1305,12 @@ public final class BluetoothAdapter { public boolean isHardwareTrackingFiltersAvailable() { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if(mService != null) return (mService.numOfHwTrackFiltersAvailable() != 0); + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + return false; } + return (iGatt.numHwTrackFiltersAvailable() != 0); } catch (RemoteException e) { Log.e(TAG, "", e); } -- cgit v1.2.3 From ea513c5d27bae3008d787bc42c6ad8ab6879b9e9 Mon Sep 17 00:00:00 2001 From: Prerepa Viswanadham Date: Thu, 23 Apr 2015 14:44:50 -0700 Subject: Reduce log spam in BluetoothAdapter for getState. Change-Id: I38995fc55f12b000d58a769ed67aff623865169b --- framework/java/android/bluetooth/BluetoothAdapter.java | 1 - 1 file changed, 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 2418e82425..79e560ff9f 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -792,7 +792,6 @@ public final class BluetoothAdapter { // mService is null, handle that case } } catch (RemoteException e) {Log.e(TAG, "", e);} - if (DBG) Log.d(TAG, "" + hashCode() + ": getState() : mService = null. Returning STATE_OFF"); return STATE_OFF; } -- cgit v1.2.3 From 017ad5c0adcba3afbdd2dee256f9013a8b3c610e Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Thu, 23 Apr 2015 18:25:08 -0700 Subject: Bluetooth document fix: remove reference from open API to hidden entities Change-Id: I183ae1083727d2e2b96aa503d0e90d81ce3b1a82 --- framework/java/android/bluetooth/BluetoothAdapter.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 515be038d3..d4e79be324 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -133,10 +133,7 @@ public final class BluetoothAdapter { * {@link #STATE_OFF}, * {@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}, + * {@link #STATE_TURNING_OFF} */ public static final String EXTRA_PREVIOUS_STATE = "android.bluetooth.adapter.extra.PREVIOUS_STATE"; -- cgit v1.2.3 From 0515c51a52886def674d2ced9edc0be258fead4c Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Fri, 24 Apr 2015 18:06:59 -0700 Subject: Fix documentation - non-public API. Change-Id: I418bf47b197936b2f50b231425312d5b6d272df8 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index d4e79be324..3044a9494a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -121,9 +121,6 @@ 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"; -- cgit v1.2.3 From 20e41df181aa2e2eba6f9912bdce3aeeac70ce51 Mon Sep 17 00:00:00 2001 From: tturney Date: Wed, 29 Apr 2015 12:01:00 -0700 Subject: Fix typo. bug: b/20610710 Change-Id: I7b8e0331daddadcb31f45650f5cd937b1f4f90ff --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3044a9494a..5c676a5a79 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -389,7 +389,7 @@ public final class BluetoothAdapter { * @hide */ public static final String ACTION_BLE_STATE_CHANGED = - "anrdoid.bluetooth.adapter.action.BLE_STATE_CHANGED"; + "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; /** * Broadcast Action: The notifys Bluetooth ACL connected event. This will be -- cgit v1.2.3 From 3acb7e832747b2a14dd7db79dfd47e6d6a5dd066 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Sun, 26 Apr 2015 17:04:29 -0700 Subject: Honor Ble scanning settings from Settings UI. Bug:20643039 Change-Id: Ib1465108e26b8537c9da1bfbb31a99d2e33da910 --- .../java/android/bluetooth/BluetoothAdapter.java | 31 +++++++--------------- 1 file changed, 9 insertions(+), 22 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3044a9494a..b63192043f 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -34,6 +34,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.app.ActivityThread; import android.os.SystemProperties; +import android.provider.Settings; import android.os.Binder; import android.util.Log; import android.util.Pair; @@ -631,24 +632,6 @@ public final class BluetoothAdapter { } } - /** - * 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(). * @@ -676,7 +659,7 @@ public final class BluetoothAdapter { * @hide */ public boolean disableBLE() { - if (isLEAlwaysOnEnabled() != true) return false; + if (!isBleScanAlwaysAvailable()) return false; int state = getLeState(); if (state == BluetoothAdapter.STATE_ON) { @@ -738,7 +721,7 @@ public final class BluetoothAdapter { * @hide */ public boolean enableBLE() { - if (isLEAlwaysOnEnabled() != true) return false; + if (!isBleScanAlwaysAvailable()) return false; if (isLeEnabled() == true) { if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!"); @@ -1243,8 +1226,12 @@ public final class BluetoothAdapter { */ @SystemApi public boolean isBleScanAlwaysAvailable() { - // TODO: implement after Settings UI change. - return false; + try { + return mManagerService.isBleScanAlwaysAvailable(); + } catch (RemoteException e) { + Log.e(TAG, "remote expection when calling isBleScanAlwaysAvailable", e); + return false; + } } /** -- cgit v1.2.3 From 35566b2b38c4925a8a1c5de8578cc3bfc6ee12bb Mon Sep 17 00:00:00 2001 From: Andre Eisenbach Date: Mon, 4 May 2015 13:28:04 -0700 Subject: BluetoothSap class should not be public Bug: 20823932 Change-Id: I87dfa10b994f7a14c123bb384925c08b34bfbe67 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 9b4dcc6b34..0a778681b5 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1692,7 +1692,8 @@ public final class BluetoothAdapter { * @param context Context of the application * @param listener The service Listener for connection callbacks. * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH}, - * {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}. + * {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. + * {@link BluetoothProfile#GATT} or {@link BluetoothProfile#GATT_SERVER}. * @return true on success, false on error */ public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, -- cgit v1.2.3 From baa2d7c9b389a590c67c793bd6227c1e5b37775d Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 7 May 2015 16:25:33 -0700 Subject: Allow obtaining BLE capabilities in BLE scan only mode. Bug:20923734 Change-Id: I7f3e5fd4410da39922be4512e4ba6ccdeb32887d --- framework/java/android/bluetooth/BluetoothAdapter.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 0a778681b5..ec6f18d217 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -28,14 +28,11 @@ import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.content.Context; +import android.os.Binder; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceManager; -import android.app.ActivityThread; -import android.os.SystemProperties; -import android.provider.Settings; -import android.os.Binder; import android.util.Log; import android.util.Pair; @@ -1255,7 +1252,7 @@ public final class BluetoothAdapter { * @return true if chipset supports on-chip filtering */ public boolean isOffloadedFilteringSupported() { - if (getState() != STATE_ON) return false; + if (!getLeAccess()) return false; try { return mService.isOffloadedFilteringSupported(); } catch (RemoteException e) { @@ -1270,7 +1267,7 @@ public final class BluetoothAdapter { * @return true if chipset supports on-chip scan batching */ public boolean isOffloadedScanBatchingSupported() { - if (getState() != STATE_ON) return false; + if (!getLeAccess()) return false; try { return mService.isOffloadedScanBatchingSupported(); } catch (RemoteException e) { @@ -1286,7 +1283,7 @@ public final class BluetoothAdapter { * @hide */ public boolean isHardwareTrackingFiltersAvailable() { - if (getState() != STATE_ON) return false; + if (!getLeAccess()) return false; try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); if (iGatt == null) { -- cgit v1.2.3 From 27ce6cfbe105e5c36e19b1f76bc9b8f29710b331 Mon Sep 17 00:00:00 2001 From: Tor Norbye Date: Thu, 23 Apr 2015 17:10:21 -0700 Subject: Add bluetooth permission annotations Change-Id: I5bc86f8ec6ea5c873f1e14dab0e0c47c5c9df7f7 --- .../java/android/bluetooth/BluetoothAdapter.java | 39 +++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ec6f18d217..8768f400b1 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -17,6 +17,9 @@ package android.bluetooth; +import android.Manifest; +import android.annotation.IntDef; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; @@ -37,6 +40,8 @@ import android.util.Log; import android.util.Pair; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -133,6 +138,12 @@ public final class BluetoothAdapter { public static final String EXTRA_PREVIOUS_STATE = "android.bluetooth.adapter.extra.PREVIOUS_STATE"; + /** @hide */ + @IntDef({STATE_OFF, STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, STATE_BLE_TURNING_ON, + STATE_BLE_ON, STATE_BLE_TURNING_OFF}) + @Retention(RetentionPolicy.SOURCE) + public @interface AdapterState {} + /** * Indicates the local Bluetooth adapter is off. */ @@ -273,6 +284,11 @@ public final class BluetoothAdapter { public static final String EXTRA_PREVIOUS_SCAN_MODE = "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE"; + /** @hide */ + @IntDef({SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE}) + @Retention(RetentionPolicy.SOURCE) + public @interface ScanMode {} + /** * Indicates that both inquiry scan and page scan are disabled on the local * Bluetooth adapter. Therefore this device is neither discoverable @@ -578,6 +594,7 @@ public final class BluetoothAdapter { * * @return true if the local adapter is turned on */ + @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isEnabled() { try { synchronized(mManagerCallback) { @@ -752,6 +769,8 @@ public final class BluetoothAdapter { * * @return current state of Bluetooth adapter */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + @AdapterState public int getState() { try { synchronized(mManagerCallback) { @@ -792,6 +811,8 @@ public final class BluetoothAdapter { * @return current state of Bluetooth adapter * @hide */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + @AdapterState public int getLeState() { try { synchronized(mManagerCallback) { @@ -845,6 +866,7 @@ public final class BluetoothAdapter { * @return true to indicate adapter startup has begun, or false on * immediate error */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean enable() { int state = STATE_OFF; if (isEnabled() == true){ @@ -893,6 +915,7 @@ public final class BluetoothAdapter { * @return true to indicate adapter shutdown has begun, or false on * immediate error */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean disable() { try { return mManagerService.disable(true); @@ -925,6 +948,7 @@ public final class BluetoothAdapter { * * @return Bluetooth hardware address as string */ + @RequiresPermission(Manifest.permission.BLUETOOTH) public String getAddress() { try { return mManagerService.getAddress(); @@ -998,6 +1022,7 @@ public final class BluetoothAdapter { * @param name a valid Bluetooth name * @return true if the name was set, false otherwise */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String name) { if (getState() != STATE_ON) return false; try { @@ -1024,6 +1049,8 @@ public final class BluetoothAdapter { * * @return scan mode */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + @ScanMode public int getScanMode() { if (getState() != STATE_ON) return SCAN_MODE_NONE; try { @@ -1062,7 +1089,7 @@ public final class BluetoothAdapter { * @return true if the scan mode was set, false otherwise * @hide */ - public boolean setScanMode(int mode, int duration) { + public boolean setScanMode(@ScanMode int mode, int duration) { if (getState() != STATE_ON) return false; try { synchronized(mManagerCallback) { @@ -1130,6 +1157,7 @@ public final class BluetoothAdapter { * * @return true on success, false on error */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean startDiscovery() { if (getState() != STATE_ON) return false; try { @@ -1157,6 +1185,7 @@ public final class BluetoothAdapter { * * @return true on success, false on error */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelDiscovery() { if (getState() != STATE_ON) return false; try { @@ -1186,6 +1215,7 @@ public final class BluetoothAdapter { * * @return true if discovering */ + @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isDiscovering() { if (getState() != STATE_ON) return false; try { @@ -1345,6 +1375,7 @@ public final class BluetoothAdapter { * * @return unmodifiable set of {@link BluetoothDevice}, or null on error */ + @RequiresPermission(Manifest.permission.BLUETOOTH) public Set getBondedDevices() { if (getState() != STATE_ON) { return toDeviceSet(new BluetoothDevice[0]); @@ -1396,6 +1427,7 @@ public final class BluetoothAdapter { * {@link BluetoothProfile#STATE_CONNECTED}, * {@link BluetoothProfile#STATE_DISCONNECTING} */ + @RequiresPermission(Manifest.permission.BLUETOOTH) public int getProfileConnectionState(int profile) { if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED; try { @@ -1460,6 +1492,7 @@ public final class BluetoothAdapter { * @throws IOException on error, for example Bluetooth not available, or * insufficient permissions, or channel in use. */ + @RequiresPermission(Manifest.permission.BLUETOOTH) public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) throws IOException { return createNewRfcommSocketAndRecord(name, uuid, true, true); @@ -1491,6 +1524,7 @@ public final class BluetoothAdapter { * @throws IOException on error, for example Bluetooth not available, or * insufficient permissions, or channel in use. */ + @RequiresPermission(Manifest.permission.BLUETOOTH) public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid) throws IOException { return createNewRfcommSocketAndRecord(name, uuid, false, false); @@ -2032,6 +2066,7 @@ public final class BluetoothAdapter { * instead. */ @Deprecated + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean startLeScan(LeScanCallback callback) { return startLeScan(null, callback); } @@ -2052,6 +2087,7 @@ public final class BluetoothAdapter { * instead. */ @Deprecated + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) { if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids); if (callback == null) { @@ -2138,6 +2174,7 @@ public final class BluetoothAdapter { * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead. */ @Deprecated + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public void stopLeScan(LeScanCallback callback) { if (DBG) Log.d(TAG, "stopLeScan()"); BluetoothLeScanner scanner = getBluetoothLeScanner(); -- cgit v1.2.3 From 252a61970f78294b0d6d3d85c0dcdb9af7f588b4 Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Tue, 12 May 2015 19:13:36 -0700 Subject: Do not report WiFi and Bluetooth MAC addresses - framework. As a part of the new runtime permissions work we are limiting the PII apps can access. BT and WiFi MAC addresses are PII and based on our research there is no valid use case for app dev to get these addresses aside of user tracking which we are trying to limit. bug:21078858 Change-Id: Ib48223b272c0fd4f5c36acc889d4f44df204b309 --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8768f400b1..b22b914686 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -95,6 +95,14 @@ public final class BluetoothAdapter { private static final boolean DBG = true; private static final boolean VDBG = false; + /** + * Default MAC address reported to a client that does not have the + * android.permission.LOCAL_MAC_ADDRESS permission. + * + * @hide + */ + public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; + /** * Sentinel error value for this class. Guaranteed to not equal any other * integer constant in this class. Provided as a convenience for functions -- cgit v1.2.3 From 5a6856971729f446fca4392eb7f09ccb88484e93 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Mon, 1 Jun 2015 12:14:28 -0700 Subject: Expose a few system APIs for BLE scan only mode. Bug: 21562349 Change-Id: Ifc58efcf01edac5b4f9e5266adb966e7bc492209 --- .../java/android/bluetooth/BluetoothAdapter.java | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b22b914686..8107a97e9d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -410,6 +410,7 @@ public final class BluetoothAdapter { * Broadcast Action: The Bluetooth adapter state has changed in LE only mode. * @hide */ + @SystemApi public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; @@ -620,17 +621,18 @@ public final class BluetoothAdapter { * @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; + @SystemApi + 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; } /** @@ -680,6 +682,7 @@ public final class BluetoothAdapter { * immediate error * @hide */ + @SystemApi public boolean disableBLE() { if (!isBleScanAlwaysAvailable()) return false; @@ -742,6 +745,7 @@ public final class BluetoothAdapter { * immediate error * @hide */ + @SystemApi public boolean enableBLE() { if (!isBleScanAlwaysAvailable()) return false; -- cgit v1.2.3 From 60d77c2c9ceea76d7e4e32ab173ef3da64ff607e Mon Sep 17 00:00:00 2001 From: Casper Bonde Date: Tue, 21 Apr 2015 13:12:05 +0200 Subject: Add support for MITM for BluetoothSockets (1/4) This change adds an option to enforce Man-in-the-middle protection for the authentication process. This feature is needed for the Sim Access Profile. Change-Id: Ia3ef0caeb750f88608c9fa6bf6367d1c77de4cf3 Signed-off-by: Casper Bonde --- .../java/android/bluetooth/BluetoothAdapter.java | 48 ++++++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8107a97e9d..ab3f7bcdf5 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1467,10 +1467,31 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException { + return listenUsingRfcommOn(channel, false); + } + + /** + * Create a listening, secure RFCOMM Bluetooth socket. + *

A remote device connecting to this socket will be authenticated and + * communication on this socket will be encrypted. + *

Use {@link BluetoothServerSocket#accept} to retrieve incoming + * connections from a listening {@link BluetoothServerSocket}. + *

Valid RFCOMM channels are in range 1 to 30. + *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + *

To auto assign a channel without creating a SDP record use + * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. + * @param channel RFCOMM channel to listen on + * @param mitm enforce man-in-the-middle protection for authentication. + * @return a listening RFCOMM BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or + * insufficient permissions, or channel in use. + * @hide + */ + public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm) throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, true, true, channel); + BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm); int errno = socket.mSocket.bindListen(); - if(channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); } if (errno != 0) { @@ -1669,14 +1690,18 @@ public final class BluetoothAdapter { /** * Construct an encrypted, authenticated, L2CAP server socket. * Call #accept to retrieve connections to this socket. + *

To auto assign a port without creating a SDP record use + * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. + * @param port the PSM to listen on + * @param mitm enforce man-in-the-middle protection for authentication. * @return An L2CAP BluetoothServerSocket * @throws IOException On error, for example Bluetooth not available, or * insufficient permissions. * @hide */ - public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { + public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm) throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_L2CAP, true, true, port); + BluetoothSocket.TYPE_L2CAP, true, true, port, mitm); int errno = socket.mSocket.bindListen(); if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -1690,6 +1715,21 @@ public final class BluetoothAdapter { return socket; } + /** + * Construct an encrypted, authenticated, L2CAP server socket. + * Call #accept to retrieve connections to this socket. + *

To auto assign a port without creating a SDP record use + * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. + * @param port the PSM to listen on + * @return An L2CAP BluetoothServerSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + * @hide + */ + public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { + return listenUsingL2capOn(port, false); + } + /** * Read the local Out of Band Pairing Data *

Requires {@link android.Manifest.permission#BLUETOOTH} -- cgit v1.2.3 From 91276018bd5dd6c61dcd69cd87090ba022b532e7 Mon Sep 17 00:00:00 2001 From: Casper Bonde Date: Fri, 8 May 2015 14:32:24 +0200 Subject: SAP: Make it possible to enforce a 16-digit pin code (4/5) This change enable the posibility to enforce using a 16-digit pin or MITM for a RFCOMM or L2CAP connection. This is needed for the SIM access profile. Change-Id: I3205013f9e758c353381442a86845dab467780f8 Signed-off-by: Casper Bonde --- framework/java/android/bluetooth/BluetoothAdapter.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ab3f7bcdf5..97afafa4c8 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1467,7 +1467,7 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException { - return listenUsingRfcommOn(channel, false); + return listenUsingRfcommOn(channel, false, false); } /** @@ -1482,14 +1482,17 @@ public final class BluetoothAdapter { * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. * @param channel RFCOMM channel to listen on * @param mitm enforce man-in-the-middle protection for authentication. + * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 connections. * @return a listening RFCOMM BluetoothServerSocket * @throws IOException on error, for example Bluetooth not available, or * insufficient permissions, or channel in use. * @hide */ - public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm) throws IOException { + public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm, + boolean min16DigitPin) + throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm); + BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm, min16DigitPin); int errno = socket.mSocket.bindListen(); if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -1694,14 +1697,16 @@ public final class BluetoothAdapter { * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. * @param port the PSM to listen on * @param mitm enforce man-in-the-middle protection for authentication. + * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 connections. * @return An L2CAP BluetoothServerSocket * @throws IOException On error, for example Bluetooth not available, or * insufficient permissions. * @hide */ - public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm) throws IOException { + public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin) + throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_L2CAP, true, true, port, mitm); + BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, min16DigitPin); int errno = socket.mSocket.bindListen(); if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -1727,7 +1732,7 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { - return listenUsingL2capOn(port, false); + return listenUsingL2capOn(port, false, false); } /** -- cgit v1.2.3 From c74cf3a0a338cd7395b9748f397aeb23ffbe8b27 Mon Sep 17 00:00:00 2001 From: Florian Salbrechter Date: Fri, 31 Jul 2015 14:43:15 +0100 Subject: Fix wrong javadoc in BluetoothAdapter. Calling getSystemService(BLUETOOTH_SERVICE) returns a BluetoothManager. See ag/661924. Change-Id: I589837b9db3b7e0bc0639c85f4acf23a8f9fb7d1 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 97afafa4c8..4316c55ccf 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -64,9 +64,7 @@ import java.util.UUID; *

To get a {@link BluetoothAdapter} representing the local Bluetooth * adapter, when running on JELLY_BEAN_MR1 and below, call the * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and - * higher, retrieve it through - * {@link android.content.Context#getSystemService} with - * {@link android.content.Context#BLUETOOTH_SERVICE}. + * higher, call {@link BluetoothManager#getAdapter}. * Fundamentally, this is your starting point for all * Bluetooth actions. Once you have the local adapter, you can get a set of * {@link BluetoothDevice} objects representing all paired devices with -- cgit v1.2.3 From e1601facd17c1d0b6f74e86fa19187126060fc45 Mon Sep 17 00:00:00 2001 From: Ajay Panicker Date: Tue, 28 Jul 2015 16:52:09 -0700 Subject: Implement Bluetooth settings factory reset (2/5) Implemented the factory reset function to be used to reset all bluetooth settings on device to factory default Bug: 16161518 --- .../java/android/bluetooth/BluetoothAdapter.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 97afafa4c8..1f3ff51487 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1001,6 +1001,25 @@ public final class BluetoothAdapter { return false; } + /** + * Factory reset bluetooth settings. + * + *

Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * permission + * + * @return true to indicate that the config file was successfully cleared + * + * @hide + */ + public boolean factoryReset() { + try { + if (mService != null) { + return mService.factoryReset(); + } + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + /** * Get the UUIDs supported by the local Bluetooth adapter. * -- cgit v1.2.3 From 6c1177ba5808b4bcc0db48c5c4eb658c4eb8a8f1 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Tue, 24 Nov 2015 18:19:06 +0000 Subject: Add thread safety documentation An upcoming change will remove "synchronized" from the API docs. This change documents those cases where the guarantees can be determined from code inspection. Bug: 25767152 Change-Id: I75083ce01513ed315222304fe3f34190d40748cb --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 2d825fa627..3e8a51e47c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -74,6 +74,8 @@ import java.util.UUID; * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}; or start a scan for * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. * + *

This class is thread safe. + * *

Note: * Most methods require the {@link android.Manifest.permission#BLUETOOTH} * permission and some also require the @@ -82,7 +84,7 @@ import java.util.UUID; *

*

Developer Guides

*

For more information about using Bluetooth, read the - * Bluetooth developer guide.

+ * Bluetooth developer guide. *
* * {@see BluetoothDevice} -- cgit v1.2.3 From 7b1e740c286aeea6a38d8f95ccb30d16ff599a19 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Fri, 11 Dec 2015 18:00:38 -0800 Subject: Frameworks/base: Use Arrays.toString Fix a couple of cases where Arrays.toString should be used. Bug: 19797138 Change-Id: I905fc79e63face9b26975320a92086c732bf6316 --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3e8a51e47c..eb4cb919ce 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2165,7 +2165,7 @@ public final class BluetoothAdapter { @Deprecated @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) { - if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids); + if (DBG) Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids)); if (callback == null) { if (DBG) Log.e(TAG, "startLeScan: null callback"); return false; -- cgit v1.2.3 From c94b3a8452558749e8b929c3ea23272bf7d3ee3c Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Tue, 24 Nov 2015 18:19:06 +0000 Subject: Add thread safety documentation An upcoming change will remove "synchronized" from the API docs. This change documents those cases where the guarantees can be determined from code inspection. Bug: 25767152 (cherry-picked from commit bf0dc0fba790cf95f76870c37469703f8f20a57c) Change-Id: I328b96328e89950b90d537bf0a6a704242de4993 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 1f3ff51487..6b3e7ab4ee 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -76,6 +76,8 @@ import java.util.UUID; * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}; or start a scan for * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. * + *

This class is thread safe. + * *

Note: * Most methods require the {@link android.Manifest.permission#BLUETOOTH} * permission and some also require the @@ -84,7 +86,7 @@ import java.util.UUID; *

*

Developer Guides

*

For more information about using Bluetooth, read the - * Bluetooth developer guide.

+ * Bluetooth developer guide. *
* * {@see BluetoothDevice} -- cgit v1.2.3 From 6f56b0f6641d666b98471517e21b3c567a7dfc5a Mon Sep 17 00:00:00 2001 From: Joseph Pirozzo Date: Fri, 4 Mar 2016 13:02:54 -0800 Subject: Add BluetoothProfile for PBAP PCE role. Create a new Bluetooth profile for Pbap Client. Bug: 27490041 Change-Id: I77d2c7eeeb8e955ea61386d784b02b14f415b318 --- framework/java/android/bluetooth/BluetoothAdapter.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index eb4cb919ce..d762a17272 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 The Android Open Source Project + * Copyright (C) 2009-2016 The Android Open Source Project * Copyright (C) 2015 Samsung LSI * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -1837,6 +1837,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.SAP) { BluetoothSap sap = new BluetoothSap(context, listener); return true; + } else if (profile == BluetoothProfile.PBAP_CLIENT) { + BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener); + return true; } else { return false; } @@ -1905,6 +1908,10 @@ public final class BluetoothAdapter { BluetoothSap sap = (BluetoothSap)proxy; sap.close(); break; + case BluetoothProfile.PBAP_CLIENT: + BluetoothPbapClient pbapClient = (BluetoothPbapClient)proxy; + pbapClient.close(); + break; } } -- cgit v1.2.3 From 9a12f3128813b89dd5677e37c709077b7c393f3d Mon Sep 17 00:00:00 2001 From: Ajay Panicker Date: Mon, 29 Feb 2016 16:09:14 -0800 Subject: Allow factory reset when bluetooth is off (1/2) Bug: 27348444 Change-Id: I6c2709371b86581709649d7faf09391230449b9b --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 6b3e7ab4ee..ceb7e91bf7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -36,6 +36,7 @@ import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.util.Log; import android.util.Pair; @@ -1017,6 +1018,8 @@ public final class BluetoothAdapter { try { if (mService != null) { return mService.factoryReset(); + } else { + SystemProperties.set("persist.bluetooth.factoryreset", "true"); } } catch (RemoteException e) {Log.e(TAG, "", e);} return false; -- cgit v1.2.3 From 75f3ec20467e276ce24fb55758ee02e360ddc9cd Mon Sep 17 00:00:00 2001 From: Ajay Panicker Date: Mon, 29 Feb 2016 16:09:14 -0800 Subject: Allow factory reset when bluetooth is off (1/2) Bug: 27348444 Change-Id: I6c2709371b86581709649d7faf09391230449b9b --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index d762a17272..2a7eff8830 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -36,6 +36,7 @@ import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.util.Log; import android.util.Pair; @@ -1015,6 +1016,8 @@ public final class BluetoothAdapter { try { if (mService != null) { return mService.factoryReset(); + } else { + SystemProperties.set("persist.bluetooth.factoryreset", "true"); } } catch (RemoteException e) {Log.e(TAG, "", e);} return false; -- cgit v1.2.3 From 6b31ff83910fe3ceb75f4af508bff62c13d71bc5 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Mon, 11 Apr 2016 12:18:18 -0700 Subject: BatteryStats: Introduce Async external stats requests Instead of calling out to external processes with a blocking IPC, pass along a Binder on which the external process can pass back the response. The calling process can then wait for the reply with a timeout. This eliminates watchdog restarts of the system_server when an external process like telephony or bluetooth hangs. Bug:26842468 Change-Id: I1b242e4ed22a63f1a4a0be8c78de8ac4d7bf56c5 --- .../java/android/bluetooth/BluetoothAdapter.java | 53 ++++++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 2a7eff8830..e74847711b 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -31,11 +31,14 @@ import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.content.Context; +import android.os.BatteryStats; import android.os.Binder; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; +import android.os.ResultReceiver; import android.os.ServiceManager; +import android.os.SynchronousResultReceiver; import android.os.SystemProperties; import android.util.Log; import android.util.Pair; @@ -53,6 +56,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.TimeoutException; /** * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter} @@ -1369,33 +1373,62 @@ public final class BluetoothAdapter { * * @return a record with {@link BluetoothActivityEnergyInfo} or null if * report is unavailable or unsupported + * @deprecated use the asynchronous + * {@link #requestControllerActivityEnergyInfo(int, ResultReceiver)} instead. * @hide */ + @Deprecated public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { - if (getState() != STATE_ON) return null; + SynchronousResultReceiver receiver = new SynchronousResultReceiver(); + requestControllerActivityEnergyInfo(updateType, receiver); + try { + SynchronousResultReceiver.Result result = receiver.awaitResult(1000); + if (result.bundle != null) { + return result.bundle.getParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY); + } + } catch (TimeoutException e) { + Log.e(TAG, "getControllerActivityEnergyInfo timed out"); + } + return null; + } + + /** + * Request the record of {@link BluetoothActivityEnergyInfo} object that + * has the activity and energy info. This can be used to ascertain what + * the controller has been up to, since the last sample. + * + * A null value for the activity info object may be sent if the bluetooth service is + * unreachable or the device does not support reporting such information. + * + * @param updateType Type of info, cached vs refreshed. + * @param result The callback to which to send the activity info. + * @hide + */ + public void requestControllerActivityEnergyInfo(int updateType, ResultReceiver result) { + if (getState() != STATE_ON) { + result.send(0, null); + return; + } + try { - BluetoothActivityEnergyInfo record; if (!mService.isActivityAndEnergyReportingSupported()) { - return null; + result.send(0, null); + return; } synchronized(this) { if (updateType == ACTIVITY_ENERGY_INFO_REFRESHED) { mService.getActivityEnergyInfoFromController(); wait(CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS); } - record = mService.reportActivityInfo(); - if (record.isValid()) { - return record; - } else { - return null; - } + mService.requestActivityInfo(result); } } catch (InterruptedException e) { Log.e(TAG, "getControllerActivityEnergyInfoCallback wait interrupted: " + e); + result.send(0, null); } catch (RemoteException e) { Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e); + result.send(0, null); } - return null; } /** -- cgit v1.2.3 From 39d90151aa8db5f7bde321db5f10af9794d1259e Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Tue, 10 May 2016 14:00:03 -0700 Subject: BluetoothManager: Make requestControllerActivityInfo one call Instead of making multiple calls into the Bluetooth service, make one call that can timeout. This helps prevent cases when the Bluetooth process hangs and the system_server is calling into it and causes a WATCHDOG restart. Bug:28658141 Change-Id: I37778b7b6e508be420a21bdf23593ae89b38f5b8 --- .../java/android/bluetooth/BluetoothAdapter.java | 40 +++++++--------------- 1 file changed, 12 insertions(+), 28 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e74847711b..d036d96257 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -472,12 +472,6 @@ public final class BluetoothAdapter { private static final int ADDRESS_LENGTH = 17; - private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30; - /** @hide */ - public static final int ACTIVITY_ENERGY_INFO_CACHED = 0; - /** @hide */ - public static final int ACTIVITY_ENERGY_INFO_REFRESHED = 1; - /** * Lazily initialized singleton. Guaranteed final after first object * constructed. @@ -1374,13 +1368,13 @@ public final class BluetoothAdapter { * @return a record with {@link BluetoothActivityEnergyInfo} or null if * report is unavailable or unsupported * @deprecated use the asynchronous - * {@link #requestControllerActivityEnergyInfo(int, ResultReceiver)} instead. + * {@link #requestControllerActivityEnergyInfo(ResultReceiver)} instead. * @hide */ @Deprecated public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { SynchronousResultReceiver receiver = new SynchronousResultReceiver(); - requestControllerActivityEnergyInfo(updateType, receiver); + requestControllerActivityEnergyInfo(receiver); try { SynchronousResultReceiver.Result result = receiver.awaitResult(1000); if (result.bundle != null) { @@ -1400,34 +1394,24 @@ public final class BluetoothAdapter { * A null value for the activity info object may be sent if the bluetooth service is * unreachable or the device does not support reporting such information. * - * @param updateType Type of info, cached vs refreshed. * @param result The callback to which to send the activity info. * @hide */ - public void requestControllerActivityEnergyInfo(int updateType, ResultReceiver result) { - if (getState() != STATE_ON) { - result.send(0, null); - return; - } - + public void requestControllerActivityEnergyInfo(ResultReceiver result) { try { - if (!mService.isActivityAndEnergyReportingSupported()) { - result.send(0, null); - return; - } - synchronized(this) { - if (updateType == ACTIVITY_ENERGY_INFO_REFRESHED) { - mService.getActivityEnergyInfoFromController(); - wait(CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS); + synchronized(mManagerCallback) { + if (mService != null) { + mService.requestActivityInfo(result); + result = null; } - mService.requestActivityInfo(result); } - } catch (InterruptedException e) { - Log.e(TAG, "getControllerActivityEnergyInfoCallback wait interrupted: " + e); - result.send(0, null); } catch (RemoteException e) { Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e); - result.send(0, null); + } finally { + if (result != null) { + // Only send an immediate result if we failed. + result.send(0, null); + } } } -- cgit v1.2.3 From 6d126c81896c8956f36a162382815b121f3e2be1 Mon Sep 17 00:00:00 2001 From: Pavlin Radoslavov Date: Sun, 22 May 2016 22:16:41 -0700 Subject: Reduced the impact of "synchronized" statements * Removed "synchronized" statements that are not needed * Replaced "synchronized" statements with Read/Write lock as appropriate. The lock protects the access to and the setting of BluetoothAdapter.mService and BluetoothManagerService.mBluetooth and associated state. Bug: 28734075 Bug: 28799467 Change-Id: I8f8281c505f0a1ae0add1e14a3caba1f5b2a98e4 --- .../java/android/bluetooth/BluetoothAdapter.java | 367 +++++++++++++-------- 1 file changed, 232 insertions(+), 135 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index d036d96257..4c8657810c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -57,6 +57,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter} @@ -483,6 +484,8 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; private IBluetooth mService; + private final ReentrantReadWriteLock mServiceLock = + new ReentrantReadWriteLock(); private final Object mLock = new Object(); private final Map mLeScanClients; @@ -517,8 +520,13 @@ public final class BluetoothAdapter { throw new IllegalArgumentException("bluetooth manager service is null"); } try { + mServiceLock.writeLock().lock(); mService = managerService.registerAdapter(mManagerCallback); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.writeLock().unlock(); + } mManagerService = managerService; mLeScanClients = new HashMap(); mToken = new Binder(); @@ -605,10 +613,14 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isEnabled() { try { - synchronized(mManagerCallback) { - if (mService != null) return mService.isEnabled(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.isEnabled(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; } @@ -639,12 +651,12 @@ public final class BluetoothAdapter { * 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 { + mServiceLock.readLock().lock(); + if (mService == null) { + Log.e(TAG, "mService is null"); + return; + } if (enable) { mService.onLeServiceUp(); //NA:TODO implementation pending } else { @@ -652,6 +664,8 @@ public final class BluetoothAdapter { } } catch (RemoteException e) { Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); } } @@ -783,26 +797,28 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) @AdapterState public int getState() { + int state = BluetoothAdapter.STATE_OFF; + try { - synchronized(mManagerCallback) { - if (mService != null) - { - 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 - // mService is null, handle that case + mServiceLock.readLock().lock(); + if (mService != null) { + state = mService.getState(); } - } catch (RemoteException e) {Log.e(TAG, "", e);} - return STATE_OFF; + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + + // 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; + } + if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state); + return state; } /** @@ -825,19 +841,21 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) @AdapterState public int getLeState() { + int state = BluetoothAdapter.STATE_OFF; + try { - synchronized(mManagerCallback) { - if (mService != null) - { - int state= mService.getState(); - if (VDBG) Log.d(TAG,"getLeState() returning " + state); - return state; - } + mServiceLock.readLock().lock(); + if (mService != null) { + state = mService.getState(); } } catch (RemoteException e) { Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); } - return BluetoothAdapter.STATE_OFF; + + if (VDBG) Log.d(TAG,"getLeState() returning " + state); + return state; } boolean getLeAccess() { @@ -879,16 +897,21 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean enable() { - int state = STATE_OFF; - if (isEnabled() == true){ + int state = BluetoothAdapter.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);} + // Use service interface to get the exact state + try { + mServiceLock.readLock().lock(); + if (mService != null) { + state = mService.getState(); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); } if (state == BluetoothAdapter.STATE_BLE_ON) { @@ -993,10 +1016,13 @@ public final class BluetoothAdapter { */ public boolean configHciSnoopLog(boolean enable) { try { - synchronized(mManagerCallback) { - if (mService != null) return mService.configHciSnoopLog(enable); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.configHciSnoopLog(enable); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1012,12 +1038,16 @@ public final class BluetoothAdapter { */ public boolean factoryReset() { try { + mServiceLock.readLock().lock(); if (mService != null) { return mService.factoryReset(); - } else { - SystemProperties.set("persist.bluetooth.factoryreset", "true"); } - } catch (RemoteException e) {Log.e(TAG, "", e);} + SystemProperties.set("persist.bluetooth.factoryreset", "true"); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1032,10 +1062,13 @@ public final class BluetoothAdapter { public ParcelUuid[] getUuids() { if (getState() != STATE_ON) return null; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.getUuids(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.getUuids(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return null; } @@ -1058,10 +1091,13 @@ public final class BluetoothAdapter { public boolean setName(String name) { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.setName(name); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.setName(name); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1086,10 +1122,13 @@ public final class BluetoothAdapter { public int getScanMode() { if (getState() != STATE_ON) return SCAN_MODE_NONE; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.getScanMode(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.getScanMode(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return SCAN_MODE_NONE; } @@ -1124,10 +1163,13 @@ public final class BluetoothAdapter { public boolean setScanMode(@ScanMode int mode, int duration) { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.setScanMode(mode, duration); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.setScanMode(mode, duration); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1142,10 +1184,13 @@ public final class BluetoothAdapter { public int getDiscoverableTimeout() { if (getState() != STATE_ON) return -1; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.getDiscoverableTimeout(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.getDiscoverableTimeout(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return -1; } @@ -1153,10 +1198,13 @@ public final class BluetoothAdapter { public void setDiscoverableTimeout(int timeout) { if (getState() != STATE_ON) return; try { - synchronized(mManagerCallback) { - if (mService != null) mService.setDiscoverableTimeout(timeout); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) mService.setDiscoverableTimeout(timeout); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } } /** @@ -1193,10 +1241,13 @@ public final class BluetoothAdapter { public boolean startDiscovery() { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.startDiscovery(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.startDiscovery(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1221,10 +1272,13 @@ public final class BluetoothAdapter { public boolean cancelDiscovery() { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.cancelDiscovery(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.cancelDiscovery(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1251,10 +1305,13 @@ public final class BluetoothAdapter { public boolean isDiscovering() { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if (mService != null ) return mService.isDiscovering(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.isDiscovering(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1266,9 +1323,12 @@ public final class BluetoothAdapter { public boolean isMultipleAdvertisementSupported() { if (getState() != STATE_ON) return false; try { - return mService.isMultiAdvertisementSupported(); + mServiceLock.readLock().lock(); + if (mService != null) return mService.isMultiAdvertisementSupported(); } catch (RemoteException e) { Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); } return false; } @@ -1301,9 +1361,12 @@ public final class BluetoothAdapter { public boolean isPeripheralModeSupported() { if (getState() != STATE_ON) return false; try { - return mService.isPeripheralModeSupported(); + mServiceLock.readLock().lock(); + if (mService != null) return mService.isPeripheralModeSupported(); } catch (RemoteException e) { Log.e(TAG, "failed to get peripheral mode capability: ", e); + } finally { + mServiceLock.readLock().unlock(); } return false; } @@ -1316,9 +1379,12 @@ public final class BluetoothAdapter { public boolean isOffloadedFilteringSupported() { if (!getLeAccess()) return false; try { - return mService.isOffloadedFilteringSupported(); + mServiceLock.readLock().lock(); + if (mService != null) return mService.isOffloadedFilteringSupported(); } catch (RemoteException e) { Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); } return false; } @@ -1331,9 +1397,12 @@ public final class BluetoothAdapter { public boolean isOffloadedScanBatchingSupported() { if (!getLeAccess()) return false; try { - return mService.isOffloadedScanBatchingSupported(); + mServiceLock.readLock().lock(); + if (mService != null) return mService.isOffloadedScanBatchingSupported(); } catch (RemoteException e) { Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); } return false; } @@ -1399,15 +1468,15 @@ public final class BluetoothAdapter { */ public void requestControllerActivityEnergyInfo(ResultReceiver result) { try { - synchronized(mManagerCallback) { - if (mService != null) { - mService.requestActivityInfo(result); - result = null; - } + mServiceLock.readLock().lock(); + if (mService != null) { + mService.requestActivityInfo(result); + result = null; } } catch (RemoteException e) { Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e); } finally { + mServiceLock.readLock().unlock(); if (result != null) { // Only send an immediate result if we failed. result.send(0, null); @@ -1432,11 +1501,14 @@ public final class BluetoothAdapter { return toDeviceSet(new BluetoothDevice[0]); } try { - synchronized(mManagerCallback) { - if (mService != null) return toDeviceSet(mService.getBondedDevices()); - } + mServiceLock.readLock().lock(); + if (mService != null) return toDeviceSet(mService.getBondedDevices()); return toDeviceSet(new BluetoothDevice[0]); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return null; } @@ -1456,10 +1528,13 @@ public final class BluetoothAdapter { public int getConnectionState() { if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.getAdapterConnectionState(); - } - } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.getAdapterConnectionState(); + } catch (RemoteException e) { + Log.e(TAG, "getConnectionState:", e); + } finally { + mServiceLock.readLock().unlock(); + } return BluetoothAdapter.STATE_DISCONNECTED; } @@ -1482,11 +1557,12 @@ public final class BluetoothAdapter { public int getProfileConnectionState(int profile) { if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.getProfileConnectionState(profile); - } + mServiceLock.readLock().lock(); + if (mService != null) return mService.getProfileConnectionState(profile); } catch (RemoteException e) { Log.e(TAG, "getProfileConnectionState:", e); + } finally { + mServiceLock.readLock().unlock(); } return BluetoothProfile.STATE_DISCONNECTED; } @@ -1790,7 +1866,9 @@ public final class BluetoothAdapter { byte[] hash; byte[] randomizer; - byte[] ret = mService.readOutOfBandData(); + byte[] ret = null; + mServiceLock.readLock().lock(); + if (mService != null) mService.readOutOfBandData(); if (ret == null || ret.length != 32) return null; @@ -1803,7 +1881,12 @@ public final class BluetoothAdapter { } return new Pair(hash, randomizer); - } catch (RemoteException e) {Log.e(TAG, "", e);}*/ + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + */ return null; } @@ -1939,17 +2022,21 @@ public final class BluetoothAdapter { new IBluetoothManagerCallback.Stub() { public void onBluetoothServiceUp(IBluetooth bluetoothService) { if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); - synchronized (mManagerCallback) { - mService = bluetoothService; - synchronized (mProxyServiceStateCallbacks) { - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ - try { - if (cb != null) { - cb.onBluetoothServiceUp(bluetoothService); - } else { - Log.d(TAG, "onBluetoothServiceUp: cb is null!!!"); - } - } catch (Exception e) { Log.e(TAG,"",e);} + + mServiceLock.writeLock().lock(); + mService = bluetoothService; + mServiceLock.writeLock().unlock(); + + synchronized (mProxyServiceStateCallbacks) { + for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ) { + try { + if (cb != null) { + cb.onBluetoothServiceUp(bluetoothService); + } else { + Log.d(TAG, "onBluetoothServiceUp: cb is null!!!"); + } + } catch (Exception e) { + Log.e(TAG,"",e); } } } @@ -1957,20 +2044,24 @@ public final class BluetoothAdapter { public void onBluetoothServiceDown() { if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); - synchronized (mManagerCallback) { - mService = null; - if (mLeScanClients != null) mLeScanClients.clear(); - if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); - if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); - synchronized (mProxyServiceStateCallbacks) { - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ - try { - if (cb != null) { - cb.onBluetoothServiceDown(); - } else { - Log.d(TAG, "onBluetoothServiceDown: cb is null!!!"); - } - } catch (Exception e) { Log.e(TAG,"",e);} + + mServiceLock.writeLock().lock(); + mService = null; + if (mLeScanClients != null) mLeScanClients.clear(); + if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); + if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); + mServiceLock.writeLock().unlock(); + + synchronized (mProxyServiceStateCallbacks) { + for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ + try { + if (cb != null) { + cb.onBluetoothServiceDown(); + } else { + Log.d(TAG, "onBluetoothServiceDown: cb is null!!!"); + } + } catch (Exception e) { + Log.e(TAG,"",e); } } } @@ -2033,11 +2124,17 @@ public final class BluetoothAdapter { //TODO(BT) /* try { - return mService.changeApplicationBluetoothState(on, new + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.changeApplicationBluetoothState(on, new StateChangeCallbackWrapper(callback), new Binder()); + } } catch (RemoteException e) { Log.e(TAG, "changeBluetoothState", e); - }*/ + } finally { + mServiceLock.readLock().unlock(); + } + */ return false; } -- cgit v1.2.3 From 08eec363400b9c305072d87e8b242397b7eba024 Mon Sep 17 00:00:00 2001 From: Pavlin Radoslavov Date: Sun, 22 May 2016 22:16:41 -0700 Subject: Reduced the impact of "synchronized" statements * Removed "synchronized" statements that are not needed * Replaced "synchronized" statements with Read/Write lock as appropriate. The lock protects the access to and the setting of BluetoothAdapter.mService and BluetoothManagerService.mBluetooth and associated state. Bug: 28734075 Bug: 28799467 Change-Id: I8f8281c505f0a1ae0add1e14a3caba1f5b2a98e4 (cherry picked from commit eb50a39e98acb78d16465041bb5c172aa1637e97) --- .../java/android/bluetooth/BluetoothAdapter.java | 367 +++++++++++++-------- 1 file changed, 235 insertions(+), 132 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ceb7e91bf7..15b16f7314 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -53,6 +53,8 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter} @@ -487,6 +489,8 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; private IBluetooth mService; + private final ReentrantReadWriteLock mServiceLock = + new ReentrantReadWriteLock(); private final Object mLock = new Object(); private final Map mLeScanClients; @@ -521,8 +525,13 @@ public final class BluetoothAdapter { throw new IllegalArgumentException("bluetooth manager service is null"); } try { + mServiceLock.writeLock().lock(); mService = managerService.registerAdapter(mManagerCallback); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.writeLock().unlock(); + } mManagerService = managerService; mLeScanClients = new HashMap(); mToken = new Binder(); @@ -609,10 +618,14 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isEnabled() { try { - synchronized(mManagerCallback) { - if (mService != null) return mService.isEnabled(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.isEnabled(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; } @@ -643,12 +656,12 @@ public final class BluetoothAdapter { * 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 { + mServiceLock.readLock().lock(); + if (mService == null) { + Log.e(TAG, "mService is null"); + return; + } if (enable) { mService.onLeServiceUp(); //NA:TODO implementation pending } else { @@ -656,6 +669,8 @@ public final class BluetoothAdapter { } } catch (RemoteException e) { Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); } } @@ -787,26 +802,28 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) @AdapterState public int getState() { + int state = BluetoothAdapter.STATE_OFF; + try { - synchronized(mManagerCallback) { - if (mService != null) - { - 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 - // mService is null, handle that case + mServiceLock.readLock().lock(); + if (mService != null) { + state = mService.getState(); } - } catch (RemoteException e) {Log.e(TAG, "", e);} - return STATE_OFF; + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + + // 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; + } + if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state); + return state; } /** @@ -829,19 +846,21 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) @AdapterState public int getLeState() { + int state = BluetoothAdapter.STATE_OFF; + try { - synchronized(mManagerCallback) { - if (mService != null) - { - int state= mService.getState(); - if (VDBG) Log.d(TAG,"getLeState() returning " + state); - return state; - } + mServiceLock.readLock().lock(); + if (mService != null) { + state = mService.getState(); } } catch (RemoteException e) { Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); } - return BluetoothAdapter.STATE_OFF; + + if (VDBG) Log.d(TAG,"getLeState() returning " + state); + return state; } boolean getLeAccess() { @@ -883,16 +902,21 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean enable() { - int state = STATE_OFF; - if (isEnabled() == true){ + int state = BluetoothAdapter.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);} + // Use service interface to get the exact state + try { + mServiceLock.readLock().lock(); + if (mService != null) { + state = mService.getState(); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); } if (state == BluetoothAdapter.STATE_BLE_ON) { @@ -997,10 +1021,13 @@ public final class BluetoothAdapter { */ public boolean configHciSnoopLog(boolean enable) { try { - synchronized(mManagerCallback) { - if (mService != null) return mService.configHciSnoopLog(enable); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.configHciSnoopLog(enable); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1016,12 +1043,16 @@ public final class BluetoothAdapter { */ public boolean factoryReset() { try { + mServiceLock.readLock().lock(); if (mService != null) { return mService.factoryReset(); - } else { - SystemProperties.set("persist.bluetooth.factoryreset", "true"); } - } catch (RemoteException e) {Log.e(TAG, "", e);} + SystemProperties.set("persist.bluetooth.factoryreset", "true"); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1036,10 +1067,13 @@ public final class BluetoothAdapter { public ParcelUuid[] getUuids() { if (getState() != STATE_ON) return null; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.getUuids(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.getUuids(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return null; } @@ -1062,10 +1096,13 @@ public final class BluetoothAdapter { public boolean setName(String name) { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.setName(name); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.setName(name); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1090,10 +1127,13 @@ public final class BluetoothAdapter { public int getScanMode() { if (getState() != STATE_ON) return SCAN_MODE_NONE; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.getScanMode(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.getScanMode(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return SCAN_MODE_NONE; } @@ -1128,10 +1168,13 @@ public final class BluetoothAdapter { public boolean setScanMode(@ScanMode int mode, int duration) { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.setScanMode(mode, duration); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.setScanMode(mode, duration); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1146,10 +1189,13 @@ public final class BluetoothAdapter { public int getDiscoverableTimeout() { if (getState() != STATE_ON) return -1; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.getDiscoverableTimeout(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.getDiscoverableTimeout(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return -1; } @@ -1157,10 +1203,13 @@ public final class BluetoothAdapter { public void setDiscoverableTimeout(int timeout) { if (getState() != STATE_ON) return; try { - synchronized(mManagerCallback) { - if (mService != null) mService.setDiscoverableTimeout(timeout); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) mService.setDiscoverableTimeout(timeout); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } } /** @@ -1197,10 +1246,13 @@ public final class BluetoothAdapter { public boolean startDiscovery() { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.startDiscovery(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.startDiscovery(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1225,10 +1277,13 @@ public final class BluetoothAdapter { public boolean cancelDiscovery() { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.cancelDiscovery(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.cancelDiscovery(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1255,10 +1310,13 @@ public final class BluetoothAdapter { public boolean isDiscovering() { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if (mService != null ) return mService.isDiscovering(); - } - } catch (RemoteException e) {Log.e(TAG, "", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.isDiscovering(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return false; } @@ -1270,9 +1328,12 @@ public final class BluetoothAdapter { public boolean isMultipleAdvertisementSupported() { if (getState() != STATE_ON) return false; try { - return mService.isMultiAdvertisementSupported(); + mServiceLock.readLock().lock(); + if (mService != null) return mService.isMultiAdvertisementSupported(); } catch (RemoteException e) { Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); } return false; } @@ -1305,9 +1366,12 @@ public final class BluetoothAdapter { public boolean isPeripheralModeSupported() { if (getState() != STATE_ON) return false; try { - return mService.isPeripheralModeSupported(); + mServiceLock.readLock().lock(); + if (mService != null) return mService.isPeripheralModeSupported(); } catch (RemoteException e) { Log.e(TAG, "failed to get peripheral mode capability: ", e); + } finally { + mServiceLock.readLock().unlock(); } return false; } @@ -1320,9 +1384,12 @@ public final class BluetoothAdapter { public boolean isOffloadedFilteringSupported() { if (!getLeAccess()) return false; try { - return mService.isOffloadedFilteringSupported(); + mServiceLock.readLock().lock(); + if (mService != null) return mService.isOffloadedFilteringSupported(); } catch (RemoteException e) { Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); } return false; } @@ -1335,9 +1402,12 @@ public final class BluetoothAdapter { public boolean isOffloadedScanBatchingSupported() { if (!getLeAccess()) return false; try { - return mService.isOffloadedScanBatchingSupported(); + mServiceLock.readLock().lock(); + if (mService != null) return mService.isOffloadedScanBatchingSupported(); } catch (RemoteException e) { Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); } return false; } @@ -1376,9 +1446,12 @@ public final class BluetoothAdapter { public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { if (getState() != STATE_ON) return null; try { + mServiceLock.readLock().lock(); BluetoothActivityEnergyInfo record; - if (!mService.isActivityAndEnergyReportingSupported()) { - return null; + if (mService != null) { + if (!mService.isActivityAndEnergyReportingSupported()) { + return null; + } } synchronized(this) { if (updateType == ACTIVITY_ENERGY_INFO_REFRESHED) { @@ -1396,6 +1469,8 @@ public final class BluetoothAdapter { Log.e(TAG, "getControllerActivityEnergyInfoCallback wait interrupted: " + e); } catch (RemoteException e) { Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e); + } finally { + mServiceLock.readLock().unlock(); } return null; } @@ -1417,11 +1492,14 @@ public final class BluetoothAdapter { return toDeviceSet(new BluetoothDevice[0]); } try { - synchronized(mManagerCallback) { - if (mService != null) return toDeviceSet(mService.getBondedDevices()); - } + mServiceLock.readLock().lock(); + if (mService != null) return toDeviceSet(mService.getBondedDevices()); return toDeviceSet(new BluetoothDevice[0]); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } return null; } @@ -1441,10 +1519,13 @@ public final class BluetoothAdapter { public int getConnectionState() { if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.getAdapterConnectionState(); - } - } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);} + mServiceLock.readLock().lock(); + if (mService != null) return mService.getAdapterConnectionState(); + } catch (RemoteException e) { + Log.e(TAG, "getConnectionState:", e); + } finally { + mServiceLock.readLock().unlock(); + } return BluetoothAdapter.STATE_DISCONNECTED; } @@ -1467,11 +1548,12 @@ public final class BluetoothAdapter { public int getProfileConnectionState(int profile) { if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED; try { - synchronized(mManagerCallback) { - if (mService != null) return mService.getProfileConnectionState(profile); - } + mServiceLock.readLock().lock(); + if (mService != null) return mService.getProfileConnectionState(profile); } catch (RemoteException e) { Log.e(TAG, "getProfileConnectionState:", e); + } finally { + mServiceLock.readLock().unlock(); } return BluetoothProfile.STATE_DISCONNECTED; } @@ -1775,7 +1857,9 @@ public final class BluetoothAdapter { byte[] hash; byte[] randomizer; - byte[] ret = mService.readOutOfBandData(); + byte[] ret = null; + mServiceLock.readLock().lock(); + if (mService != null) mService.readOutOfBandData(); if (ret == null || ret.length != 32) return null; @@ -1788,7 +1872,12 @@ public final class BluetoothAdapter { } return new Pair(hash, randomizer); - } catch (RemoteException e) {Log.e(TAG, "", e);}*/ + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + */ return null; } @@ -1917,17 +2006,21 @@ public final class BluetoothAdapter { new IBluetoothManagerCallback.Stub() { public void onBluetoothServiceUp(IBluetooth bluetoothService) { if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); - synchronized (mManagerCallback) { - mService = bluetoothService; - synchronized (mProxyServiceStateCallbacks) { - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ - try { - if (cb != null) { - cb.onBluetoothServiceUp(bluetoothService); - } else { - Log.d(TAG, "onBluetoothServiceUp: cb is null!!!"); - } - } catch (Exception e) { Log.e(TAG,"",e);} + + mServiceLock.writeLock().lock(); + mService = bluetoothService; + mServiceLock.writeLock().unlock(); + + synchronized (mProxyServiceStateCallbacks) { + for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ) { + try { + if (cb != null) { + cb.onBluetoothServiceUp(bluetoothService); + } else { + Log.d(TAG, "onBluetoothServiceUp: cb is null!!!"); + } + } catch (Exception e) { + Log.e(TAG,"",e); } } } @@ -1935,20 +2028,24 @@ public final class BluetoothAdapter { public void onBluetoothServiceDown() { if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); - synchronized (mManagerCallback) { - mService = null; - if (mLeScanClients != null) mLeScanClients.clear(); - if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); - if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); - synchronized (mProxyServiceStateCallbacks) { - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ - try { - if (cb != null) { - cb.onBluetoothServiceDown(); - } else { - Log.d(TAG, "onBluetoothServiceDown: cb is null!!!"); - } - } catch (Exception e) { Log.e(TAG,"",e);} + + mServiceLock.writeLock().lock(); + mService = null; + if (mLeScanClients != null) mLeScanClients.clear(); + if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); + if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); + mServiceLock.writeLock().unlock(); + + synchronized (mProxyServiceStateCallbacks) { + for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ + try { + if (cb != null) { + cb.onBluetoothServiceDown(); + } else { + Log.d(TAG, "onBluetoothServiceDown: cb is null!!!"); + } + } catch (Exception e) { + Log.e(TAG,"",e); } } } @@ -2011,11 +2108,17 @@ public final class BluetoothAdapter { //TODO(BT) /* try { - return mService.changeApplicationBluetoothState(on, new + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.changeApplicationBluetoothState(on, new StateChangeCallbackWrapper(callback), new Binder()); + } } catch (RemoteException e) { Log.e(TAG, "changeBluetoothState", e); - }*/ + } finally { + mServiceLock.readLock().unlock(); + } + */ return false; } -- cgit v1.2.3 From 630c0a3a0748855515a6544da3380c12f83a619e Mon Sep 17 00:00:00 2001 From: Pavlin Radoslavov Date: Tue, 24 May 2016 15:28:41 -0700 Subject: Add missing "try ... finally" safeguards Safeguards for code protected by ReentrantReadWriteLock. Bug: 28734075 Bug: 28799467 Change-Id: Ib7f598a92e8df6bd855ca48cdd094c1c73a935f2 --- framework/java/android/bluetooth/BluetoothAdapter.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 4c8657810c..9390bcd13d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2045,12 +2045,15 @@ public final class BluetoothAdapter { public void onBluetoothServiceDown() { if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); - mServiceLock.writeLock().lock(); - mService = null; - if (mLeScanClients != null) mLeScanClients.clear(); - if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); - if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); - mServiceLock.writeLock().unlock(); + try { + mServiceLock.writeLock().lock(); + mService = null; + if (mLeScanClients != null) mLeScanClients.clear(); + if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); + if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); + } finally { + mServiceLock.writeLock().unlock(); + } synchronized (mProxyServiceStateCallbacks) { for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ -- cgit v1.2.3 From f453e34eac30e6587d0764a57ddf98f9ced69c25 Mon Sep 17 00:00:00 2001 From: Pavlin Radoslavov Date: Tue, 24 May 2016 15:28:41 -0700 Subject: Add missing "try ... finally" safeguards Safeguards for code protected by ReentrantReadWriteLock. Bug: 28734075 Bug: 28799467 Change-Id: Ib7f598a92e8df6bd855ca48cdd094c1c73a935f2 (cherry picked from commit e957a8a0b4100d001f79c866e7904d2426ac8da0) --- framework/java/android/bluetooth/BluetoothAdapter.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 15b16f7314..36e041ae0c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2029,12 +2029,15 @@ public final class BluetoothAdapter { public void onBluetoothServiceDown() { if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); - mServiceLock.writeLock().lock(); - mService = null; - if (mLeScanClients != null) mLeScanClients.clear(); - if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); - if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); - mServiceLock.writeLock().unlock(); + try { + mServiceLock.writeLock().lock(); + mService = null; + if (mLeScanClients != null) mLeScanClients.clear(); + if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); + if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); + } finally { + mServiceLock.writeLock().unlock(); + } synchronized (mProxyServiceStateCallbacks) { for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ -- cgit v1.2.3 From 20f11b34f738d5586e0ad6b1cd50bbe4239de58d Mon Sep 17 00:00:00 2001 From: Calvin On Date: Wed, 15 Jun 2016 17:58:23 -0700 Subject: Fix race with BT disable in BLE_ON_STATE This will restart the BT stack when it detects a transition into OFF state while the user enable flag (mEnable) is set. Bug: 29363429 Change-Id: I9839119b34c4694ad92e96240c6989008b2f8d52 --- framework/java/android/bluetooth/BluetoothAdapter.java | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 9390bcd13d..47ae68796f 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -897,28 +897,10 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean enable() { - int state = BluetoothAdapter.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 - try { - mServiceLock.readLock().lock(); - if (mService != null) { - state = mService.getState(); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - - 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);} -- cgit v1.2.3 From f242df2f7ac42405d7d4d83bb745c2bc40088c13 Mon Sep 17 00:00:00 2001 From: Marie Janssen Date: Mon, 20 Jun 2016 10:26:31 -0700 Subject: Fix links to Bluetooth Guide Change-Id: I5798c3d71c7cc9c509e0f7b04fa140168b0fdc11 --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 36e041ae0c..3479e8066a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -89,7 +89,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; *
*

Developer Guides

*

For more information about using Bluetooth, read the - * Bluetooth developer guide. + * Bluetooth developer guide. *

* * {@see BluetoothDevice} -- cgit v1.2.3 From e2cf867851868c34fac467aa356ae59c6649c85e Mon Sep 17 00:00:00 2001 From: Hemal Patel Date: Wed, 17 Aug 2016 13:18:14 -0700 Subject: Docs: Fixed the Bluetooth guide link Fixed the link that points to the Bluetooth guide. Bug: 29268546 Change-Id: I51c48cebf45c78481f8853a93ff7bcd8483d69ba --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 47ae68796f..246a752b3a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -89,8 +89,11 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * *
*

Developer Guides

- *

For more information about using Bluetooth, read the - * Bluetooth developer guide. + *

+ * For more information about using Bluetooth, read the Bluetooth developer + * guide. + *

*
* * {@see BluetoothDevice} -- cgit v1.2.3 From 9bb3a68712a411104a6484b58a21521166f5f761 Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Sun, 9 Oct 2016 12:54:42 -0700 Subject: Add a way to query for supported Bluetooth profiles. Currently there is no way to get the profiles supported by the Bluetooth adapter. Asking for a profile proxy of an unsupported profile does not fail and can lead to code indefinitely waiting for the proxy response. This new code will allow for checking the supported profiles before asking for the proxies. Bug: 26451648 Change-Id: I4b48e7151f5ca53851aa3b967c143fae140ecd34 --- .../java/android/bluetooth/BluetoothAdapter.java | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 246a752b3a..b93a5578f2 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1497,6 +1497,36 @@ public final class BluetoothAdapter { return null; } + /** + * Gets the currently supported profiles by the adapter. + * + *

This can be used to check whether a profile is supported before attempting + * to connect to its respective proxy. + * + * @return a list of integers indicating the ids of supported profiles as defined in + * {@link BluetoothProfile}. + * @hide + */ + public List getSupportedProfiles() { + final ArrayList supportedProfiles = new ArrayList(); + + try { + synchronized (mManagerCallback) { + if (mService != null) { + final long supportedProfilesBitMask = mService.getSupportedProfiles(); + + for (int i = 0; i <= BluetoothProfile.MAX_PROFILE_ID; i++) { + if ((supportedProfilesBitMask & (1 << i)) != 0) { + supportedProfiles.add(i); + } + } + } + } + } catch (RemoteException e) {Log.e(TAG, "getSupportedProfiles:", e);} + + return supportedProfiles; + } + /** * Get the current connection state of the local Bluetooth adapter. * This can be used to check whether the local Bluetooth adapter is connected -- cgit v1.2.3 From c816f2eeba24e185baf977bb5b82227d23257aca Mon Sep 17 00:00:00 2001 From: Marie Janssen Date: Tue, 18 Oct 2016 10:04:24 -0700 Subject: Bluetooth: More logging of bluetooth service state Bug: 32140251 Bug: 32140271 Bug: 32060415 Change-Id: I50faa184551748023ea5a573646a75293f553d16 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 246a752b3a..6be5a9725d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2006,7 +2006,7 @@ public final class BluetoothAdapter { final private IBluetoothManagerCallback mManagerCallback = new IBluetoothManagerCallback.Stub() { public void onBluetoothServiceUp(IBluetooth bluetoothService) { - if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); + if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); mServiceLock.writeLock().lock(); mService = bluetoothService; @@ -2028,7 +2028,7 @@ public final class BluetoothAdapter { } public void onBluetoothServiceDown() { - if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); + if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); try { mServiceLock.writeLock().lock(); @@ -2056,7 +2056,7 @@ public final class BluetoothAdapter { } public void onBrEdrDown() { - if (VDBG) Log.i(TAG, "on QBrEdrDown: "); + if (DBG) Log.i(TAG, "onBrEdrDown:"); } }; -- cgit v1.2.3 From 167b3c5e922186f5d4a6a63c737401c5f2051193 Mon Sep 17 00:00:00 2001 From: Marie Janssen Date: Tue, 25 Oct 2016 10:47:51 -0700 Subject: Bluetooth: prevent enabling BLE in airplane mode Enabling BLE in airplane mode puts BluetoothManagerService in an unexpected state which causes Bluetooth to be on when airplane mode is disabled. Also fixes a bug where a crash of a BLE client would trigger a restart into ON mode. Test: SL4A BleBackgroundScanTest:test_airplane_mode_disables_ble Bug: 32140251 Bug: 32140271 Bug: 32369494 Change-Id: Ie65157e65c3a1ca914f567a7a0c631175d1e5835 (cherry picked from commit bd93b7b3dc6141cef6236cf0ca7dcc5acf5bfeed) --- framework/java/android/bluetooth/BluetoothAdapter.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 6be5a9725d..50c8e275ff 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -765,19 +765,13 @@ public final class BluetoothAdapter { public boolean enableBLE() { if (!isBleScanAlwaysAvailable()) 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); + if (isLeEnabled()) { + if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled"); + return true; + } + if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); return mManagerService.enable(); } catch (RemoteException e) { Log.e(TAG, "", e); -- cgit v1.2.3 From acb832d29d97138cfb925f00a2efd527ff912cac Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Wed, 29 Jun 2016 17:31:44 -0700 Subject: Add Bluetooth toggle prompts - framework If permission review is enabled toggling bluetoth on or off results in a user prompt to collect consent. This applies only to legacy apps, i.e. ones that don't support runtime permissions as they target SDK 22. Also added a configuration resource which controls whether permission review mode is enabled. By default it is not and an OEM can change this via an overlay. For now we also keep the old mechanism to toggle review mode via a build property which is still used and will be removed when clients have transitioned. bug:28715749 Change-Id: I94c5828ad6c8aa6b363622a26ff9da4fc2e2fac7 (cherry picked from commit 1fff3cdf4b1e4fc7920a5b76d4ae92eb6824325d) --- .../java/android/bluetooth/BluetoothAdapter.java | 32 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index cd1a3dd02b..073196cf7c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -23,6 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; +import android.app.ActivityThread; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; @@ -251,6 +252,29 @@ public final class BluetoothAdapter { public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"; + /** + * Activity Action: Show a system activity that allows the user to turn off + * Bluetooth. This is used only if permission review is enabled which is for + * apps targeting API less than 23 require a permission review before any of + * the app's components can run. + *

This system activity will return once Bluetooth has completed turning + * off, or the user has decided not to turn Bluetooth off. + *

Notification of the result of this activity is posted using the + * {@link android.app.Activity#onActivityResult} callback. The + * resultCode + * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been + * turned off or {@link android.app.Activity#RESULT_CANCELED} if the user + * has rejected the request or an error has occurred. + *

Applications can also listen for {@link #ACTION_STATE_CHANGED} + * for global notification whenever Bluetooth is turned on or off. + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_REQUEST_DISABLE = + "android.bluetooth.adapter.action.REQUEST_DISABLE"; + /** * Activity Action: Show a system activity that allows user to enable BLE scans even when * Bluetooth is turned off.

@@ -775,7 +799,7 @@ public final class BluetoothAdapter { try { if (DBG) Log.d(TAG, "Calling enableBLE"); mManagerService.updateBleAppCount(mToken, true); - return mManagerService.enable(); + return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -902,7 +926,7 @@ public final class BluetoothAdapter { return true; } try { - return mManagerService.enable(); + return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -934,7 +958,7 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean disable() { try { - return mManagerService.disable(true); + return mManagerService.disable(ActivityThread.currentPackageName(), true); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -952,7 +976,7 @@ public final class BluetoothAdapter { public boolean disable(boolean persist) { try { - return mManagerService.disable(persist); + return mManagerService.disable(ActivityThread.currentPackageName(), persist); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } -- cgit v1.2.3 From 257f8fe85e626e8741ae626228214c2c34390aea Mon Sep 17 00:00:00 2001 From: Marie Janssen Date: Tue, 25 Oct 2016 10:47:51 -0700 Subject: Bluetooth: prevent enabling BLE in airplane mode Enabling BLE in airplane mode puts BluetoothManagerService in an unexpected state which causes Bluetooth to be on when airplane mode is disabled. Also fixes a bug where a crash of a BLE client would trigger a restart into ON mode. Test: SL4A BleBackgroundScanTest:test_airplane_mode_disables_ble Bug: 32140251 Bug: 32140271 Bug: 32369494 Change-Id: Ie65157e65c3a1ca914f567a7a0c631175d1e5835 --- framework/java/android/bluetooth/BluetoothAdapter.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 073196cf7c..b57a4e07bf 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -786,19 +786,13 @@ public final class BluetoothAdapter { public boolean enableBLE() { if (!isBleScanAlwaysAvailable()) 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); + if (isLeEnabled()) { + if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled"); + return true; + } + if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) { Log.e(TAG, "", e); -- cgit v1.2.3 From ff5093b73ec3daf31209d1d031e0e160e012274d Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Sun, 9 Oct 2016 12:54:42 -0700 Subject: Add a way to query for supported Bluetooth profiles. Currently there is no way to get the profiles supported by the Bluetooth adapter. Asking for a profile proxy of an unsupported profile does not fail and can lead to code indefinitely waiting for the proxy response. This new code will allow for checking the supported profiles before asking for the proxies. Bug: 26451648 Change-Id: I4b48e7151f5ca53851aa3b967c143fae140ecd34 (cherry picked from commit b1301fa2849bafd6daa422281dc5200863bc761e) --- .../java/android/bluetooth/BluetoothAdapter.java | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b57a4e07bf..59edadce96 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1512,6 +1512,36 @@ public final class BluetoothAdapter { return null; } + /** + * Gets the currently supported profiles by the adapter. + * + *

This can be used to check whether a profile is supported before attempting + * to connect to its respective proxy. + * + * @return a list of integers indicating the ids of supported profiles as defined in + * {@link BluetoothProfile}. + * @hide + */ + public List getSupportedProfiles() { + final ArrayList supportedProfiles = new ArrayList(); + + try { + synchronized (mManagerCallback) { + if (mService != null) { + final long supportedProfilesBitMask = mService.getSupportedProfiles(); + + for (int i = 0; i <= BluetoothProfile.MAX_PROFILE_ID; i++) { + if ((supportedProfilesBitMask & (1 << i)) != 0) { + supportedProfiles.add(i); + } + } + } + } + } catch (RemoteException e) {Log.e(TAG, "getSupportedProfiles:", e);} + + return supportedProfiles; + } + /** * Get the current connection state of the local Bluetooth adapter. * This can be used to check whether the local Bluetooth adapter is connected -- cgit v1.2.3 From 54d4b66174dd0ce4d5c7e8d3898a2b4d3893dc71 Mon Sep 17 00:00:00 2001 From: Joseph Pirozzo Date: Thu, 1 Sep 2016 14:19:28 -0700 Subject: MAP MCE Add MAP client code into packages/apps/Bluetooth. Changes here are to define the MAP MCE interface and enable its selection when running on a device that is also running a PBAP client (Car Kitt). Bug: 30467210 Change-Id: Ifa2cdea7d67f63a2b5f3d971df8ec6d321dc5fee (cherry picked from commit fae5ff2578fe1e51a4677e6d344d4f5ff4618ed1) --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 59edadce96..11c27355c7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1973,6 +1973,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.PBAP_CLIENT) { BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener); return true; + } else if (profile == BluetoothProfile.MAP_CLIENT) { + BluetoothMapClient mapClient = new BluetoothMapClient(context, listener); + return true; } else { return false; } @@ -2045,6 +2048,10 @@ public final class BluetoothAdapter { BluetoothPbapClient pbapClient = (BluetoothPbapClient)proxy; pbapClient.close(); break; + case BluetoothProfile.MAP_CLIENT: + BluetoothMapClient mapClient = (BluetoothMapClient)proxy; + mapClient.close(); + break; } } -- cgit v1.2.3 From 976e264b589c692ec33ddd82c7b585b2d830bf69 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Fri, 4 Nov 2016 15:25:57 -0700 Subject: Bluetooth: advertising improvements This patch removes isPeripheralModeSupported(), hidden public method which is always returning true. It also modify the BluetoothLeAdvertiser to be able to use advertising instance with instance id equal 0. Bug: 30622771 Bug: 24099160 Change-Id: Id31582621dbe56d5c3a8d4ee5cd296af66a5f026 --- .../java/android/bluetooth/BluetoothAdapter.java | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 11c27355c7..4271e3f99d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -601,10 +601,6 @@ public final class BluetoothAdapter { */ public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { if (!getLeAccess()) return null; - if (!isMultipleAdvertisementSupported() && !isPeripheralModeSupported()) { - Log.e(TAG, "Bluetooth LE advertising not supported"); - return null; - } synchronized(mLock) { if (sBluetoothLeAdvertiser == null) { sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); @@ -1353,24 +1349,6 @@ public final class BluetoothAdapter { } } - /** - * Returns whether peripheral mode is supported. - * - * @hide - */ - public boolean isPeripheralModeSupported() { - if (getState() != STATE_ON) return false; - try { - mServiceLock.readLock().lock(); - if (mService != null) return mService.isPeripheralModeSupported(); - } catch (RemoteException e) { - Log.e(TAG, "failed to get peripheral mode capability: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - /** * Return true if offloaded filters are supported * -- cgit v1.2.3 From 5682fb80c9c84e215def90b2204ff25d2a6ba87b Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Wed, 29 Jun 2016 17:31:44 -0700 Subject: Add Bluetooth toggle prompts - framework If permission review is enabled toggling bluetoth on or off results in a user prompt to collect consent. This applies only to legacy apps, i.e. ones that don't support runtime permissions as they target SDK 22. Also added a configuration resource which controls whether permission review mode is enabled. By default it is not and an OEM can change this via an overlay. For now we also keep the old mechanism to toggle review mode via a build property which is still used and will be removed when clients have transitioned. bug:28715749 Change-Id: I94c5828ad6c8aa6b363622a26ff9da4fc2e2fac7 --- .../java/android/bluetooth/BluetoothAdapter.java | 32 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 4f19dcac16..542b06b136 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -23,6 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; +import android.app.ActivityThread; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; @@ -254,6 +255,29 @@ public final class BluetoothAdapter { public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"; + /** + * Activity Action: Show a system activity that allows the user to turn off + * Bluetooth. This is used only if permission review is enabled which is for + * apps targeting API less than 23 require a permission review before any of + * the app's components can run. + *

This system activity will return once Bluetooth has completed turning + * off, or the user has decided not to turn Bluetooth off. + *

Notification of the result of this activity is posted using the + * {@link android.app.Activity#onActivityResult} callback. The + * resultCode + * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been + * turned off or {@link android.app.Activity#RESULT_CANCELED} if the user + * has rejected the request or an error has occurred. + *

Applications can also listen for {@link #ACTION_STATE_CHANGED} + * for global notification whenever Bluetooth is turned on or off. + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_REQUEST_DISABLE = + "android.bluetooth.adapter.action.REQUEST_DISABLE"; + /** * Activity Action: Show a system activity that allows user to enable BLE scans even when * Bluetooth is turned off.

@@ -772,7 +796,7 @@ public final class BluetoothAdapter { return true; } if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); - return mManagerService.enable(); + return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -899,7 +923,7 @@ public final class BluetoothAdapter { return true; } try { - return mManagerService.enable(); + return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -931,7 +955,7 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean disable() { try { - return mManagerService.disable(true); + return mManagerService.disable(ActivityThread.currentPackageName(), true); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -949,7 +973,7 @@ public final class BluetoothAdapter { public boolean disable(boolean persist) { try { - return mManagerService.disable(persist); + return mManagerService.disable(ActivityThread.currentPackageName(), persist); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } -- cgit v1.2.3 From 45b8ffba5f29180a91f0d13429135d8a608419e6 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Wed, 29 Jun 2016 17:31:44 -0700 Subject: DO NOT MERGE Add Bluetooth toggle prompts - framework If permission review is enabled toggling bluetoth on or off results in a user prompt to collect consent. This applies only to legacy apps, i.e. ones that don't support runtime permissions as they target SDK 22. Also added a configuration resource which controls whether permission review mode is enabled. By default it is not and an OEM can change this via an overlay. For now we also keep the old mechanism to toggle review mode via a build property which is still used and will be removed when clients have transitioned. bug:28715749 Change-Id: I77bca2305f9d0f20034b2c8fc5b58e0565d5e617 --- .../java/android/bluetooth/BluetoothAdapter.java | 32 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index d419d0384f..61544e4f92 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -23,6 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; +import android.app.ActivityThread; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; @@ -254,6 +255,29 @@ public final class BluetoothAdapter { public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"; + /** + * Activity Action: Show a system activity that allows the user to turn off + * Bluetooth. This is used only if permission review is enabled which is for + * apps targeting API less than 23 require a permission review before any of + * the app's components can run. + *

This system activity will return once Bluetooth has completed turning + * off, or the user has decided not to turn Bluetooth off. + *

Notification of the result of this activity is posted using the + * {@link android.app.Activity#onActivityResult} callback. The + * resultCode + * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been + * turned off or {@link android.app.Activity#RESULT_CANCELED} if the user + * has rejected the request or an error has occurred. + *

Applications can also listen for {@link #ACTION_STATE_CHANGED} + * for global notification whenever Bluetooth is turned on or off. + *

Requires {@link android.Manifest.permission#BLUETOOTH} + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_REQUEST_DISABLE = + "android.bluetooth.adapter.action.REQUEST_DISABLE"; + /** * Activity Action: Show a system activity that allows user to enable BLE scans even when * Bluetooth is turned off.

@@ -768,7 +792,7 @@ public final class BluetoothAdapter { return true; } if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); - return mManagerService.enable(); + return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -895,7 +919,7 @@ public final class BluetoothAdapter { return true; } try { - return mManagerService.enable(); + return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -927,7 +951,7 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean disable() { try { - return mManagerService.disable(true); + return mManagerService.disable(ActivityThread.currentPackageName(), true); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } @@ -945,7 +969,7 @@ public final class BluetoothAdapter { public boolean disable(boolean persist) { try { - return mManagerService.disable(persist); + return mManagerService.disable(ActivityThread.currentPackageName(), persist); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } -- cgit v1.2.3 From f46373a3b2c3218fa95b0cb4cb8fd9c2c605df16 Mon Sep 17 00:00:00 2001 From: Marie Janssen Date: Tue, 13 Dec 2016 10:51:02 -0800 Subject: Bluetooth: log message improvements Some log improvements: - Reduce logspam - Use names for states in logs instead of numbers - Be more consistent with messages Also remove some commented out dead code. Test: run on phone, observe more useful logs Change-Id: I32163278e148be144c03d4e8aaf0eb761226c94c --- .../java/android/bluetooth/BluetoothAdapter.java | 97 +++++++--------------- 1 file changed, 32 insertions(+), 65 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 61544e4f92..4a97b078f7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -200,6 +200,23 @@ public final class BluetoothAdapter { */ public static final int STATE_BLE_TURNING_OFF = 16; + /** + * Human-readable string helper for AdapterState + * @hide + */ + public static String nameForState(@AdapterState int state) { + switch(state) { + case STATE_OFF: return "OFF"; + case STATE_TURNING_ON: return "TURNING_ON"; + case STATE_ON: return "ON"; + case STATE_TURNING_OFF: return "TURNING_OFF"; + case STATE_BLE_TURNING_ON: return "BLE_TURNING_ON"; + case STATE_BLE_ON: return "BLE_ON"; + case STATE_BLE_TURNING_OFF: return "BLE_TURNING_OFF"; + default: return "?!?!? (" + state + ")"; + } + } + /** * Activity Action: Show a system activity that requests discoverable mode. * This activity will also request the user to turn on Bluetooth if it @@ -658,15 +675,8 @@ public final class BluetoothAdapter { @SystemApi 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; + if (DBG) Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state)); + return (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON); } /** @@ -831,10 +841,10 @@ public final class BluetoothAdapter { 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"); + if (VDBG) Log.d(TAG, "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF"); state = BluetoothAdapter.STATE_OFF; } - if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state); + if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState(state)); return state; } @@ -871,12 +881,12 @@ public final class BluetoothAdapter { mServiceLock.readLock().unlock(); } - if (VDBG) Log.d(TAG,"getLeState() returning " + state); + if (VDBG) Log.d(TAG,"getLeState() returning " + BluetoothAdapter.nameForState(state)); return state; } boolean getLeAccess() { - if(getLeState() == STATE_ON) + if (getLeState() == STATE_ON) return true; else if (getLeState() == STATE_BLE_ON) @@ -914,8 +924,8 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean enable() { - if (isEnabled() == true) { - if (DBG) Log.d(TAG, "enable(): BT is already enabled..!"); + if (isEnabled()) { + if (DBG) Log.d(TAG, "enable(): BT already enabled!"); return true; } try { @@ -1518,8 +1528,9 @@ public final class BluetoothAdapter { } } } - } catch (RemoteException e) {Log.e(TAG, "getSupportedProfiles:", e);} - + } catch (RemoteException e) { + Log.e(TAG, "getSupportedProfiles:", e); + } return supportedProfiles; } @@ -1870,34 +1881,6 @@ public final class BluetoothAdapter { * @hide */ public Pair readOutOfBandData() { - if (getState() != STATE_ON) return null; - //TODO(BT - /* - try { - byte[] hash; - byte[] randomizer; - - byte[] ret = null; - mServiceLock.readLock().lock(); - if (mService != null) mService.readOutOfBandData(); - - if (ret == null || ret.length != 32) return null; - - hash = Arrays.copyOfRange(ret, 0, 16); - randomizer = Arrays.copyOfRange(ret, 16, 32); - - if (DBG) { - Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) + - ":" + Arrays.toString(randomizer)); - } - return new Pair(hash, randomizer); - - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - */ return null; } @@ -2051,7 +2034,7 @@ public final class BluetoothAdapter { if (cb != null) { cb.onBluetoothServiceUp(bluetoothService); } else { - Log.d(TAG, "onBluetoothServiceUp: cb is null!!!"); + Log.d(TAG, "onBluetoothServiceUp: cb is null!"); } } catch (Exception e) { Log.e(TAG,"",e); @@ -2079,7 +2062,7 @@ public final class BluetoothAdapter { if (cb != null) { cb.onBluetoothServiceDown(); } else { - Log.d(TAG, "onBluetoothServiceDown: cb is null!!!"); + Log.d(TAG, "onBluetoothServiceDown: cb is null!"); } } catch (Exception e) { Log.e(TAG,"",e); @@ -2089,7 +2072,7 @@ public final class BluetoothAdapter { } public void onBrEdrDown() { - if (VDBG) Log.i(TAG, "on QBrEdrDown: "); + if (VDBG) Log.i(TAG, "onBrEdrDown: " + mService); } }; @@ -2100,7 +2083,7 @@ public final class BluetoothAdapter { */ public boolean enableNoAutoConnect() { if (isEnabled() == true){ - if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT is already enabled..!"); + if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT already enabled!"); return true; } try { @@ -2140,22 +2123,6 @@ public final class BluetoothAdapter { */ public boolean changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback) { - if (callback == null) return false; - - //TODO(BT) - /* - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.changeApplicationBluetoothState(on, new - StateChangeCallbackWrapper(callback), new Binder()); - } - } catch (RemoteException e) { - Log.e(TAG, "changeBluetoothState", e); - } finally { - mServiceLock.readLock().unlock(); - } - */ return false; } -- cgit v1.2.3 From 7d82a61d972018cfa94f983a97283718c34ce4e0 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Fri, 18 Apr 2014 11:22:45 +0530 Subject: Bluetooth: Add support for HID Device Role This patch adds the HID Device Role support in Bluetooth framework. Also AIDL and callback related files for HID Device role are added to provide interface for third party applications to communicate with HID Device Service. Change-Id: Id03a362b7bcfa2e76056fa0197eaac12ce49b5a2 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 4a97b078f7..2b35e2bec4 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1940,6 +1940,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.MAP_CLIENT) { BluetoothMapClient mapClient = new BluetoothMapClient(context, listener); return true; + } else if (profile == BluetoothProfile.HID_DEVICE) { + BluetoothHidDevice hidd = new BluetoothHidDevice(context, listener); + return true; } else { return false; } @@ -2016,6 +2019,10 @@ public final class BluetoothAdapter { BluetoothMapClient mapClient = (BluetoothMapClient)proxy; mapClient.close(); break; + case BluetoothProfile.HID_DEVICE: + BluetoothHidDevice hidd = (BluetoothHidDevice) proxy; + hidd.close(); + break; } } -- cgit v1.2.3 From 5fabc4426e870bc119027d773efafdf524e5f988 Mon Sep 17 00:00:00 2001 From: Ivan Podogov Date: Fri, 23 Dec 2016 11:52:21 +0000 Subject: Rename the Bluetooth profile classes for HID Device role. We already have BluetoothInputDevice class, so adding something called BluetoothHidDevice seems confusing. On the other hand, the new class is designed to connect to HID Host devices, so naming it BluetoothInputHost makes sense and goes in line with the existing BluetoothInputDevice. The same goes for the new constant HID_DEVICE that is just as confusing to have together with the INPUT_DEVICE one. This CL also renames the "connection state changed" broadcast (for the same reasons), declares it as an SDK constant, and also adds some javadoc to it. Note that BluetoothHidDeviceApp* classes remained unchanged, as those correspond to the app that implements the Device (and connects to the Host). Test: make Change-Id: I5075ca5b97db3c1dd403c2e9660eecc7380cffe2 --- framework/java/android/bluetooth/BluetoothAdapter.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 2b35e2bec4..b483054c99 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1940,8 +1940,8 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.MAP_CLIENT) { BluetoothMapClient mapClient = new BluetoothMapClient(context, listener); return true; - } else if (profile == BluetoothProfile.HID_DEVICE) { - BluetoothHidDevice hidd = new BluetoothHidDevice(context, listener); + } else if (profile == BluetoothProfile.INPUT_HOST) { + BluetoothInputHost iHost = new BluetoothInputHost(context, listener); return true; } else { return false; @@ -2019,9 +2019,9 @@ public final class BluetoothAdapter { BluetoothMapClient mapClient = (BluetoothMapClient)proxy; mapClient.close(); break; - case BluetoothProfile.HID_DEVICE: - BluetoothHidDevice hidd = (BluetoothHidDevice) proxy; - hidd.close(); + case BluetoothProfile.INPUT_HOST: + BluetoothInputHost iHost = (BluetoothInputHost) proxy; + iHost.close(); break; } } -- cgit v1.2.3 From 6eb20469015829978b820ba63bc0d064e36d3697 Mon Sep 17 00:00:00 2001 From: Marie Janssen Date: Wed, 28 Dec 2016 14:13:21 -0800 Subject: Bluetooth: track enabling in dumpsys Move basic state dumpsys to here from AdapterService. Track which apps are enabling and disabling Bluetooth, including BLE apps, and show the apps in the dumpsys logs. Test: start phone and enable/disable, take bug report Bug: 33692282 Change-Id: I6ea62ebdcfd7873d0be1bb5c5c520bbce3737a40 --- .../java/android/bluetooth/BluetoothAdapter.java | 99 ++++++++-------------- 1 file changed, 33 insertions(+), 66 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 4a97b078f7..927d382f64 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -680,30 +680,7 @@ public final class BluetoothAdapter { } /** - * Performs action based on user action to turn BT ON - * or OFF if BT is in BLE_ON state - */ - private void notifyUserAction(boolean enable) { - try { - mServiceLock.readLock().lock(); - if (mService == null) { - Log.e(TAG, "mService is null"); - return; - } - if (enable) { - mService.onLeServiceUp(); //NA:TODO implementation pending - } else { - mService.onBrEdrDown(); //NA:TODO implementation pending - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - } - - /** - * Turns off Bluetooth LE which was earlier turned on by calling EnableBLE(). + * Turns off Bluetooth LE which was earlier turned on by calling enableBLE(). * *

If the internal Adapter state is STATE_BLE_ON, this would trigger the transition * to STATE_OFF and completely shut-down Bluetooth @@ -733,61 +710,50 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) 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; + if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) { + String packageName = ActivityThread.currentPackageName(); + if (DBG) Log.d (TAG, "disableBLE(): de-registering " + packageName); try { - bleAppCnt = mManagerService.updateBleAppCount(mToken, false); + mManagerService.updateBleAppCount(mToken, false, packageName); } 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"); + if (DBG) Log.d (TAG, "disableBLE(): 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. - *

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. + * Applications who want to only use Bluetooth Low Energy (BLE) can call enableBLE. * - *

This is an asynchronous call: it will return immediately, and + * enableBLE registers the existence of an app using only LE functions. + * + * enableBLE may enable Bluetooth to an LE only mode so that an app can use + * LE related features (BluetoothGatt or BluetoothGattServer classes) + * + * If the user disables Bluetooth while an app is registered to use LE only features, + * Bluetooth will remain on in LE only mode for the app. + * + * When Bluetooth is in LE only mode, it is not shown as ON to the UI. + * + *

This is an asynchronous call: it returns 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 + * to be notified of adapter state changes. + * + * If this call returns * true, then the adapter state is either in a mode where + * LE is available, or will 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 prevents the + * adapter from being turned on - such as Airplane mode. + * + * {@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 + * @return true to indicate Bluetooth LE will be available, or false on * immediate error * @hide */ @@ -796,13 +762,14 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) return false; try { - mManagerService.updateBleAppCount(mToken, true); + String packageName = ActivityThread.currentPackageName(); + mManagerService.updateBleAppCount(mToken, true, packageName); if (isLeEnabled()) { if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled"); return true; } if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); - return mManagerService.enable(ActivityThread.currentPackageName()); + return mManagerService.enable(packageName); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -2087,7 +2054,7 @@ public final class BluetoothAdapter { return true; } try { - return mManagerService.enableNoAutoConnect(); + return mManagerService.enableNoAutoConnect(ActivityThread.currentPackageName()); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } -- cgit v1.2.3 From b6e4b12d1e4655e4a1f2b720fb48e33917e44511 Mon Sep 17 00:00:00 2001 From: Ivan Podogov Date: Fri, 30 Dec 2016 14:35:09 +0000 Subject: Fix profiles broken by ag/1751147 Change-Id: Ifa92819df8e63355a3979ea0f1a20a0363b6cd45 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 927d382f64..f9be3a1d7f 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1907,6 +1907,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.MAP_CLIENT) { BluetoothMapClient mapClient = new BluetoothMapClient(context, listener); return true; + } else if (profile == BluetoothProfile.INPUT_HOST) { + BluetoothInputHost iHost = new BluetoothInputHost(context, listener); + return true; } else { return false; } @@ -1983,6 +1986,10 @@ public final class BluetoothAdapter { BluetoothMapClient mapClient = (BluetoothMapClient)proxy; mapClient.close(); break; + case BluetoothProfile.INPUT_HOST: + BluetoothInputHost iHost = (BluetoothInputHost) proxy; + iHost.close(); + break; } } -- cgit v1.2.3 From e692bd35430c6a52ba59a734fdc37925fce5d30e Mon Sep 17 00:00:00 2001 From: Marie Janssen Date: Tue, 24 Jan 2017 14:09:59 -0800 Subject: Bluetooth: add getDiscoveryEndMillis() call Method to tell when the adapter finished (or will finish) being in discovery mode. Test: compiles and still can scan Bug: 34395439 Change-Id: I41b48c2b934c0a1d5e1727cec08f3f762e3cb309 --- .../java/android/bluetooth/BluetoothAdapter.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index f9be3a1d7f..9302cbc480 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1183,6 +1183,25 @@ public final class BluetoothAdapter { } } + /** + * Get the end time of the latest remote device discovery process. + * @return the latest time that the bluetooth adapter was/will be in discovery mode, + * in milliseconds since the epoch. + * This time can be in the future if {@link #startDiscovery()} has been called recently. + * @hide + */ + public long getDiscoveryEndMillis() { + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.getDiscoveryEndMillis(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + return -1; + } + /** * Start the remote device discovery process. *

The discovery process usually involves an inquiry scan of about 12 -- cgit v1.2.3 From 0849d40e0b2c0f91ac5c161f672c4f17d424eec0 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Fri, 3 Feb 2017 16:38:59 +0530 Subject: Bluetooth: Expose L2CAP API to support OPP 1.2 Add changes to expose L2CAP API to create an insecure L2CAP socket for supporting OPP 1.2. Test: Connect with Remote OPP Client supporting OPP 1.2 and verify that connection and transfer happens over L2CAP. Connect with Remote OPP Client supporting OPP 1.1 and verify that connection and transfer happens over RFCOMM. Bug: 33010988 Change-Id: I21ed672afb4ed5d2355ff0a0f9691af220921c1f --- .../java/android/bluetooth/BluetoothAdapter.java | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 9302cbc480..dbc25afcd0 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1858,6 +1858,35 @@ public final class BluetoothAdapter { return listenUsingL2capOn(port, false, false); } + + /** + * Construct an insecure L2CAP server socket. + * Call #accept to retrieve connections to this socket. + *

To auto assign a port without creating a SDP record use + * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. + * @param port the PSM to listen on + * @return An L2CAP BluetoothServerSocket + * @throws IOException On error, for example Bluetooth not available, or + * insufficient permissions. + * @hide + */ + public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException { + BluetoothServerSocket socket = new BluetoothServerSocket( + BluetoothSocket.TYPE_L2CAP, false, false, port, false, false); + int errno = socket.mSocket.bindListen(); + if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + socket.setChannel(socket.mSocket.getPort()); + } + if (errno != 0) { + //TODO(BT): Throw the same exception error code + // that the previous code was using. + //socket.mSocket.throwErrnoNative(errno); + throw new IOException("Error: " + errno); + } + return socket; + + } + /** * Read the local Out of Band Pairing Data *

Requires {@link android.Manifest.permission#BLUETOOTH} -- cgit v1.2.3 From 60d90308de61d0a54605829a0328b8d34670c6ba Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Tue, 7 Feb 2017 18:05:39 -0800 Subject: Bluetooth 5 feature check API (1/2) Bug: 30622771 Test: manual Change-Id: I90e2efe989745c07c2f2fb8f4ea5bc3b718382f6 (cherry picked from commit 79d66495c32996a5b532328571bf6ceecca70ca5) --- .../java/android/bluetooth/BluetoothAdapter.java | 72 ++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index dbc25afcd0..4ecf1249d1 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1384,6 +1384,78 @@ public final class BluetoothAdapter { return false; } + /** + * Return true if LE 2M PHY feature is supported. + * + * @return true if chipset supports LE 2M PHY feature + */ + public boolean isLe2MPhySupported() { + if (!getLeAccess()) return false; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.isLe2MPhySupported(); + } catch (RemoteException e) { + Log.e(TAG, "failed to get isExtendedAdvertisingSupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; + } + + /** + * Return true if LE Coded PHY feature is supported. + * + * @return true if chipset supports LE Coded PHY feature + */ + public boolean isLeCodedPhySupported() { + if (!getLeAccess()) return false; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.isLeCodedPhySupported(); + } catch (RemoteException e) { + Log.e(TAG, "failed to get isLeCodedPhySupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; + } + + /** + * Return true if LE Periodic Advertising feature is supported. + * + * @return true if chipset supports LE Periodic Advertising feature + */ + public boolean isLeExtendedAdvertisingSupported() { + if (!getLeAccess()) return false; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.isLeExtendedAdvertisingSupported(); + } catch (RemoteException e) { + Log.e(TAG, "failed to get isLeExtendedAdvertisingSupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; + } + + /** + * Return true if LE Periodic Advertising feature is supported. + * + * @return true if chipset supports LE Periodic Advertising feature + */ + public boolean isLePeriodicAdvertisingSupported() { + if (!getLeAccess()) return false; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.isLePeriodicAdvertisingSupported(); + } catch (RemoteException e) { + Log.e(TAG, "failed to get isLePeriodicAdvertisingSupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; + } + /** * Return true if hardware has entries available for matching beacons * -- cgit v1.2.3 From b74a8cd801d63b94c1770299f02bcb1de5b3b8ea Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Mon, 16 Jan 2017 07:21:01 -0800 Subject: Bluetooth 5 periodc scan API (1/2) Bug: 30622771 Test: manual Change-Id: I61853bc71f6013e9406d1d151bb51ea4484bb92c (cherry picked from commit a48e03745becc96181c676dc3d194d0572f11c10) --- .../java/android/bluetooth/BluetoothAdapter.java | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 4ecf1249d1..818693773a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -26,6 +26,7 @@ import android.annotation.SystemApi; import android.app.ActivityThread; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.PeriodicAdvertisingManager; import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanRecord; @@ -525,6 +526,7 @@ public final class BluetoothAdapter { private static BluetoothLeScanner sBluetoothLeScanner; private static BluetoothLeAdvertiser sBluetoothLeAdvertiser; + private static PeriodicAdvertisingManager sPeriodicAdvertisingManager; private final IBluetoothManager mManagerService; private IBluetooth mService; @@ -629,6 +631,30 @@ public final class BluetoothAdapter { return sBluetoothLeAdvertiser; } + /** + * Returns a {@link PeriodicAdvertisingManager} object for Bluetooth LE Periodic Advertising + * operations. Will return null if Bluetooth is turned off or if Bluetooth LE Periodic + * Advertising is not supported on this device. + *

+ * Use {@link #isLePeriodicAdvertisingSupported()} to check whether LE Periodic Advertising is + * supported on this device before calling this method. + */ + public PeriodicAdvertisingManager getPeriodicAdvertisingManager() { + if (!getLeAccess()) + return null; + + if (!isLePeriodicAdvertisingSupported()) + return null; + + synchronized (mLock) { + if (sPeriodicAdvertisingManager == null) { + sPeriodicAdvertisingManager = + new PeriodicAdvertisingManager(mManagerService); + } + } + return sPeriodicAdvertisingManager; + } + /** * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. */ -- cgit v1.2.3 From 842b81b37744f6dd4a18c7b02c31d6cb84a29b53 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Fri, 10 Mar 2017 16:07:59 -0800 Subject: Bluetooth 5 spelling fixes Bug: 30622771 Test: manual Change-Id: I46b6486619cc7366e56b25ca48937e6792f53e1d (cherry picked from commit 53501ad210dd5c65c7910a6b75b2b481e92dd22f) --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 818693773a..c689da6ca7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1447,9 +1447,9 @@ public final class BluetoothAdapter { } /** - * Return true if LE Periodic Advertising feature is supported. + * Return true if LE Extended Advertising feature is supported. * - * @return true if chipset supports LE Periodic Advertising feature + * @return true if chipset supports LE Extended Advertising feature */ public boolean isLeExtendedAdvertisingSupported() { if (!getLeAccess()) return false; -- cgit v1.2.3 From 1e2d5cb0e985d3f624fbaba697bb3a147c17582a Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Thu, 16 Mar 2017 18:22:36 -0700 Subject: LE Maximum Advertising Data Length (1/4) Add ability to check maximum advertising data length. Bug: 30622771 Test: manual Change-Id: I281f7e9f294c40a47a67a22809cc753b6693f7c4 --- .../java/android/bluetooth/BluetoothAdapter.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index c689da6ca7..27640e7882 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1482,6 +1482,25 @@ public final class BluetoothAdapter { return false; } + /** + * Return the maximum LE advertising data length, + * if LE Extended Advertising feature is supported. + * + * @return the maximum LE advertising data length. + */ + public int getLeMaximumAdvertisingDataLength() { + if (!getLeAccess()) return 0; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.getLeMaximumAdvertisingDataLength(); + } catch (RemoteException e) { + Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e); + } finally { + mServiceLock.readLock().unlock(); + } + return 0; + } + /** * Return true if hardware has entries available for matching beacons * -- cgit v1.2.3 From 409577c38a97b1a919236ba655d5872ca158b77c Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Wed, 29 Mar 2017 17:00:44 -0700 Subject: Hide periodic scanning Bug: 30622771 Test: manual Change-Id: I5d786b13cf99287732e16769e2563ac7c4fe715c --- framework/java/android/bluetooth/BluetoothAdapter.java | 1 + 1 file changed, 1 insertion(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 27640e7882..2c4520d391 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -638,6 +638,7 @@ public final class BluetoothAdapter { *

* Use {@link #isLePeriodicAdvertisingSupported()} to check whether LE Periodic Advertising is * supported on this device before calling this method. + * @hide */ public PeriodicAdvertisingManager getPeriodicAdvertisingManager() { if (!getLeAccess()) -- cgit v1.2.3 From 8d0c4baa427a7a6f6c84227c0585096534fed614 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Wed, 29 Mar 2017 17:00:44 -0700 Subject: Hide periodic scanning Bug: 30622771 Test: manual Change-Id: I5d786b13cf99287732e16769e2563ac7c4fe715c (cherry picked from commit 409577c38a97b1a919236ba655d5872ca158b77c) --- framework/java/android/bluetooth/BluetoothAdapter.java | 1 + 1 file changed, 1 insertion(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 4e1e42da4f..845a47d998 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -638,6 +638,7 @@ public final class BluetoothAdapter { *

* Use {@link #isLePeriodicAdvertisingSupported()} to check whether LE Periodic Advertising is * supported on this device before calling this method. + * @hide */ public PeriodicAdvertisingManager getPeriodicAdvertisingManager() { if (!getLeAccess()) -- cgit v1.2.3 From 723ee54c608a9ed16738de6382a06ee281bd5f83 Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Mon, 17 Apr 2017 22:35:45 -0700 Subject: Allow the Bluetooth MAC address to be updated asynchronously (2/3) There are intermittent issues where either the returned Bluetooth MAC address to Java framework is uninitialized or this address update arrives too late. This fix will do 2 things: (1) Returns error when MAC address is unavailable in the native code. (2) Updates the MAC address later by adding a new broadcast event. Test: Check address for these cases: factory reset, system reboot, and Bluetooth re-enable. Bug: 36709382 Change-Id: I09720193e38fdf9139e1bb146f8e1847e2b65b1a --- .../java/android/bluetooth/BluetoothAdapter.java | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 845a47d998..85636033d8 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -465,6 +465,30 @@ public final class BluetoothAdapter { public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; + /** + * Intent used to broadcast the change in the Bluetooth address + * of the local Bluetooth adapter. + *

Always contains the extra field {@link + * #EXTRA_BLUETOOTH_ADDRESS} containing the Bluetooth address. + * + * Note: only system level processes are allowed to send this + * defined broadcast. + * + * @hide + */ + public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED = + "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED"; + + /** + * Used as a String extra field in {@link + * #ACTION_BLUETOOTH_ADDRESS_CHANGED} intent to store the local + * Bluetooth address. + * + * @hide + */ + public static final String EXTRA_BLUETOOTH_ADDRESS = + "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS"; + /** * Broadcast Action: The notifys Bluetooth ACL connected event. This will be * by BLE Always on enabled application to know the ACL_CONNECTED event -- cgit v1.2.3 From 0e00a22d944036df3200df1afc86e9c3e8cac424 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Fri, 21 Apr 2017 04:59:55 -0700 Subject: Bluetooth: improve getLeMaximumAdvertisingDataLength comment Bug: 37534792 Test: none Change-Id: Ieff71356aceb0e2a4c6e81d9053f854448e0c927 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 85636033d8..735d84e72b 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1508,8 +1508,8 @@ public final class BluetoothAdapter { } /** - * Return the maximum LE advertising data length, - * if LE Extended Advertising feature is supported. + * Return the maximum LE advertising data length in bytes, + * if LE Extended Advertising feature is supported, 0 otherwise. * * @return the maximum LE advertising data length. */ -- cgit v1.2.3 From dc3abd6c94df6896f5247e3951be4b67ac629996 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Fri, 21 Apr 2017 04:59:55 -0700 Subject: Bluetooth: improve getLeMaximumAdvertisingDataLength comment Bug: 37534792 Test: none Change-Id: Ieff71356aceb0e2a4c6e81d9053f854448e0c927 (cherry picked from commit 4634b5cd27b274105e550f58f9d5fc51c79eb3fb) --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 845a47d998..1aca1d14e2 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1484,8 +1484,8 @@ public final class BluetoothAdapter { } /** - * Return the maximum LE advertising data length, - * if LE Extended Advertising feature is supported. + * Return the maximum LE advertising data length in bytes, + * if LE Extended Advertising feature is supported, 0 otherwise. * * @return the maximum LE advertising data length. */ -- cgit v1.2.3 From cf3818675f65d8c1901b3d33eab5db1cabb74ea7 Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Mon, 17 Apr 2017 22:35:45 -0700 Subject: Allow the Bluetooth MAC address to be updated asynchronously (2/3) There are intermittent issues where either the returned Bluetooth MAC address to Java framework is uninitialized or this address update arrives too late. This fix will do 2 things: (1) Returns error when MAC address is unavailable in the native code. (2) Updates the MAC address later by adding a new broadcast event. Test: Check address for these cases: factory reset, system reboot, and Bluetooth re-enable. Bug: 36709382 Change-Id: I09720193e38fdf9139e1bb146f8e1847e2b65b1a (cherry picked from commit ad4d1d8e28618546953e75d4983335631feb6f2a) --- .../java/android/bluetooth/BluetoothAdapter.java | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 845a47d998..85636033d8 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -465,6 +465,30 @@ public final class BluetoothAdapter { public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; + /** + * Intent used to broadcast the change in the Bluetooth address + * of the local Bluetooth adapter. + *

Always contains the extra field {@link + * #EXTRA_BLUETOOTH_ADDRESS} containing the Bluetooth address. + * + * Note: only system level processes are allowed to send this + * defined broadcast. + * + * @hide + */ + public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED = + "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED"; + + /** + * Used as a String extra field in {@link + * #ACTION_BLUETOOTH_ADDRESS_CHANGED} intent to store the local + * Bluetooth address. + * + * @hide + */ + public static final String EXTRA_BLUETOOTH_ADDRESS = + "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS"; + /** * Broadcast Action: The notifys Bluetooth ACL connected event. This will be * by BLE Always on enabled application to know the ACL_CONNECTED event -- cgit v1.2.3 From fbe8b2299f543aee40d44794f7e68a0abbea112c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 21 Apr 2017 16:29:27 -0600 Subject: More auto-doc work. Add support for AnyThread, CallSuper, and UiThread. Another related CL started documenting @RequiresPermission, so remove duplicated information in existing APIs. Suppress auto-doc on a handful of classes that are already well-documented. Test: make -j32 offline-sdk-docs Bug: 37526420 Change-Id: I791437dccec0f11d5349a23b982ba098cb551af8 --- .../java/android/bluetooth/BluetoothAdapter.java | 24 ---------------------- 1 file changed, 24 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 845a47d998..8bd568e7fb 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -673,7 +673,6 @@ public final class BluetoothAdapter { * Return true if Bluetooth is currently enabled and ready for use. *

Equivalent to: * getBluetoothState() == STATE_ON - *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @return true if the local adapter is turned on */ @@ -811,7 +810,6 @@ public final class BluetoothAdapter { * {@link #STATE_TURNING_ON}, * {@link #STATE_ON}, * {@link #STATE_TURNING_OFF}. - *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @return current state of Bluetooth adapter */ @@ -854,7 +852,6 @@ public final class BluetoothAdapter { * {@link #STATE_ON}, * {@link #STATE_TURNING_OFF}, * {@link #STATE_BLE_TURNING_OFF}. - *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @return current state of Bluetooth adapter * @hide @@ -910,8 +907,6 @@ public final class BluetoothAdapter { * #STATE_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. - *

Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * permission * * @return true to indicate adapter startup has begun, or false on * immediate error @@ -946,8 +941,6 @@ public final class BluetoothAdapter { * #STATE_ON}. If this call returns false then there was an * immediate problem that will prevent the adapter from being turned off - * such as the adapter already being turned off. - *

Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * permission * * @return true to indicate adapter shutdown has begun, or false on * immediate error @@ -981,7 +974,6 @@ public final class BluetoothAdapter { /** * Returns the hardware address of the local Bluetooth adapter. *

For example, "00:11:22:AA:BB:CC". - *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @return Bluetooth hardware address as string */ @@ -1085,7 +1077,6 @@ public final class BluetoothAdapter { * will return false. After turning on Bluetooth, * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} * to get the updated value. - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * * @param name a valid Bluetooth name * @return true if the name was set, false otherwise @@ -1116,7 +1107,6 @@ public final class BluetoothAdapter { * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth, * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} * to get the updated value. - *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @return scan mode */ @@ -1255,7 +1245,6 @@ public final class BluetoothAdapter { * will return false. After turning on Bluetooth, * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} * to get the updated value. - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. * * @return true on success, false on error */ @@ -1275,7 +1264,6 @@ public final class BluetoothAdapter { /** * Cancel the current device discovery process. - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. *

Because discovery is a heavyweight procedure for the Bluetooth * adapter, this method should always be called before attempting to connect * to a remote device with {@link @@ -1319,7 +1307,6 @@ public final class BluetoothAdapter { * will return false. After turning on Bluetooth, * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} * to get the updated value. - *

Requires {@link android.Manifest.permission#BLUETOOTH}. * * @return true if discovering */ @@ -1586,7 +1573,6 @@ public final class BluetoothAdapter { * will return an empty set. After turning on Bluetooth, * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} * to get the updated value. - *

Requires {@link android.Manifest.permission#BLUETOOTH}. * * @return unmodifiable set of {@link BluetoothDevice}, or null on error */ @@ -1671,8 +1657,6 @@ public final class BluetoothAdapter { * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, * {@link BluetoothProfile#A2DP}. * - *

Requires {@link android.Manifest.permission#BLUETOOTH}. - * *

Return value can be one of * {@link BluetoothProfile#STATE_DISCONNECTED}, * {@link BluetoothProfile#STATE_CONNECTING}, @@ -1762,7 +1746,6 @@ public final class BluetoothAdapter { * closed, or if this application closes unexpectedly. *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to * connect to this socket from another device using the same {@link UUID}. - *

Requires {@link android.Manifest.permission#BLUETOOTH} * @param name service name for SDP record * @param uuid uuid for SDP record * @return a listening RFCOMM BluetoothServerSocket @@ -1794,7 +1777,6 @@ public final class BluetoothAdapter { * closed, or if this application closes unexpectedly. *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to * connect to this socket from another device using the same {@link UUID}. - *

Requires {@link android.Manifest.permission#BLUETOOTH} * @param name service name for SDP record * @param uuid uuid for SDP record * @return a listening RFCOMM BluetoothServerSocket @@ -2386,8 +2368,6 @@ public final class BluetoothAdapter { *

Results of the scan are reported using the * {@link LeScanCallback#onLeScan} callback. * - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. - * * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)} @@ -2406,8 +2386,6 @@ public final class BluetoothAdapter { *

Devices which advertise all specified services are reported using the * {@link LeScanCallback#onLeScan} callback. * - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. - * * @param serviceUuids Array of services to look for * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully @@ -2495,8 +2473,6 @@ public final class BluetoothAdapter { /** * Stops an ongoing Bluetooth LE device scan. * - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. - * * @param callback used to identify which scan to stop * must be the same handle used to start the scan * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead. -- cgit v1.2.3 From 210515a2790b88e3587ea39241c80ca73fbd5ffb Mon Sep 17 00:00:00 2001 From: Ajay Panicker Date: Mon, 17 Apr 2017 20:42:22 -0700 Subject: Limit btsnoop file size (3/8) Limit btsnoop file size by rotating between snoop files. The rotation occurrs when a fixed number of packets have been logged and will start overwriting the older file. Bug: 35998031 Test: Enable snoop logs from developer options and let logs get large Merged-In: I40d5da4c1b1c9b45908e5790d130f1c5e804c773 Change-Id: I40d5da4c1b1c9b45908e5790d130f1c5e804c773 --- .../java/android/bluetooth/BluetoothAdapter.java | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 735d84e72b..ff52f27447 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1031,28 +1031,6 @@ public final class BluetoothAdapter { return null; } - /** - * enable or disable Bluetooth HCI snoop log. - * - *

Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * permission - * - * @return true to indicate configure HCI log successfully, or false on - * immediate error - * @hide - */ - public boolean configHciSnoopLog(boolean enable) { - try { - mServiceLock.readLock().lock(); - if (mService != null) return mService.configHciSnoopLog(enable); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - /** * Factory reset bluetooth settings. * -- cgit v1.2.3 From dbbc5ff3db35c9554d9a85a907d28a95354281e6 Mon Sep 17 00:00:00 2001 From: Ajay Panicker Date: Mon, 17 Apr 2017 20:42:22 -0700 Subject: Limit btsnoop file size (3/8) Limit btsnoop file size by rotating between snoop files. The rotation occurrs when a fixed number of packets have been logged and will start overwriting the older file. Bug: 35998031 Test: Enable snoop logs from developer options and let logs get large Change-Id: I40d5da4c1b1c9b45908e5790d130f1c5e804c773 (cherry picked from commit 7e2e61ee2e3f46fa0e4bee82028b36a0f2aa22d5) --- .../java/android/bluetooth/BluetoothAdapter.java | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index d60d4db1ca..64c0f31de7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1023,28 +1023,6 @@ public final class BluetoothAdapter { return null; } - /** - * enable or disable Bluetooth HCI snoop log. - * - *

Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * permission - * - * @return true to indicate configure HCI log successfully, or false on - * immediate error - * @hide - */ - public boolean configHciSnoopLog(boolean enable) { - try { - mServiceLock.readLock().lock(); - if (mService != null) return mService.configHciSnoopLog(enable); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; - } - /** * Factory reset bluetooth settings. * -- cgit v1.2.3 From 36354fb05c282dcb0e4b27bd4422fa424b7bc032 Mon Sep 17 00:00:00 2001 From: Marie Janssen Date: Thu, 12 Jan 2017 16:00:30 -0800 Subject: Bluetooth: minor documentation fix to de-confuse It was somewhat unclear which is the preferred method of retrieving a BluetoothAdapter. Make it clear that using BluetoothManager is preferred, and remove references to the old method in BluetoothManager docs since it is only avaialable in API 18 or higher. Test: recompile, check that documentation is updated Fix: 33355430 Change-Id: Ia20b4e45dca03bc2f13c2ab477799b89c5e14f45 --- framework/java/android/bluetooth/BluetoothAdapter.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ff52f27447..838fb72ea3 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -70,9 +70,10 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * devices, and start a scan for Bluetooth LE devices. * *

To get a {@link BluetoothAdapter} representing the local Bluetooth - * adapter, when running on JELLY_BEAN_MR1 and below, call the - * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and - * higher, call {@link BluetoothManager#getAdapter}. + * adapter, call the {@link BluetoothManager#getAdapter} function on {@link BluetoothManager}. + * On JELLY_BEAN_MR1 and below you will need to use the static {@link #getDefaultAdapter} + * method instead. + *

* Fundamentally, this is your starting point for all * Bluetooth actions. Once you have the local adapter, you can get a set of * {@link BluetoothDevice} objects representing all paired devices with @@ -81,14 +82,13 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * listen for incoming connection requests with * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}; or start a scan for * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. - * - *

This class is thread safe. - * + *

+ *

This class is thread safe.

*

Note: * Most methods require the {@link android.Manifest.permission#BLUETOOTH} * permission and some also require the * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. - * + *

*
*

Developer Guides

*

@@ -565,6 +565,7 @@ public final class BluetoothAdapter { *

Currently Android only supports one Bluetooth adapter, but the API * could be extended to support more. This will always return the default * adapter. + *

* @return the default local adapter, or null if Bluetooth is not supported * on this hardware platform */ -- cgit v1.2.3 From 910201beb0bde1dcf6b33e4ec5d1eb60042419d8 Mon Sep 17 00:00:00 2001 From: Jack He Date: Tue, 22 Aug 2017 16:06:54 -0700 Subject: Fix checkstyle errors (1/2) * Automatic style corrections through IDE Bug: 63596319 Test: make checkbuild, no manual changes, no functional changes Change-Id: I2397d55abc34c9b7a9b748bec6137778df3421a7 --- .../java/android/bluetooth/BluetoothAdapter.java | 498 ++++++++++++--------- 1 file changed, 274 insertions(+), 224 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index fc3a72482a..1b9ce88de0 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -80,7 +80,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * {@link #getBondedDevices()}; start device discovery with * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to * listen for incoming connection requests with - * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}; or start a scan for + * {@link #listenUsingRfcommWithServiceRecord(String, UUID)}; or start a scan for * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. *

*

This class is thread safe.

@@ -92,7 +92,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; *
*

Developer Guides

*

- * For more information about using Bluetooth, read the Bluetooth developer * guide. *

@@ -161,7 +161,8 @@ public final class BluetoothAdapter { @IntDef({STATE_OFF, STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, STATE_BLE_TURNING_ON, STATE_BLE_ON, STATE_BLE_TURNING_OFF}) @Retention(RetentionPolicy.SOURCE) - public @interface AdapterState {} + public @interface AdapterState { + } /** * Indicates the local Bluetooth adapter is off. @@ -185,36 +186,48 @@ public final class BluetoothAdapter { /** * 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; /** * Human-readable string helper for AdapterState + * * @hide */ public static String nameForState(@AdapterState int state) { - switch(state) { - case STATE_OFF: return "OFF"; - case STATE_TURNING_ON: return "TURNING_ON"; - case STATE_ON: return "ON"; - case STATE_TURNING_OFF: return "TURNING_OFF"; - case STATE_BLE_TURNING_ON: return "BLE_TURNING_ON"; - case STATE_BLE_ON: return "BLE_ON"; - case STATE_BLE_TURNING_OFF: return "BLE_TURNING_OFF"; - default: return "?!?!? (" + state + ")"; + switch (state) { + case STATE_OFF: + return "OFF"; + case STATE_TURNING_ON: + return "TURNING_ON"; + case STATE_ON: + return "ON"; + case STATE_TURNING_OFF: + return "TURNING_OFF"; + case STATE_BLE_TURNING_ON: + return "BLE_TURNING_ON"; + case STATE_BLE_ON: + return "BLE_ON"; + case STATE_BLE_TURNING_OFF: + return "BLE_TURNING_OFF"; + default: + return "?!?!? (" + state + ")"; } } @@ -346,7 +359,8 @@ public final class BluetoothAdapter { /** @hide */ @IntDef({SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE}) @Retention(RetentionPolicy.SOURCE) - public @interface ScanMode {} + public @interface ScanMode { + } /** * Indicates that both inquiry scan and page scan are disabled on the local @@ -439,7 +453,7 @@ public final class BluetoothAdapter { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CONNECTION_STATE_CHANGED = - "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"; + "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"; /** * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} @@ -447,7 +461,7 @@ public final class BluetoothAdapter { * This extra represents the current connection state. */ public static final String EXTRA_CONNECTION_STATE = - "android.bluetooth.adapter.extra.CONNECTION_STATE"; + "android.bluetooth.adapter.extra.CONNECTION_STATE"; /** * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} @@ -455,15 +469,16 @@ public final class BluetoothAdapter { * This extra represents the previous connection state. */ public static final String EXTRA_PREVIOUS_CONNECTION_STATE = - "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE"; + "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE"; /** * Broadcast Action: The Bluetooth adapter state has changed in LE only mode. + * * @hide */ @SystemApi public static final String ACTION_BLE_STATE_CHANGED = - "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; + "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; /** * Intent used to broadcast the change in the Bluetooth address @@ -477,7 +492,7 @@ public final class BluetoothAdapter { * @hide */ public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED = - "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED"; + "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED"; /** * Used as a String extra field in {@link @@ -487,7 +502,7 @@ public final class BluetoothAdapter { * @hide */ public static final String EXTRA_BLUETOOTH_ADDRESS = - "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS"; + "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS"; /** * Broadcast Action: The notifys Bluetooth ACL connected event. This will be @@ -497,10 +512,11 @@ public final class BluetoothAdapter { * * 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"; + "android.bluetooth.adapter.action.BLE_ACL_CONNECTED"; /** * Broadcast Action: The notifys Bluetooth ACL connected event. This will be @@ -510,17 +526,18 @@ public final class BluetoothAdapter { * * 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"; + "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED"; /** The profile is in disconnected state */ - public static final int STATE_DISCONNECTED = 0; + public static final int STATE_DISCONNECTED = 0; /** The profile is in connecting state */ - public static final int STATE_CONNECTING = 1; + public static final int STATE_CONNECTING = 1; /** The profile is in connected state */ - public static final int STATE_CONNECTED = 2; + public static final int STATE_CONNECTED = 2; /** The profile is in disconnecting state */ public static final int STATE_DISCONNECTING = 3; @@ -529,14 +546,17 @@ public final class BluetoothAdapter { private final IBinder mToken; - /** When creating a ServerSocket using listenUsingRfcommOn() or - * listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create - * a ServerSocket that auto assigns a channel number to the first - * bluetooth socket. - * The channel number assigned to this first Bluetooth Socket will - * be stored in the ServerSocket, and reused for subsequent Bluetooth - * sockets. - * @hide */ + /** + * When creating a ServerSocket using listenUsingRfcommOn() or + * listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create + * a ServerSocket that auto assigns a channel number to the first + * bluetooth socket. + * The channel number assigned to this first Bluetooth Socket will + * be stored in the ServerSocket, and reused for subsequent Bluetooth + * sockets. + * + * @hide + */ public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2; @@ -555,7 +575,7 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; private IBluetooth mService; private final ReentrantReadWriteLock mServiceLock = - new ReentrantReadWriteLock(); + new ReentrantReadWriteLock(); private final Object mLock = new Object(); private final Map mLeScanClients; @@ -566,8 +586,9 @@ public final class BluetoothAdapter { * could be extended to support more. This will always return the default * adapter. *

- * @return the default local adapter, or null if Bluetooth is not supported - * on this hardware platform + * + * @return the default local adapter, or null if Bluetooth is not supported on this hardware + * platform */ public static synchronized BluetoothAdapter getDefaultAdapter() { if (sAdapter == null) { @@ -648,7 +669,7 @@ public final class BluetoothAdapter { */ public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { if (!getLeAccess()) return null; - synchronized(mLock) { + synchronized (mLock) { if (sBluetoothLeAdvertiser == null) { sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); } @@ -663,22 +684,25 @@ public final class BluetoothAdapter { *

* Use {@link #isLePeriodicAdvertisingSupported()} to check whether LE Periodic Advertising is * supported on this device before calling this method. + * * @hide */ public PeriodicAdvertisingManager getPeriodicAdvertisingManager() { - if (!getLeAccess()) - return null; + if (!getLeAccess()) { + return null; + } - if (!isLePeriodicAdvertisingSupported()) - return null; + if (!isLePeriodicAdvertisingSupported()) { + return null; + } - synchronized (mLock) { - if (sPeriodicAdvertisingManager == null) { - sPeriodicAdvertisingManager = - new PeriodicAdvertisingManager(mManagerService); + synchronized (mLock) { + if (sPeriodicAdvertisingManager == null) { + sPeriodicAdvertisingManager = + new PeriodicAdvertisingManager(mManagerService); + } } - } - return sPeriodicAdvertisingManager; + return sPeriodicAdvertisingManager; } /** @@ -686,7 +710,7 @@ public final class BluetoothAdapter { */ public BluetoothLeScanner getBluetoothLeScanner() { if (!getLeAccess()) return null; - synchronized(mLock) { + synchronized (mLock) { if (sBluetoothLeScanner == null) { sBluetoothLeScanner = new BluetoothLeScanner(mManagerService); } @@ -725,9 +749,9 @@ public final class BluetoothAdapter { */ @SystemApi public boolean isLeEnabled() { - final int state = getLeState(); - if (DBG) Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state)); - return (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON); + final int state = getLeState(); + if (DBG) Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state)); + return (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON); } /** @@ -752,8 +776,7 @@ public final class BluetoothAdapter { * 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 + * @return true to indicate success, or false on immediate error * @hide */ @SystemApi @@ -763,7 +786,7 @@ public final class BluetoothAdapter { int state = getLeState(); if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) { String packageName = ActivityThread.currentPackageName(); - if (DBG) Log.d (TAG, "disableBLE(): de-registering " + packageName); + if (DBG) Log.d(TAG, "disableBLE(): de-registering " + packageName); try { mManagerService.updateBleAppCount(mToken, false, packageName); } catch (RemoteException e) { @@ -772,7 +795,7 @@ public final class BluetoothAdapter { return true; } - if (DBG) Log.d (TAG, "disableBLE(): Already disabled"); + if (DBG) Log.d(TAG, "disableBLE(): Already disabled"); return false; } @@ -804,8 +827,7 @@ public final class BluetoothAdapter { * states, It includes all the classic Bluetooth Adapter states along with * internal BLE only states * - * @return true to indicate Bluetooth LE will be available, or false on - * immediate error + * @return true to indicate Bluetooth LE will be available, or false on immediate error * @hide */ @SystemApi @@ -856,12 +878,19 @@ public final class BluetoothAdapter { // 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 " + BluetoothAdapter.nameForState(state) + " state as OFF"); + || state == BluetoothAdapter.STATE_BLE_TURNING_ON + || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { + if (VDBG) { + Log.d(TAG, + "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF"); + } state = BluetoothAdapter.STATE_OFF; } - if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState(state)); + if (VDBG) { + Log.d(TAG, + "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState( + state)); + } return state; } @@ -897,16 +926,16 @@ public final class BluetoothAdapter { mServiceLock.readLock().unlock(); } - if (VDBG) Log.d(TAG,"getLeState() returning " + BluetoothAdapter.nameForState(state)); + if (VDBG) Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state)); return state; } boolean getLeAccess() { - if (getLeState() == STATE_ON) + if (getLeState() == STATE_ON) { return true; - - else if (getLeState() == STATE_BLE_ON) + } else if (getLeState() == STATE_BLE_ON) { return true; // TODO: FILTER SYSTEM APPS HERE <-- + } return false; } @@ -933,8 +962,7 @@ public final class BluetoothAdapter { * immediate problem that will prevent the adapter from being turned on - * such as Airplane mode, or the adapter is already turned on. * - * @return true to indicate adapter startup has begun, or false on - * immediate error + * @return true to indicate adapter startup has begun, or false on immediate error */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean enable() { @@ -944,7 +972,9 @@ public final class BluetoothAdapter { } try { return mManagerService.enable(ActivityThread.currentPackageName()); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) { + Log.e(TAG, "", e); + } return false; } @@ -967,14 +997,15 @@ public final class BluetoothAdapter { * immediate problem that will prevent the adapter from being turned off - * such as the adapter already being turned off. * - * @return true to indicate adapter shutdown has begun, or false on - * immediate error + * @return true to indicate adapter shutdown has begun, or false on immediate error */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean disable() { try { return mManagerService.disable(ActivityThread.currentPackageName(), true); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) { + Log.e(TAG, "", e); + } return false; } @@ -984,15 +1015,16 @@ public final class BluetoothAdapter { *

Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} * permission * - * @return true to indicate adapter shutdown has begun, or false on - * immediate error + * @return true to indicate adapter shutdown has begun, or false on immediate error * @hide */ public boolean disable(boolean persist) { try { return mManagerService.disable(ActivityThread.currentPackageName(), persist); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) { + Log.e(TAG, "", e); + } return false; } @@ -1006,7 +1038,9 @@ public final class BluetoothAdapter { public String getAddress() { try { return mManagerService.getAddress(); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) { + Log.e(TAG, "", e); + } return null; } @@ -1020,7 +1054,9 @@ public final class BluetoothAdapter { public String getName() { try { return mManagerService.getName(); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) { + Log.e(TAG, "", e); + } return null; } @@ -1031,7 +1067,6 @@ public final class BluetoothAdapter { * permission * * @return true to indicate that the config file was successfully cleared - * * @hide */ public boolean factoryReset() { @@ -1082,7 +1117,7 @@ public final class BluetoothAdapter { * to get the updated value. * * @param name a valid Bluetooth name - * @return true if the name was set, false otherwise + * @return true if the name was set, false otherwise */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String name) { @@ -1151,9 +1186,9 @@ public final class BluetoothAdapter { * instead. * * @param mode valid scan mode - * @param duration time in seconds to apply scan mode, only used for - * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE} - * @return true if the scan mode was set, false otherwise + * @param duration time in seconds to apply scan mode, only used for {@link + * #SCAN_MODE_CONNECTABLE_DISCOVERABLE} + * @return true if the scan mode was set, false otherwise * @hide */ public boolean setScanMode(@ScanMode int mode, int duration) { @@ -1205,9 +1240,10 @@ public final class BluetoothAdapter { /** * Get the end time of the latest remote device discovery process. - * @return the latest time that the bluetooth adapter was/will be in discovery mode, - * in milliseconds since the epoch. - * This time can be in the future if {@link #startDiscovery()} has been called recently. + * + * @return the latest time that the bluetooth adapter was/will be in discovery mode, in + * milliseconds since the epoch. This time can be in the future if {@link #startDiscovery()} has + * been called recently. * @hide */ public long getDiscoveryEndMillis() { @@ -1517,13 +1553,13 @@ public final class BluetoothAdapter { * Return the record of {@link BluetoothActivityEnergyInfo} object that * has the activity and energy info. This can be used to ascertain what * the controller has been up to, since the last sample. - * @param updateType Type of info, cached vs refreshed. * - * @return a record with {@link BluetoothActivityEnergyInfo} or null if - * report is unavailable or unsupported - * @deprecated use the asynchronous - * {@link #requestControllerActivityEnergyInfo(ResultReceiver)} instead. + * @param updateType Type of info, cached vs refreshed. + * @return a record with {@link BluetoothActivityEnergyInfo} or null if report is unavailable or + * unsupported * @hide + * @deprecated use the asynchronous {@link #requestControllerActivityEnergyInfo(ResultReceiver)} + * instead. */ @Deprecated public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { @@ -1599,11 +1635,11 @@ public final class BluetoothAdapter { /** * Gets the currently supported profiles by the adapter. * - *

This can be used to check whether a profile is supported before attempting + *

This can be used to check whether a profile is supported before attempting * to connect to its respective proxy. * - * @return a list of integers indicating the ids of supported profiles as defined in - * {@link BluetoothProfile}. + * @return a list of integers indicating the ids of supported profiles as defined in {@link + * BluetoothProfile}. * @hide */ public List getSupportedProfiles() { @@ -1622,7 +1658,7 @@ public final class BluetoothAdapter { } } } catch (RemoteException e) { - Log.e(TAG, "getSupportedProfiles:", e); + Log.e(TAG, "getSupportedProfiles:", e); } return supportedProfiles; } @@ -1635,9 +1671,8 @@ public final class BluetoothAdapter { *

Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED} * intent to get the connection state of the adapter. * - * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED}, - * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED} - * + * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED}, {@link + * #STATE_CONNECTING} or {@link #STATE_DISCONNECTED} * @hide */ public int getConnectionState() { @@ -1688,10 +1723,11 @@ public final class BluetoothAdapter { * connections from a listening {@link BluetoothServerSocket}. *

Valid RFCOMM channels are in range 1 to 30. *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * * @param channel RFCOMM channel to listen on * @return a listening RFCOMM BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or - * insufficient permissions, or channel in use. + * @throws IOException on error, for example Bluetooth not available, or insufficient + * permissions, or channel in use. * @hide */ public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException { @@ -1708,12 +1744,14 @@ public final class BluetoothAdapter { *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} *

To auto assign a channel without creating a SDP record use * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. + * * @param channel RFCOMM channel to listen on - * @param mitm enforce man-in-the-middle protection for authentication. - * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 connections. + * @param mitm enforce man-in-the-middle protection for authentication. + * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 + * connections. * @return a listening RFCOMM BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or - * insufficient permissions, or channel in use. + * @throws IOException on error, for example Bluetooth not available, or insufficient + * permissions, or channel in use. * @hide */ public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm, @@ -1749,11 +1787,12 @@ public final class BluetoothAdapter { * closed, or if this application closes unexpectedly. *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to * connect to this socket from another device using the same {@link UUID}. + * * @param name service name for SDP record * @param uuid uuid for SDP record * @return a listening RFCOMM BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or - * insufficient permissions, or channel in use. + * @throws IOException on error, for example Bluetooth not available, or insufficient + * permissions, or channel in use. */ @RequiresPermission(Manifest.permission.BLUETOOTH) public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) @@ -1780,11 +1819,12 @@ public final class BluetoothAdapter { * closed, or if this application closes unexpectedly. *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to * connect to this socket from another device using the same {@link UUID}. + * * @param name service name for SDP record * @param uuid uuid for SDP record * @return a listening RFCOMM BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or - * insufficient permissions, or channel in use. + * @throws IOException on error, for example Bluetooth not available, or insufficient + * permissions, or channel in use. */ @RequiresPermission(Manifest.permission.BLUETOOTH) public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid) @@ -1792,7 +1832,7 @@ public final class BluetoothAdapter { return createNewRfcommSocketAndRecord(name, uuid, false, false); } - /** + /** * Create a listening, encrypted, * RFCOMM Bluetooth socket with Service Record. *

The link will be encrypted, but the link key is not required to be authenticated @@ -1818,11 +1858,12 @@ public final class BluetoothAdapter { *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to * connect to this socket from another device using the same {@link UUID}. *

Requires {@link android.Manifest.permission#BLUETOOTH} + * * @param name service name for SDP record * @param uuid uuid for SDP record * @return a listening RFCOMM BluetoothServerSocket - * @throws IOException on error, for example Bluetooth not available, or - * insufficient permissions, or channel in use. + * @throws IOException on error, for example Bluetooth not available, or insufficient + * permissions, or channel in use. * @hide */ public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord( @@ -1835,7 +1876,7 @@ public final class BluetoothAdapter { boolean auth, boolean encrypt) throws IOException { BluetoothServerSocket socket; socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, - encrypt, new ParcelUuid(uuid)); + encrypt, new ParcelUuid(uuid)); socket.setServiceName(name); int errno = socket.mSocket.bindListen(); if (errno != 0) { @@ -1850,16 +1891,17 @@ public final class BluetoothAdapter { /** * Construct an unencrypted, unauthenticated, RFCOMM server socket. * Call #accept to retrieve connections to this socket. + * * @return An RFCOMM BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or - * insufficient permissions. + * @throws IOException On error, for example Bluetooth not available, or insufficient + * permissions. * @hide */ public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, false, false, port); int errno = socket.mSocket.bindListen(); - if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); } if (errno != 0) { @@ -1871,12 +1913,13 @@ public final class BluetoothAdapter { return socket; } - /** + /** * Construct an encrypted, RFCOMM server socket. * Call #accept to retrieve connections to this socket. + * * @return An RFCOMM BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or - * insufficient permissions. + * @throws IOException On error, for example Bluetooth not available, or insufficient + * permissions. * @hide */ public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) @@ -1884,7 +1927,7 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_RFCOMM, false, true, port); int errno = socket.mSocket.bindListen(); - if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); } if (errno < 0) { @@ -1899,9 +1942,10 @@ public final class BluetoothAdapter { /** * Construct a SCO server socket. * Call #accept to retrieve connections to this socket. + * * @return A SCO BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or - * insufficient permissions. + * @throws IOException On error, for example Bluetooth not available, or insufficient + * permissions. * @hide */ public static BluetoothServerSocket listenUsingScoOn() throws IOException { @@ -1921,12 +1965,14 @@ public final class BluetoothAdapter { * Call #accept to retrieve connections to this socket. *

To auto assign a port without creating a SDP record use * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. - * @param port the PSM to listen on - * @param mitm enforce man-in-the-middle protection for authentication. - * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 connections. + * + * @param port the PSM to listen on + * @param mitm enforce man-in-the-middle protection for authentication. + * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 + * connections. * @return An L2CAP BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or - * insufficient permissions. + * @throws IOException On error, for example Bluetooth not available, or insufficient + * permissions. * @hide */ public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin) @@ -1934,7 +1980,7 @@ public final class BluetoothAdapter { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, min16DigitPin); int errno = socket.mSocket.bindListen(); - if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); } if (errno != 0) { @@ -1951,10 +1997,11 @@ public final class BluetoothAdapter { * Call #accept to retrieve connections to this socket. *

To auto assign a port without creating a SDP record use * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. - * @param port the PSM to listen on + * + * @param port the PSM to listen on * @return An L2CAP BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or - * insufficient permissions. + * @throws IOException On error, for example Bluetooth not available, or insufficient + * permissions. * @hide */ public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { @@ -1967,17 +2014,18 @@ public final class BluetoothAdapter { * Call #accept to retrieve connections to this socket. *

To auto assign a port without creating a SDP record use * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. - * @param port the PSM to listen on + * + * @param port the PSM to listen on * @return An L2CAP BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or - * insufficient permissions. + * @throws IOException On error, for example Bluetooth not available, or insufficient + * permissions. * @hide */ public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket( BluetoothSocket.TYPE_L2CAP, false, false, port, false, false); int errno = socket.mSocket.bindListen(); - if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { + if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); } if (errno != 0) { @@ -1995,7 +2043,6 @@ public final class BluetoothAdapter { *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @return Pair of Hash and Randomizer - * * @hide */ public Pair readOutOfBandData() { @@ -2013,13 +2060,13 @@ public final class BluetoothAdapter { * * @param context Context of the application * @param listener The service Listener for connection callbacks. - * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH}, - * {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. - * {@link BluetoothProfile#GATT} or {@link BluetoothProfile#GATT_SERVER}. + * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH}, {@link + * BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. {@link BluetoothProfile#GATT} or + * {@link BluetoothProfile#GATT_SERVER}. * @return true on success, false on error */ public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, - int profile) { + int profile) { if (context == null || listener == null) return false; if (profile == BluetoothProfile.HEADSET) { @@ -2082,59 +2129,59 @@ public final class BluetoothAdapter { switch (profile) { case BluetoothProfile.HEADSET: - BluetoothHeadset headset = (BluetoothHeadset)proxy; + BluetoothHeadset headset = (BluetoothHeadset) proxy; headset.close(); break; case BluetoothProfile.A2DP: - BluetoothA2dp a2dp = (BluetoothA2dp)proxy; + BluetoothA2dp a2dp = (BluetoothA2dp) proxy; a2dp.close(); break; case BluetoothProfile.A2DP_SINK: - BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink)proxy; + BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink) proxy; a2dpSink.close(); break; case BluetoothProfile.AVRCP_CONTROLLER: - BluetoothAvrcpController avrcp = (BluetoothAvrcpController)proxy; + BluetoothAvrcpController avrcp = (BluetoothAvrcpController) proxy; avrcp.close(); break; case BluetoothProfile.INPUT_DEVICE: - BluetoothInputDevice iDev = (BluetoothInputDevice)proxy; + BluetoothInputDevice iDev = (BluetoothInputDevice) proxy; iDev.close(); break; case BluetoothProfile.PAN: - BluetoothPan pan = (BluetoothPan)proxy; + BluetoothPan pan = (BluetoothPan) proxy; pan.close(); break; case BluetoothProfile.HEALTH: - BluetoothHealth health = (BluetoothHealth)proxy; + BluetoothHealth health = (BluetoothHealth) proxy; health.close(); break; - case BluetoothProfile.GATT: - BluetoothGatt gatt = (BluetoothGatt)proxy; + case BluetoothProfile.GATT: + BluetoothGatt gatt = (BluetoothGatt) proxy; gatt.close(); break; case BluetoothProfile.GATT_SERVER: - BluetoothGattServer gattServer = (BluetoothGattServer)proxy; + BluetoothGattServer gattServer = (BluetoothGattServer) proxy; gattServer.close(); break; case BluetoothProfile.MAP: - BluetoothMap map = (BluetoothMap)proxy; + BluetoothMap map = (BluetoothMap) proxy; map.close(); break; case BluetoothProfile.HEADSET_CLIENT: - BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy; + BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient) proxy; headsetClient.close(); break; case BluetoothProfile.SAP: - BluetoothSap sap = (BluetoothSap)proxy; + BluetoothSap sap = (BluetoothSap) proxy; sap.close(); break; case BluetoothProfile.PBAP_CLIENT: - BluetoothPbapClient pbapClient = (BluetoothPbapClient)proxy; + BluetoothPbapClient pbapClient = (BluetoothPbapClient) proxy; pbapClient.close(); break; case BluetoothProfile.MAP_CLIENT: - BluetoothMapClient mapClient = (BluetoothMapClient)proxy; + BluetoothMapClient mapClient = (BluetoothMapClient) proxy; mapClient.close(); break; case BluetoothProfile.INPUT_HOST: @@ -2145,75 +2192,78 @@ public final class BluetoothAdapter { } final private IBluetoothManagerCallback mManagerCallback = - new IBluetoothManagerCallback.Stub() { - public void onBluetoothServiceUp(IBluetooth bluetoothService) { - if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); - - mServiceLock.writeLock().lock(); - mService = bluetoothService; - mServiceLock.writeLock().unlock(); - - synchronized (mProxyServiceStateCallbacks) { - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ) { - try { - if (cb != null) { - cb.onBluetoothServiceUp(bluetoothService); - } else { - Log.d(TAG, "onBluetoothServiceUp: cb is null!"); + new IBluetoothManagerCallback.Stub() { + public void onBluetoothServiceUp(IBluetooth bluetoothService) { + if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); + + mServiceLock.writeLock().lock(); + mService = bluetoothService; + mServiceLock.writeLock().unlock(); + + synchronized (mProxyServiceStateCallbacks) { + for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) { + try { + if (cb != null) { + cb.onBluetoothServiceUp(bluetoothService); + } else { + Log.d(TAG, "onBluetoothServiceUp: cb is null!"); + } + } catch (Exception e) { + Log.e(TAG, "", e); } - } catch (Exception e) { - Log.e(TAG,"",e); } } } - } - - public void onBluetoothServiceDown() { - if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); - try { - mServiceLock.writeLock().lock(); - mService = null; - if (mLeScanClients != null) mLeScanClients.clear(); - if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); - if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); - } finally { - mServiceLock.writeLock().unlock(); - } + public void onBluetoothServiceDown() { + if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); + + try { + mServiceLock.writeLock().lock(); + mService = null; + if (mLeScanClients != null) mLeScanClients.clear(); + if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); + if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); + } finally { + mServiceLock.writeLock().unlock(); + } - synchronized (mProxyServiceStateCallbacks) { - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ - try { - if (cb != null) { - cb.onBluetoothServiceDown(); - } else { - Log.d(TAG, "onBluetoothServiceDown: cb is null!"); + synchronized (mProxyServiceStateCallbacks) { + for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) { + try { + if (cb != null) { + cb.onBluetoothServiceDown(); + } else { + Log.d(TAG, "onBluetoothServiceDown: cb is null!"); + } + } catch (Exception e) { + Log.e(TAG, "", e); } - } catch (Exception e) { - Log.e(TAG,"",e); } } } - } - public void onBrEdrDown() { - if (VDBG) Log.i(TAG, "onBrEdrDown: " + mService); - } - }; + public void onBrEdrDown() { + if (VDBG) Log.i(TAG, "onBrEdrDown: " + mService); + } + }; /** * Enable the Bluetooth Adapter, but don't auto-connect devices * and don't persist state. Only for use by system applications. + * * @hide */ public boolean enableNoAutoConnect() { - if (isEnabled() == true){ + if (isEnabled() == true) { if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT already enabled!"); return true; } try { return mManagerService.enableNoAutoConnect(ActivityThread.currentPackageName()); - } catch (RemoteException e) {Log.e(TAG, "", e);} + } catch (RemoteException e) { + Log.e(TAG, "", e); + } return false; } @@ -2247,7 +2297,7 @@ public final class BluetoothAdapter { * @hide */ public boolean changeApplicationBluetoothState(boolean on, - BluetoothStateChangeCallback callback) { + BluetoothStateChangeCallback callback) { return false; } @@ -2305,28 +2355,29 @@ public final class BluetoothAdapter { for (int i = 0; i < ADDRESS_LENGTH; i++) { char c = address.charAt(i); switch (i % 3) { - case 0: - case 1: - if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { - // hex character, OK - break; - } - return false; - case 2: - if (c == ':') { - break; // OK - } - return false; + case 0: + case 1: + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { + // hex character, OK + break; + } + return false; + case 2: + if (c == ':') { + break; // OK + } + return false; } } return true; } /*package*/ IBluetoothManager getBluetoothManager() { - return mManagerService; + return mManagerService; } - final private ArrayList mProxyServiceStateCallbacks = new ArrayList(); + final private ArrayList mProxyServiceStateCallbacks = + new ArrayList(); /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { synchronized (mProxyServiceStateCallbacks) { @@ -2357,10 +2408,9 @@ public final class BluetoothAdapter { * by the {@link BluetoothAdapter#startLeScan} function. * * @param device Identifies the remote device - * @param rssi The RSSI value for the remote device as reported by the - * Bluetooth hardware. 0 if no RSSI value is available. - * @param scanRecord The content of the advertisement record offered by - * the remote device. + * @param rssi The RSSI value for the remote device as reported by the Bluetooth hardware. 0 + * if no RSSI value is available. + * @param scanRecord The content of the advertisement record offered by the remote device. */ public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); } @@ -2374,7 +2424,7 @@ public final class BluetoothAdapter { * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)} - * instead. + * instead. */ @Deprecated @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) @@ -2393,7 +2443,7 @@ public final class BluetoothAdapter { * @param callback the callback LE scan results are delivered * @return true, if the scan was started successfully * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)} - * instead. + * instead. */ @Deprecated @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) @@ -2409,7 +2459,7 @@ public final class BluetoothAdapter { return false; } - synchronized(mLeScanClients) { + synchronized (mLeScanClients) { if (mLeScanClients.containsKey(callback)) { if (DBG) Log.e(TAG, "LE Scan has already started"); return false; @@ -2450,8 +2500,8 @@ public final class BluetoothAdapter { } }; ScanSettings settings = new ScanSettings.Builder() - .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) - .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); + .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); List filters = new ArrayList(); if (serviceUuids != null && serviceUuids.length > 0) { @@ -2467,7 +2517,7 @@ public final class BluetoothAdapter { return true; } catch (RemoteException e) { - Log.e(TAG,"",e); + Log.e(TAG, "", e); } } return false; @@ -2476,8 +2526,8 @@ public final class BluetoothAdapter { /** * Stops an ongoing Bluetooth LE device scan. * - * @param callback used to identify which scan to stop - * must be the same handle used to start the scan + * @param callback used to identify which scan to stop must be the same handle used to start the + * scan * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead. */ @Deprecated -- cgit v1.2.3 From 9e045d26d0128826b40520f523307d8d16473779 Mon Sep 17 00:00:00 2001 From: Jack He Date: Tue, 22 Aug 2017 21:21:23 -0700 Subject: Fix checkstyle errors (2/2) * Manual style corrections with IDE assistance * Variable name refactors are done through IDE * Corrected general style errors such as: - "final private var" -> "private final var" - "&&", "+", "||" should not be at the end of line - Non-static private variable should be like "mVar" - Private static variable should be like "sVar" - Code file should always end with newline - Inherited methods should be annotated with @Override and no @hide tags - Public methods should always have a JavaDoc entry - "int[] array" is preferred over "int array[]" - private methods should be accessed without "this." when there is no name collisions. - "boolean ? true : false" -> boolean - "boolean ? false : true" -> !boolean - "boolean == true" OR "boolean != false" -> boolean - "boolean != true" OR "boolean == false" -> !boolean Bug: 63596319 Test: make checkbuild, no functional changes Change-Id: Iabdc2be912a32dd63a53213d175cf1bfef268ccd --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 1b9ce88de0..70591d4d05 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2191,7 +2191,7 @@ public final class BluetoothAdapter { } } - final private IBluetoothManagerCallback mManagerCallback = + private final IBluetoothManagerCallback mManagerCallback = new IBluetoothManagerCallback.Stub() { public void onBluetoothServiceUp(IBluetooth bluetoothService) { if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); @@ -2255,7 +2255,7 @@ public final class BluetoothAdapter { * @hide */ public boolean enableNoAutoConnect() { - if (isEnabled() == true) { + if (isEnabled()) { if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT already enabled!"); return true; } @@ -2376,7 +2376,7 @@ public final class BluetoothAdapter { return mManagerService; } - final private ArrayList mProxyServiceStateCallbacks = + private final ArrayList mProxyServiceStateCallbacks = new ArrayList(); /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { -- cgit v1.2.3 From 4729ea80cf268eb82091fe8f6c4a2071ca33606e Mon Sep 17 00:00:00 2001 From: Pulkit Bhuwalka Date: Wed, 16 Aug 2017 21:52:04 -0700 Subject: Modify Bluetooth Class of Device from Android stack Bug: 36015415 Test: Modified Class of Device using sample app and verified device icon change when discovering from a remote device. Change-Id: Ie25f10be5560f9c090ebe489d5f3bb00cbca81ef --- .../java/android/bluetooth/BluetoothAdapter.java | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 70591d4d05..84765f6d72 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1133,6 +1133,29 @@ public final class BluetoothAdapter { return false; } + /** + * Sets the {@link BluetoothClass} Bluetooth Class of Device (CoD) of + * the local Bluetooth adapter. + * + * @param bluetoothClass {@link BluetoothClass} to set the local Bluetooth adapter to. + * @return true if successful, false if unsuccessful. + * + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean setBluetoothClass(BluetoothClass bluetoothClass) { + if (getState() != STATE_ON) return false; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.setBluetoothClass(bluetoothClass); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; + } + /** * Get the current Bluetooth scan mode of the local Bluetooth adapter. *

The Bluetooth scan mode determines if the local adapter is -- cgit v1.2.3 From d9bf8fb5edc93a9f8154943af8ac36e9447df9ca Mon Sep 17 00:00:00 2001 From: Selim Gurun Date: Tue, 17 Oct 2017 17:01:38 -0700 Subject: Add SystemApis annotations There are some number of places where bluetooth APIs are used via reflection from GMSCore. Add proper annotations. Bug: 67052734 Test: Manual - and using make update-api Change-Id: Ib6e3aa1ff5b6f9cdc78367f9be13ed00542d6f65 --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 84765f6d72..3526e18966 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2277,6 +2277,8 @@ public final class BluetoothAdapter { * * @hide */ + @SystemApi + @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect() { if (isEnabled()) { if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT already enabled!"); -- cgit v1.2.3 From dba34c5da02e483e3e98c9a202497d060f463cf0 Mon Sep 17 00:00:00 2001 From: Pulkit Bhuwalka Date: Mon, 25 Sep 2017 17:55:12 -0700 Subject: Persist Bluetooth CoD config value across reboot Create new Settings key for storage and update the API doc. Bug: 36015415 Test: Verified by storing a value through a test app and restarting the machine to ensure it's picked up. Change-Id: I94aa054e525c4656bb3a824a29cae9c88f8904e0 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 84765f6d72..5c26232726 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1134,8 +1134,10 @@ public final class BluetoothAdapter { } /** - * Sets the {@link BluetoothClass} Bluetooth Class of Device (CoD) of - * the local Bluetooth adapter. + * Sets the {@link BluetoothClass} Bluetooth Class of Device (CoD) of the local Bluetooth + * adapter. + * + *

Note: This value persists across system reboot. * * @param bluetoothClass {@link BluetoothClass} to set the local Bluetooth adapter to. * @return true if successful, false if unsuccessful. -- cgit v1.2.3 From 9279eda246a7843cef6d4c0b49685bb781da4fd6 Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Fri, 20 Oct 2017 15:55:59 -0700 Subject: Change Bluetooth HID Profile Name (1/11) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the Bluetooth HID profile name consistent with the Bluetooth HID service name. BluetoothInputHost → BluetoothHidDevice BluetoothInputDevice → BluetoothHidHost IBluetoothInputHost → IBluetoothHidDevice IBluetoothInputDevice → IBluetoothHidHost BluetoothProfile.INPUT_HOST → BluetoothProfile.HID_DEVICE BluetoothProfile.INPUT_DEVICE → BluetoothProfile.HID_HOST Bug: 68055651 Test: make Change-Id: Iadb890a54dd3d6868b87514472bbac6bb0c6179f --- framework/java/android/bluetooth/BluetoothAdapter.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3526e18966..c450f8aab0 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2104,8 +2104,8 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) { BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener); return true; - } else if (profile == BluetoothProfile.INPUT_DEVICE) { - BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener); + } else if (profile == BluetoothProfile.HID_HOST) { + BluetoothHidHost iDev = new BluetoothHidHost(context, listener); return true; } else if (profile == BluetoothProfile.PAN) { BluetoothPan pan = new BluetoothPan(context, listener); @@ -2128,8 +2128,8 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.MAP_CLIENT) { BluetoothMapClient mapClient = new BluetoothMapClient(context, listener); return true; - } else if (profile == BluetoothProfile.INPUT_HOST) { - BluetoothInputHost iHost = new BluetoothInputHost(context, listener); + } else if (profile == BluetoothProfile.HID_DEVICE) { + BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener); return true; } else { return false; @@ -2167,8 +2167,8 @@ public final class BluetoothAdapter { BluetoothAvrcpController avrcp = (BluetoothAvrcpController) proxy; avrcp.close(); break; - case BluetoothProfile.INPUT_DEVICE: - BluetoothInputDevice iDev = (BluetoothInputDevice) proxy; + case BluetoothProfile.HID_HOST: + BluetoothHidHost iDev = (BluetoothHidHost) proxy; iDev.close(); break; case BluetoothProfile.PAN: @@ -2207,9 +2207,9 @@ public final class BluetoothAdapter { BluetoothMapClient mapClient = (BluetoothMapClient) proxy; mapClient.close(); break; - case BluetoothProfile.INPUT_HOST: - BluetoothInputHost iHost = (BluetoothInputHost) proxy; - iHost.close(); + case BluetoothProfile.HID_DEVICE: + BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy; + hidDevice.close(); break; } } -- cgit v1.2.3 From f0761580c81033f1004f31a7844ff86741134dea Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Fri, 20 Oct 2017 15:55:59 -0700 Subject: Change Bluetooth HID Profile Name (1/6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the Bluetooth HID profile name consistent with the Bluetooth HID service name. BluetoothInputHost → BluetoothHidDevice BluetoothInputDevice → BluetoothHidHost IBluetoothInputHost → IBluetoothHidDevice IBluetoothInputDevice → IBluetoothHidHost BluetoothProfile.INPUT_HOST → BluetoothProfile.HID_DEVICE BluetoothProfile.INPUT_DEVICE → BluetoothProfile.HID_HOST (Cherry-picked from commit c26c76c63d933f8057f795d05624f91b811c8c71) Merged-In: Iadb890a54dd3d6868b87514472bbac6bb0c6179f Bug: 68055651 Test: make Change-Id: Iadb890a54dd3d6868b87514472bbac6bb0c6179f --- framework/java/android/bluetooth/BluetoothAdapter.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 84765f6d72..17ae9078ef 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2104,8 +2104,8 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) { BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener); return true; - } else if (profile == BluetoothProfile.INPUT_DEVICE) { - BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener); + } else if (profile == BluetoothProfile.HID_HOST) { + BluetoothHidHost iDev = new BluetoothHidHost(context, listener); return true; } else if (profile == BluetoothProfile.PAN) { BluetoothPan pan = new BluetoothPan(context, listener); @@ -2128,8 +2128,8 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.MAP_CLIENT) { BluetoothMapClient mapClient = new BluetoothMapClient(context, listener); return true; - } else if (profile == BluetoothProfile.INPUT_HOST) { - BluetoothInputHost iHost = new BluetoothInputHost(context, listener); + } else if (profile == BluetoothProfile.HID_DEVICE) { + BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener); return true; } else { return false; @@ -2167,8 +2167,8 @@ public final class BluetoothAdapter { BluetoothAvrcpController avrcp = (BluetoothAvrcpController) proxy; avrcp.close(); break; - case BluetoothProfile.INPUT_DEVICE: - BluetoothInputDevice iDev = (BluetoothInputDevice) proxy; + case BluetoothProfile.HID_HOST: + BluetoothHidHost iDev = (BluetoothHidHost) proxy; iDev.close(); break; case BluetoothProfile.PAN: @@ -2207,9 +2207,9 @@ public final class BluetoothAdapter { BluetoothMapClient mapClient = (BluetoothMapClient) proxy; mapClient.close(); break; - case BluetoothProfile.INPUT_HOST: - BluetoothInputHost iHost = (BluetoothInputHost) proxy; - iHost.close(); + case BluetoothProfile.HID_DEVICE: + BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy; + hidDevice.close(); break; } } -- cgit v1.2.3 From 02e360e17e9cf32afbbe7fe3257f45d186136808 Mon Sep 17 00:00:00 2001 From: Pulkit Bhuwalka Date: Wed, 20 Sep 2017 15:10:45 -0700 Subject: Get Bluetooth Class of Device Adds API to fetch Bluetooth CoD value of the stack. The API is hidden to only be used by System code. Bug: 36015415 Test: Verified fetching of COD from test app on flashed device, after modification and after after reboot. Change-Id: Ie35ecf141704c2aac46678da7cabdc7203a088f2 --- .../java/android/bluetooth/BluetoothAdapter.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 01af9fe31d..3d9651db68 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1133,6 +1133,28 @@ public final class BluetoothAdapter { return false; } + /** + * Returns the {@link BluetoothClass} Bluetooth Class of Device (CoD) of the local Bluetooth + * adapter. + * + * @return {@link BluetoothClass} Bluetooth CoD of local Bluetooth device. + * + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public BluetoothClass getBluetoothClass() { + if (getState() != STATE_ON) return null; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.getBluetoothClass(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + return null; + } + /** * Sets the {@link BluetoothClass} Bluetooth Class of Device (CoD) of the local Bluetooth * adapter. -- cgit v1.2.3 From 57dda24cac3ce88b63eea6a505f37ace674bd7c6 Mon Sep 17 00:00:00 2001 From: Myles Watson Date: Mon, 27 Nov 2017 16:41:47 -0800 Subject: Auto-format BluetoothAdapter.java Test: build Change-Id: I7bfc729373a24cceee05e443195640ff7f6d43b9 --- .../java/android/bluetooth/BluetoothAdapter.java | 460 ++++++++++++++------- 1 file changed, 302 insertions(+), 158 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3d9651db68..158aebb478 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1,6 +1,6 @@ /* - * Copyright (C) 2009-2016 The Android Open Source Project - * Copyright (C) 2015 Samsung LSI + * Copyright 2009-2016 The Android Open Source Project + * Copyright 2015 Samsung LSI * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -132,9 +132,8 @@ public final class BluetoothAdapter { * respectively. *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_STATE_CHANGED = - "android.bluetooth.adapter.action.STATE_CHANGED"; + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED"; /** * Used as an int extra field in {@link #ACTION_STATE_CHANGED} @@ -144,8 +143,7 @@ public final class BluetoothAdapter { * {@link #STATE_ON}, * {@link #STATE_TURNING_OFF}, */ - public static final String EXTRA_STATE = - "android.bluetooth.adapter.extra.STATE"; + public static final String EXTRA_STATE = "android.bluetooth.adapter.extra.STATE"; /** * Used as an int extra field in {@link #ACTION_STATE_CHANGED} * intents to request the previous power state. Possible values are: @@ -158,11 +156,17 @@ public final class BluetoothAdapter { "android.bluetooth.adapter.extra.PREVIOUS_STATE"; /** @hide */ - @IntDef({STATE_OFF, STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, STATE_BLE_TURNING_ON, - STATE_BLE_ON, STATE_BLE_TURNING_OFF}) + @IntDef({ + STATE_OFF, + STATE_TURNING_ON, + STATE_ON, + STATE_TURNING_OFF, + STATE_BLE_TURNING_ON, + STATE_BLE_ON, + STATE_BLE_TURNING_OFF + }) @Retention(RetentionPolicy.SOURCE) - public @interface AdapterState { - } + public @interface AdapterState {} /** * Indicates the local Bluetooth adapter is off. @@ -254,9 +258,8 @@ public final class BluetoothAdapter { * application can be notified when the device has ended discoverability. *

Requires {@link android.Manifest.permission#BLUETOOTH} */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_REQUEST_DISCOVERABLE = - "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"; + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String + ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"; /** * Used as an optional int extra field in {@link @@ -282,9 +285,8 @@ public final class BluetoothAdapter { * for global notification whenever Bluetooth is turned on or off. *

Requires {@link android.Manifest.permission#BLUETOOTH} */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_REQUEST_ENABLE = - "android.bluetooth.adapter.action.REQUEST_ENABLE"; + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String + ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"; /** * Activity Action: Show a system activity that allows the user to turn off @@ -305,9 +307,8 @@ public final class BluetoothAdapter { * * @hide */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_REQUEST_DISABLE = - "android.bluetooth.adapter.action.REQUEST_DISABLE"; + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String + ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE"; /** * Activity Action: Show a system activity that allows user to enable BLE scans even when @@ -334,9 +335,8 @@ public final class BluetoothAdapter { * respectively. *

Requires {@link android.Manifest.permission#BLUETOOTH} */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_SCAN_MODE_CHANGED = - "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; /** * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} @@ -359,8 +359,7 @@ public final class BluetoothAdapter { /** @hide */ @IntDef({SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE}) @Retention(RetentionPolicy.SOURCE) - public @interface ScanMode { - } + public @interface ScanMode {} /** * Indicates that both inquiry scan and page scan are disabled on the local @@ -396,17 +395,15 @@ public final class BluetoothAdapter { * discovery. *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_DISCOVERY_STARTED = - "android.bluetooth.adapter.action.DISCOVERY_STARTED"; + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED"; /** * Broadcast Action: The local Bluetooth adapter has finished the device * discovery process. *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_DISCOVERY_FINISHED = - "android.bluetooth.adapter.action.DISCOVERY_FINISHED"; + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED"; /** * Broadcast Action: The local Bluetooth adapter has changed its friendly @@ -416,9 +413,8 @@ public final class BluetoothAdapter { * the name. *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_LOCAL_NAME_CHANGED = - "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED"; + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED"; /** * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED} * intents to request the local Bluetooth name. @@ -451,8 +447,8 @@ public final class BluetoothAdapter { * *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_CONNECTION_STATE_CHANGED = + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String + ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"; /** @@ -476,8 +472,7 @@ public final class BluetoothAdapter { * * @hide */ - @SystemApi - public static final String ACTION_BLE_STATE_CHANGED = + @SystemApi public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; /** @@ -574,8 +569,7 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; private IBluetooth mService; - private final ReentrantReadWriteLock mServiceLock = - new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); private final Object mLock = new Object(); private final Map mLeScanClients; @@ -655,8 +649,9 @@ public final class BluetoothAdapter { if (address == null || address.length != 6) { throw new IllegalArgumentException("Bluetooth address must have 6 bytes"); } - return new BluetoothDevice(String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", - address[0], address[1], address[2], address[3], address[4], address[5])); + return new BluetoothDevice( + String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1], + address[2], address[3], address[4], address[5])); } /** @@ -668,7 +663,9 @@ public final class BluetoothAdapter { * on this device before calling this method. */ public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { - if (!getLeAccess()) return null; + if (!getLeAccess()) { + return null; + } synchronized (mLock) { if (sBluetoothLeAdvertiser == null) { sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); @@ -698,8 +695,7 @@ public final class BluetoothAdapter { synchronized (mLock) { if (sPeriodicAdvertisingManager == null) { - sPeriodicAdvertisingManager = - new PeriodicAdvertisingManager(mManagerService); + sPeriodicAdvertisingManager = new PeriodicAdvertisingManager(mManagerService); } } return sPeriodicAdvertisingManager; @@ -709,7 +705,9 @@ public final class BluetoothAdapter { * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. */ public BluetoothLeScanner getBluetoothLeScanner() { - if (!getLeAccess()) return null; + if (!getLeAccess()) { + return null; + } synchronized (mLock) { if (sBluetoothLeScanner == null) { sBluetoothLeScanner = new BluetoothLeScanner(mManagerService); @@ -729,7 +727,9 @@ public final class BluetoothAdapter { public boolean isEnabled() { try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isEnabled(); + if (mService != null) { + return mService.isEnabled(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -750,7 +750,9 @@ public final class BluetoothAdapter { @SystemApi public boolean isLeEnabled() { final int state = getLeState(); - if (DBG) Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state)); + if (DBG) { + Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state)); + } return (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON); } @@ -781,12 +783,16 @@ public final class BluetoothAdapter { */ @SystemApi public boolean disableBLE() { - if (!isBleScanAlwaysAvailable()) return false; + if (!isBleScanAlwaysAvailable()) { + return false; + } int state = getLeState(); if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) { String packageName = ActivityThread.currentPackageName(); - if (DBG) Log.d(TAG, "disableBLE(): de-registering " + packageName); + if (DBG) { + Log.d(TAG, "disableBLE(): de-registering " + packageName); + } try { mManagerService.updateBleAppCount(mToken, false, packageName); } catch (RemoteException e) { @@ -795,7 +801,9 @@ public final class BluetoothAdapter { return true; } - if (DBG) Log.d(TAG, "disableBLE(): Already disabled"); + if (DBG) { + Log.d(TAG, "disableBLE(): Already disabled"); + } return false; } @@ -832,16 +840,22 @@ public final class BluetoothAdapter { */ @SystemApi public boolean enableBLE() { - if (!isBleScanAlwaysAvailable()) return false; + if (!isBleScanAlwaysAvailable()) { + return false; + } try { String packageName = ActivityThread.currentPackageName(); mManagerService.updateBleAppCount(mToken, true, packageName); if (isLeEnabled()) { - if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled"); + if (DBG) { + Log.d(TAG, "enableBLE(): Bluetooth already enabled"); + } return true; } - if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); + if (DBG) { + Log.d(TAG, "enableBLE(): Calling enable"); + } return mManagerService.enable(packageName); } catch (RemoteException e) { Log.e(TAG, "", e); @@ -877,19 +891,16 @@ public final class BluetoothAdapter { } // Consider all internal states as OFF - if (state == BluetoothAdapter.STATE_BLE_ON - || state == BluetoothAdapter.STATE_BLE_TURNING_ON + if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { if (VDBG) { - Log.d(TAG, - "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF"); + Log.d(TAG, "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF"); } state = BluetoothAdapter.STATE_OFF; } if (VDBG) { - Log.d(TAG, - "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState( - state)); + Log.d(TAG, "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState( + state)); } return state; } @@ -926,7 +937,9 @@ public final class BluetoothAdapter { mServiceLock.readLock().unlock(); } - if (VDBG) Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state)); + if (VDBG) { + Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state)); + } return state; } @@ -967,7 +980,9 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean enable() { if (isEnabled()) { - if (DBG) Log.d(TAG, "enable(): BT already enabled!"); + if (DBG) { + Log.d(TAG, "enable(): BT already enabled!"); + } return true; } try { @@ -1093,10 +1108,14 @@ public final class BluetoothAdapter { * @hide */ public ParcelUuid[] getUuids() { - if (getState() != STATE_ON) return null; + if (getState() != STATE_ON) { + return null; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getUuids(); + if (mService != null) { + return mService.getUuids(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1121,10 +1140,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String name) { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.setName(name); + if (mService != null) { + return mService.setName(name); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1143,10 +1166,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public BluetoothClass getBluetoothClass() { - if (getState() != STATE_ON) return null; + if (getState() != STATE_ON) { + return null; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getBluetoothClass(); + if (mService != null) { + return mService.getBluetoothClass(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1168,10 +1195,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBluetoothClass(BluetoothClass bluetoothClass) { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.setBluetoothClass(bluetoothClass); + if (mService != null) { + return mService.setBluetoothClass(bluetoothClass); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1198,10 +1229,14 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) @ScanMode public int getScanMode() { - if (getState() != STATE_ON) return SCAN_MODE_NONE; + if (getState() != STATE_ON) { + return SCAN_MODE_NONE; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getScanMode(); + if (mService != null) { + return mService.getScanMode(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1239,10 +1274,14 @@ public final class BluetoothAdapter { * @hide */ public boolean setScanMode(@ScanMode int mode, int duration) { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.setScanMode(mode, duration); + if (mService != null) { + return mService.setScanMode(mode, duration); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1253,17 +1292,23 @@ public final class BluetoothAdapter { /** @hide */ public boolean setScanMode(int mode) { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } /* getDiscoverableTimeout() to use the latest from NV than use 0 */ return setScanMode(mode, getDiscoverableTimeout()); } /** @hide */ public int getDiscoverableTimeout() { - if (getState() != STATE_ON) return -1; + if (getState() != STATE_ON) { + return -1; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getDiscoverableTimeout(); + if (mService != null) { + return mService.getDiscoverableTimeout(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1274,10 +1319,14 @@ public final class BluetoothAdapter { /** @hide */ public void setDiscoverableTimeout(int timeout) { - if (getState() != STATE_ON) return; + if (getState() != STATE_ON) { + return; + } try { mServiceLock.readLock().lock(); - if (mService != null) mService.setDiscoverableTimeout(timeout); + if (mService != null) { + mService.setDiscoverableTimeout(timeout); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1296,7 +1345,9 @@ public final class BluetoothAdapter { public long getDiscoveryEndMillis() { try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getDiscoveryEndMillis(); + if (mService != null) { + return mService.getDiscoveryEndMillis(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1336,10 +1387,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean startDiscovery() { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.startDiscovery(); + if (mService != null) { + return mService.startDiscovery(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1366,10 +1421,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelDiscovery() { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.cancelDiscovery(); + if (mService != null) { + return mService.cancelDiscovery(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1398,10 +1457,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isDiscovering() { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isDiscovering(); + if (mService != null) { + return mService.isDiscovering(); + } } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -1416,10 +1479,14 @@ public final class BluetoothAdapter { * @return true if Multiple Advertisement feature is supported */ public boolean isMultipleAdvertisementSupported() { - if (getState() != STATE_ON) return false; + if (getState() != STATE_ON) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isMultiAdvertisementSupported(); + if (mService != null) { + return mService.isMultiAdvertisementSupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e); } finally { @@ -1454,10 +1521,14 @@ public final class BluetoothAdapter { * @return true if chipset supports on-chip filtering */ public boolean isOffloadedFilteringSupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isOffloadedFilteringSupported(); + if (mService != null) { + return mService.isOffloadedFilteringSupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); } finally { @@ -1472,10 +1543,14 @@ public final class BluetoothAdapter { * @return true if chipset supports on-chip scan batching */ public boolean isOffloadedScanBatchingSupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isOffloadedScanBatchingSupported(); + if (mService != null) { + return mService.isOffloadedScanBatchingSupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e); } finally { @@ -1490,10 +1565,14 @@ public final class BluetoothAdapter { * @return true if chipset supports LE 2M PHY feature */ public boolean isLe2MPhySupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isLe2MPhySupported(); + if (mService != null) { + return mService.isLe2MPhySupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isExtendedAdvertisingSupported, error: ", e); } finally { @@ -1508,10 +1587,14 @@ public final class BluetoothAdapter { * @return true if chipset supports LE Coded PHY feature */ public boolean isLeCodedPhySupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isLeCodedPhySupported(); + if (mService != null) { + return mService.isLeCodedPhySupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isLeCodedPhySupported, error: ", e); } finally { @@ -1526,10 +1609,14 @@ public final class BluetoothAdapter { * @return true if chipset supports LE Extended Advertising feature */ public boolean isLeExtendedAdvertisingSupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isLeExtendedAdvertisingSupported(); + if (mService != null) { + return mService.isLeExtendedAdvertisingSupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isLeExtendedAdvertisingSupported, error: ", e); } finally { @@ -1544,10 +1631,14 @@ public final class BluetoothAdapter { * @return true if chipset supports LE Periodic Advertising feature */ public boolean isLePeriodicAdvertisingSupported() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.isLePeriodicAdvertisingSupported(); + if (mService != null) { + return mService.isLePeriodicAdvertisingSupported(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get isLePeriodicAdvertisingSupported, error: ", e); } finally { @@ -1563,10 +1654,14 @@ public final class BluetoothAdapter { * @return the maximum LE advertising data length. */ public int getLeMaximumAdvertisingDataLength() { - if (!getLeAccess()) return 0; + if (!getLeAccess()) { + return 0; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getLeMaximumAdvertisingDataLength(); + if (mService != null) { + return mService.getLeMaximumAdvertisingDataLength(); + } } catch (RemoteException e) { Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e); } finally { @@ -1582,7 +1677,9 @@ public final class BluetoothAdapter { * @hide */ public boolean isHardwareTrackingFiltersAvailable() { - if (!getLeAccess()) return false; + if (!getLeAccess()) { + return false; + } try { IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); if (iGatt == null) { @@ -1669,7 +1766,9 @@ public final class BluetoothAdapter { } try { mServiceLock.readLock().lock(); - if (mService != null) return toDeviceSet(mService.getBondedDevices()); + if (mService != null) { + return toDeviceSet(mService.getBondedDevices()); + } return toDeviceSet(new BluetoothDevice[0]); } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1723,10 +1822,14 @@ public final class BluetoothAdapter { * @hide */ public int getConnectionState() { - if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED; + if (getState() != STATE_ON) { + return BluetoothAdapter.STATE_DISCONNECTED; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getAdapterConnectionState(); + if (mService != null) { + return mService.getAdapterConnectionState(); + } } catch (RemoteException e) { Log.e(TAG, "getConnectionState:", e); } finally { @@ -1750,10 +1853,14 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH) public int getProfileConnectionState(int profile) { - if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED; + if (getState() != STATE_ON) { + return BluetoothProfile.STATE_DISCONNECTED; + } try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getProfileConnectionState(profile); + if (mService != null) { + return mService.getProfileConnectionState(profile); + } } catch (RemoteException e) { Log.e(TAG, "getProfileConnectionState:", e); } finally { @@ -1790,7 +1897,7 @@ public final class BluetoothAdapter { *

Valid RFCOMM channels are in range 1 to 30. *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} *

To auto assign a channel without creating a SDP record use - * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. + * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. * * @param channel RFCOMM channel to listen on * @param mitm enforce man-in-the-middle protection for authentication. @@ -1802,10 +1909,10 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm, - boolean min16DigitPin) - throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm, min16DigitPin); + boolean min16DigitPin) throws IOException { + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm, + min16DigitPin); int errno = socket.mSocket.bindListen(); if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -1913,8 +2020,8 @@ public final class BluetoothAdapter { * permissions, or channel in use. * @hide */ - public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord( - String name, UUID uuid) throws IOException { + public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid) + throws IOException { return createNewRfcommSocketAndRecord(name, uuid, false, true); } @@ -1922,8 +2029,8 @@ public final class BluetoothAdapter { private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt) throws IOException { BluetoothServerSocket socket; - socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, - encrypt, new ParcelUuid(uuid)); + socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, encrypt, + new ParcelUuid(uuid)); socket.setServiceName(name); int errno = socket.mSocket.bindListen(); if (errno != 0) { @@ -1945,8 +2052,8 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, false, false, port); + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, false, port); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -1969,10 +2076,9 @@ public final class BluetoothAdapter { * permissions. * @hide */ - public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) - throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_RFCOMM, false, true, port); + public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) throws IOException { + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, true, port); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -1996,8 +2102,8 @@ public final class BluetoothAdapter { * @hide */ public static BluetoothServerSocket listenUsingScoOn() throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_SCO, false, false, -1); + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_SCO, false, false, -1); int errno = socket.mSocket.bindListen(); if (errno < 0) { //TODO(BT): Throw the same exception error code @@ -2011,7 +2117,7 @@ public final class BluetoothAdapter { * Construct an encrypted, authenticated, L2CAP server socket. * Call #accept to retrieve connections to this socket. *

To auto assign a port without creating a SDP record use - * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. + * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. * * @param port the PSM to listen on * @param mitm enforce man-in-the-middle protection for authentication. @@ -2024,8 +2130,9 @@ public final class BluetoothAdapter { */ public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin) throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, min16DigitPin); + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, + min16DigitPin); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -2043,7 +2150,7 @@ public final class BluetoothAdapter { * Construct an encrypted, authenticated, L2CAP server socket. * Call #accept to retrieve connections to this socket. *

To auto assign a port without creating a SDP record use - * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. + * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. * * @param port the PSM to listen on * @return An L2CAP BluetoothServerSocket @@ -2060,7 +2167,7 @@ public final class BluetoothAdapter { * Construct an insecure L2CAP server socket. * Call #accept to retrieve connections to this socket. *

To auto assign a port without creating a SDP record use - * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. + * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. * * @param port the PSM to listen on * @return An L2CAP BluetoothServerSocket @@ -2069,8 +2176,9 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException { - BluetoothServerSocket socket = new BluetoothServerSocket( - BluetoothSocket.TYPE_L2CAP, false, false, port, false, false); + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, false, false, port, false, + false); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { socket.setChannel(socket.mSocket.getPort()); @@ -2114,7 +2222,9 @@ public final class BluetoothAdapter { */ public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile) { - if (context == null || listener == null) return false; + if (context == null || listener == null) { + return false; + } if (profile == BluetoothProfile.HEADSET) { BluetoothHeadset headset = new BluetoothHeadset(context, listener); @@ -2172,7 +2282,9 @@ public final class BluetoothAdapter { * @param proxy Profile proxy object */ public void closeProfileProxy(int profile, BluetoothProfile proxy) { - if (proxy == null) return; + if (proxy == null) { + return; + } switch (profile) { case BluetoothProfile.HEADSET: @@ -2241,7 +2353,9 @@ public final class BluetoothAdapter { private final IBluetoothManagerCallback mManagerCallback = new IBluetoothManagerCallback.Stub() { public void onBluetoothServiceUp(IBluetooth bluetoothService) { - if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); + if (DBG) { + Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); + } mServiceLock.writeLock().lock(); mService = bluetoothService; @@ -2263,14 +2377,22 @@ public final class BluetoothAdapter { } public void onBluetoothServiceDown() { - if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); + if (DBG) { + Log.d(TAG, "onBluetoothServiceDown: " + mService); + } try { mServiceLock.writeLock().lock(); mService = null; - if (mLeScanClients != null) mLeScanClients.clear(); - if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); - if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); + if (mLeScanClients != null) { + mLeScanClients.clear(); + } + if (sBluetoothLeAdvertiser != null) { + sBluetoothLeAdvertiser.cleanup(); + } + if (sBluetoothLeScanner != null) { + sBluetoothLeScanner.cleanup(); + } } finally { mServiceLock.writeLock().unlock(); } @@ -2291,7 +2413,9 @@ public final class BluetoothAdapter { } public void onBrEdrDown() { - if (VDBG) Log.i(TAG, "onBrEdrDown: " + mService); + if (VDBG) { + Log.i(TAG, "onBrEdrDown: " + mService); + } } }; @@ -2303,7 +2427,9 @@ public final class BluetoothAdapter { */ public boolean enableNoAutoConnect() { if (isEnabled()) { - if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT already enabled!"); + if (DBG) { + Log.d(TAG, "enableNoAutoConnect(): BT already enabled!"); + } return true; } try { @@ -2352,7 +2478,10 @@ public final class BluetoothAdapter { * @hide */ public interface BluetoothStateChangeCallback { - public void onBluetoothStateChange(boolean on); + /** + * @hide + */ + void onBluetoothStateChange(boolean on); } /** @@ -2361,8 +2490,7 @@ public final class BluetoothAdapter { public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub { private BluetoothStateChangeCallback mCallback; - StateChangeCallbackWrapper(BluetoothStateChangeCallback - callback) { + StateChangeCallbackWrapper(BluetoothStateChangeCallback callback) { mCallback = callback; } @@ -2459,7 +2587,7 @@ public final class BluetoothAdapter { * if no RSSI value is available. * @param scanRecord The content of the advertisement record offered by the remote device. */ - public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); + void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); } /** @@ -2495,20 +2623,28 @@ public final class BluetoothAdapter { @Deprecated @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) { - if (DBG) Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids)); + if (DBG) { + Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids)); + } if (callback == null) { - if (DBG) Log.e(TAG, "startLeScan: null callback"); + if (DBG) { + Log.e(TAG, "startLeScan: null callback"); + } return false; } BluetoothLeScanner scanner = getBluetoothLeScanner(); if (scanner == null) { - if (DBG) Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner"); + if (DBG) { + Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner"); + } return false; } synchronized (mLeScanClients) { if (mLeScanClients.containsKey(callback)) { - if (DBG) Log.e(TAG, "LE Scan has already started"); + if (DBG) { + Log.e(TAG, "LE Scan has already started"); + } return false; } @@ -2538,7 +2674,9 @@ public final class BluetoothAdapter { } List scanServiceUuids = scanRecord.getServiceUuids(); if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) { - if (DBG) Log.d(TAG, "uuids does not match"); + if (DBG) { + Log.d(TAG, "uuids does not match"); + } return; } } @@ -2546,16 +2684,18 @@ public final class BluetoothAdapter { scanRecord.getBytes()); } }; - ScanSettings settings = new ScanSettings.Builder() - .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) - .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); + ScanSettings settings = new ScanSettings.Builder().setCallbackType( + ScanSettings.CALLBACK_TYPE_ALL_MATCHES) + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .build(); List filters = new ArrayList(); if (serviceUuids != null && serviceUuids.length > 0) { // Note scan filter does not support matching an UUID array so we put one // UUID to hardware and match the whole array in callback. - ScanFilter filter = new ScanFilter.Builder().setServiceUuid( - new ParcelUuid(serviceUuids[0])).build(); + ScanFilter filter = + new ScanFilter.Builder().setServiceUuid(new ParcelUuid(serviceUuids[0])) + .build(); filters.add(filter); } scanner.startScan(filters, settings, scanCallback); @@ -2580,7 +2720,9 @@ public final class BluetoothAdapter { @Deprecated @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public void stopLeScan(LeScanCallback callback) { - if (DBG) Log.d(TAG, "stopLeScan()"); + if (DBG) { + Log.d(TAG, "stopLeScan()"); + } BluetoothLeScanner scanner = getBluetoothLeScanner(); if (scanner == null) { return; @@ -2588,7 +2730,9 @@ public final class BluetoothAdapter { synchronized (mLeScanClients) { ScanCallback scanCallback = mLeScanClients.remove(callback); if (scanCallback == null) { - if (DBG) Log.d(TAG, "scan not started yet"); + if (DBG) { + Log.d(TAG, "scan not started yet"); + } return; } scanner.stopScan(scanCallback); -- cgit v1.2.3 From e0a0509b6a4e9259dc525a28e46e7433b1adcd87 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 13 Dec 2017 20:05:05 -0700 Subject: Add more IntDef prefixes for auto-documenting. Test: builds, boots Bug: 70177949 Exempt-From-Owner-Approval: annotation-only changes Change-Id: I76dde6054e06f52240bd4b1a0f196dcb74623608 --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index c7be0f36ec..3290d57f13 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -156,7 +156,7 @@ public final class BluetoothAdapter { "android.bluetooth.adapter.extra.PREVIOUS_STATE"; /** @hide */ - @IntDef({ + @IntDef(prefix = { "STATE_" }, value = { STATE_OFF, STATE_TURNING_ON, STATE_ON, @@ -357,7 +357,11 @@ public final class BluetoothAdapter { "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE"; /** @hide */ - @IntDef({SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE}) + @IntDef(prefix = { "SCAN_" }, value = { + SCAN_MODE_NONE, + SCAN_MODE_CONNECTABLE, + SCAN_MODE_CONNECTABLE_DISCOVERABLE + }) @Retention(RetentionPolicy.SOURCE) public @interface ScanMode {} -- cgit v1.2.3 From a117cb378778a5b123fc1be76f887ee6ed5428ec Mon Sep 17 00:00:00 2001 From: Selim Gurun Date: Tue, 17 Oct 2017 17:01:38 -0700 Subject: Add SystemApis annotations There are some number of places where bluetooth APIs are used via reflection from GMSCore. Add proper annotations. Bug: 67052734 Test: Manual - and using make update-api Change-Id: Ib6e3aa1ff5b6f9cdc78367f9be13ed00542d6f65 (cherry picked from commit d9bf8fb5edc93a9f8154943af8ac36e9447df9ca) --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 158aebb478..c7be0f36ec 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2425,6 +2425,8 @@ public final class BluetoothAdapter { * * @hide */ + @SystemApi + @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect() { if (isEnabled()) { if (DBG) { -- cgit v1.2.3 From d67d5e4f1e8c1afd98f11b11ca8ca26792da9d6b Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Wed, 22 Nov 2017 16:04:40 -0800 Subject: Added APIs for Connection-oriented channels Experimental and hidden APIs are defined for the Connection-oriented Channel (CoC) features. The APIs using PSM are implemented. Test: Can compile Bug: 70683224 Change-Id: Icdb5fa190b0e21881a60437fa48cd575371ee1e4 --- .../java/android/bluetooth/BluetoothAdapter.java | 126 ++++++++++++++++++++- 1 file changed, 121 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 158aebb478..4775bde420 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -79,8 +79,9 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * {@link BluetoothDevice} objects representing all paired devices with * {@link #getBondedDevices()}; start device discovery with * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to - * listen for incoming connection requests with - * {@link #listenUsingRfcommWithServiceRecord(String, UUID)}; or start a scan for + * listen for incoming RFComm connection requests with {@link + * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented + * Channels (CoC) connection requests with listenUsingL2capCoc(int)}; or start a scan for * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. *

*

This class is thread safe.

@@ -209,6 +210,14 @@ public final class BluetoothAdapter { */ public static final int STATE_BLE_TURNING_OFF = 16; + /** + * UUID of the GATT Read Characteristics for LE_PSM value. + * + * @hide + */ + public static final UUID LE_PSM_CHARACTERISTIC_UUID = + UUID.fromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a"); + /** * Human-readable string helper for AdapterState * @@ -2135,7 +2144,9 @@ public final class BluetoothAdapter { min16DigitPin); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - socket.setChannel(socket.mSocket.getPort()); + int assignedChannel = socket.mSocket.getPort(); + if (DBG) Log.d(TAG, "listenUsingL2capOn: set assigned channel to " + assignedChannel); + socket.setChannel(assignedChannel); } if (errno != 0) { //TODO(BT): Throw the same exception error code @@ -2176,12 +2187,18 @@ public final class BluetoothAdapter { * @hide */ public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException { + Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port); BluetoothServerSocket socket = new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, false, false, port, false, - false); + false); int errno = socket.mSocket.bindListen(); if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - socket.setChannel(socket.mSocket.getPort()); + int assignedChannel = socket.mSocket.getPort(); + if (DBG) { + Log.d(TAG, "listenUsingInsecureL2capOn: set assigned channel to " + + assignedChannel); + } + socket.setChannel(assignedChannel); } if (errno != 0) { //TODO(BT): Throw the same exception error code @@ -2738,4 +2755,103 @@ public final class BluetoothAdapter { scanner.stopScan(scanCallback); } } + + /** + * Create a secure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and + * assign a dynamic protocol/service multiplexer (PSM) value. This socket can be used to listen + * for incoming connections. + *

A remote device connecting to this socket will be authenticated and communication on this + * socket will be encrypted. + *

Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening + * {@link BluetoothServerSocket}. + *

The system will assign a dynamic PSM value. This PSM value can be read from the {#link + * BluetoothServerSocket#getPsm()} and this value will be released when this server socket is + * closed, Bluetooth is turned off, or the application exits unexpectedly. + *

The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is + * defined and performed by the application. + *

Use {@link BluetoothDevice#createL2capCocSocket(int, int)} to connect to this server + * socket from another Android device that is given the PSM value. + * + * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE} + * @return an L2CAP CoC BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or insufficient + * permissions, or unable to start this CoC + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public BluetoothServerSocket listenUsingL2capCoc(int transport) + throws IOException { + if (transport != BluetoothDevice.TRANSPORT_LE) { + throw new IllegalArgumentException("Unsupported transport: " + transport); + } + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true, + SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false); + int errno = socket.mSocket.bindListen(); + if (errno != 0) { + throw new IOException("Error: " + errno); + } + + int assignedPsm = socket.mSocket.getPort(); + if (assignedPsm == 0) { + throw new IOException("Error: Unable to assign PSM value"); + } + if (DBG) { + Log.d(TAG, "listenUsingL2capCoc: set assigned PSM to " + + assignedPsm); + } + socket.setChannel(assignedPsm); + + return socket; + } + + /** + * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and + * assign a dynamic PSM value. This socket can be used to listen for incoming connections. + *

The link key is not required to be authenticated, i.e the communication may be vulnerable + * to man-in-the-middle attacks. Use {@link #listenUsingL2capCoc}, if an encrypted and + * authenticated communication channel is desired. + *

Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening + * {@link BluetoothServerSocket}. + *

The system will assign a dynamic protocol/service multiplexer (PSM) value. This PSM value + * can be read from the {#link BluetoothServerSocket#getPsm()} and this value will be released + * when this server socket is closed, Bluetooth is turned off, or the application exits + * unexpectedly. + *

The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is + * defined and performed by the application. + *

Use {@link BluetoothDevice#createInsecureL2capCocSocket(int, int)} to connect to this + * server socket from another Android device that is given the PSM value. + * + * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE} + * @return an L2CAP CoC BluetoothServerSocket + * @throws IOException on error, for example Bluetooth not available, or insufficient + * permissions, or unable to start this CoC + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport) + throws IOException { + if (transport != BluetoothDevice.TRANSPORT_LE) { + throw new IllegalArgumentException("Unsupported transport: " + transport); + } + BluetoothServerSocket socket = + new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false, + SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false); + int errno = socket.mSocket.bindListen(); + if (errno != 0) { + throw new IOException("Error: " + errno); + } + + int assignedPsm = socket.mSocket.getPort(); + if (assignedPsm == 0) { + throw new IOException("Error: Unable to assign PSM value"); + } + if (DBG) { + Log.d(TAG, "listenUsingInsecureL2capOn: set assigned PSM to " + + assignedPsm); + } + socket.setChannel(assignedPsm); + + return socket; + } } -- cgit v1.2.3 From cc816bb0a93e42e6ffa4ec1447a2bf69a23b50d1 Mon Sep 17 00:00:00 2001 From: Pavlin Radoslavov Date: Wed, 17 Jan 2018 02:09:53 -0800 Subject: Added internal API getMaxConnectedAudioDevices() The API can be used to obtain the maximum number of connected devices for A2DP or HFP. Test: Manual Bug: 64767509 Change-Id: I80b8a1c85e33ae0b23fdc4812f8991a4202d9abc --- .../java/android/bluetooth/BluetoothAdapter.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index c7be0f36ec..cdc881a25a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1670,6 +1670,27 @@ public final class BluetoothAdapter { return 0; } + /** + * Get the maximum number of connected audio devices. + * + * @return the maximum number of connected audio devices + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public int getMaxConnectedAudioDevices() { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.getMaxConnectedAudioDevices(); + } + } catch (RemoteException e) { + Log.e(TAG, "failed to get getMaxConnectedAudioDevices, error: ", e); + } finally { + mServiceLock.readLock().unlock(); + } + return 1; + } + /** * Return true if hardware has entries available for matching beacons * -- cgit v1.2.3 From 42044b47619069bdfdeeb151bea505c59c2e6510 Mon Sep 17 00:00:00 2001 From: Ricardo Loo Foronda Date: Wed, 24 Jan 2018 17:49:18 -0800 Subject: docs: Added a missing "be" in ACTION_CONNECTION_STATE_CHANGED Status: Ready for writer review. Note: This is a javadoc only change. Test: Build the docs with "make ds-docs" and staged updated content. Staged content: go/dac-stage/reference/android/bluetooth/BluetoothAdapter.html#ACTION_CONNECTION_STATE_CHANGED Bug: 69097875 Change-Id: Ibffea2373ded825558beaa669ae4daf3c0ff3d2f --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index fc3a72482a..1553eec8da 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -415,7 +415,7 @@ public final class BluetoothAdapter { * Intent used to broadcast the change in connection state of the local * Bluetooth adapter to a profile of the remote device. When the adapter is * not connected to any profiles of any remote devices and it attempts a - * connection to a profile this intent will sent. Once connected, this intent + * connection to a profile this intent will be sent. Once connected, this intent * will not be sent for any more connection attempts to any profiles of any * remote device. When the adapter disconnects from the last profile its * connected to of any remote device, this intent will be sent. -- cgit v1.2.3 From 3f23873b7e0bc6eca4c9778caeea1fd7ae41bf15 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Wed, 22 Nov 2017 11:02:34 -0800 Subject: Hearing Aid profile This is implementation of Hearing Aid Profile that will in future be connected to Bluetooth Manager - see TODOs in BluetoothHearingAid.java Bug: 69623109 Test: compilation. Manual test with HA. Change-Id: I79643ea1e14e9df7f5771169359c964a60c56618 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 6c8fe2e399..dc761521fb 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2303,6 +2303,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.HID_DEVICE) { BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener); return true; + } else if (profile == BluetoothProfile.HEARING_AID) { + BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener); + return true; } else { return false; } @@ -2385,6 +2388,9 @@ public final class BluetoothAdapter { BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy; hidDevice.close(); break; + case BluetoothProfile.HEARING_AID: + BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy; + hearingAid.close(); } } -- cgit v1.2.3 From 88c08ef5922e945a65d5f6e37dd1fb873aae4972 Mon Sep 17 00:00:00 2001 From: Jack He Date: Fri, 2 Mar 2018 13:11:27 -0800 Subject: Bluetooth: Use enums for adapter connection states Bug: 69478930 Test: make, no user visible change Change-Id: I999d0c445fe3b24aca72961c40c3428901542bc1 --- framework/java/android/bluetooth/BluetoothAdapter.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index dc761521fb..be4e207e58 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -537,13 +537,14 @@ public final class BluetoothAdapter { "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED"; /** The profile is in disconnected state */ - public static final int STATE_DISCONNECTED = 0; + public static final int STATE_DISCONNECTED = BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED; /** The profile is in connecting state */ - public static final int STATE_CONNECTING = 1; + public static final int STATE_CONNECTING = BluetoothProtoEnums.CONNECTION_STATE_CONNECTING; /** The profile is in connected state */ - public static final int STATE_CONNECTED = 2; + public static final int STATE_CONNECTED = BluetoothProtoEnums.CONNECTION_STATE_CONNECTED; /** The profile is in disconnecting state */ - public static final int STATE_DISCONNECTING = 3; + public static final int STATE_DISCONNECTING = + BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING; /** @hide */ public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; -- cgit v1.2.3 From 27128c930b398b0e24074db93396b793058c204f Mon Sep 17 00:00:00 2001 From: Jack He Date: Fri, 2 Mar 2018 13:11:27 -0800 Subject: Bluetooth: Use enums for adapter connection states Bug: 69478930 Test: make, no user visible change Change-Id: I999d0c445fe3b24aca72961c40c3428901542bc1 (cherry picked from commit ee81f9915041875a8c9b6b71a39cb0508f6d7b22) --- framework/java/android/bluetooth/BluetoothAdapter.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 1dc7549e76..ee667c2207 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -541,13 +541,14 @@ public final class BluetoothAdapter { "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED"; /** The profile is in disconnected state */ - public static final int STATE_DISCONNECTED = 0; + public static final int STATE_DISCONNECTED = BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED; /** The profile is in connecting state */ - public static final int STATE_CONNECTING = 1; + public static final int STATE_CONNECTING = BluetoothProtoEnums.CONNECTION_STATE_CONNECTING; /** The profile is in connected state */ - public static final int STATE_CONNECTED = 2; + public static final int STATE_CONNECTED = BluetoothProtoEnums.CONNECTION_STATE_CONNECTED; /** The profile is in disconnecting state */ - public static final int STATE_DISCONNECTING = 3; + public static final int STATE_DISCONNECTING = + BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING; /** @hide */ public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; -- cgit v1.2.3 From 5a96fe77b8727c8077f82007af1a87d4ff7aeacb Mon Sep 17 00:00:00 2001 From: Miao-chen Chou Date: Wed, 14 Mar 2018 15:00:23 -0700 Subject: Bluetooth: preserve one advertisement slot for GMS core This brings back the check on the multiple advertisement support before granting any Bluetooth LE advertiser. In other words, one slot is preserved for GMS core. Bug: 74819586 Test: Run an BLE application and verify the number of advertisements Change-Id: Iac3b47c76c6f699018982a69e9b04a9d8c631bfb --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index be4e207e58..6aabe18ba8 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -676,6 +676,10 @@ public final class BluetoothAdapter { if (!getLeAccess()) { return null; } + if (!isMultipleAdvertisementSupported()) { + Log.e(TAG, "Bluetooth LE advertising not supported"); + return null; + } synchronized (mLock) { if (sBluetoothLeAdvertiser == null) { sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); -- cgit v1.2.3 From a70a16b3e9d2433b7517e679f630d9dab33eea8a Mon Sep 17 00:00:00 2001 From: Qiyu Hu Date: Fri, 16 Mar 2018 12:22:16 -0700 Subject: Bluetooth: preserve one advertisement slot for GMS core This brings back the check on the multiple advertisement support before granting any Bluetooth LE advertiser. In other words, one slot is preserved for GMS core. Bug: 74819586 Test: Run an BLE application and verify the number of advertisements Change-Id: I05014e597bd5868f18a81842dc341e47991f2c79 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ee667c2207..b9e80e4067 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -680,6 +680,10 @@ public final class BluetoothAdapter { if (!getLeAccess()) { return null; } + if (!isMultipleAdvertisementSupported()) { + Log.e(TAG, "Bluetooth LE advertising not supported"); + return null; + } synchronized (mLock) { if (sBluetoothLeAdvertiser == null) { sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); -- cgit v1.2.3 From af5e99336b3a3e8573b648311db0a00141a83ff9 Mon Sep 17 00:00:00 2001 From: Zach Johnson Date: Fri, 23 Mar 2018 17:26:29 +0000 Subject: Revert "Bluetooth: preserve one advertisement slot for GMS core" This reverts commit a70a16b3e9d2433b7517e679f630d9dab33eea8a. Reason for revert: This breaks platforms that only support a single advertising slot. Bug: 76135219 Test: advertising does not work, revert change, advertising works Change-Id: Ib8c823eb9990cc06bad95c8c3ad0129afb245e00 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ---- 1 file changed, 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b9e80e4067..ee667c2207 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -680,10 +680,6 @@ public final class BluetoothAdapter { if (!getLeAccess()) { return null; } - if (!isMultipleAdvertisementSupported()) { - Log.e(TAG, "Bluetooth LE advertising not supported"); - return null; - } synchronized (mLock) { if (sBluetoothLeAdvertiser == null) { sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); -- cgit v1.2.3 From 11dc909599e9154f555db327000ec76db6910cd0 Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Wed, 4 Apr 2018 18:33:46 -0700 Subject: Cleanup documentation for LE CoC in BluetoothAdapter Test: Compile Bug: 77631591 Change-Id: Ic3c7f13e560534a048bf5c8b274fe62190c214c7 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 6aabe18ba8..3d95669f4c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -80,8 +80,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * {@link #getBondedDevices()}; start device discovery with * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to * listen for incoming RFComm connection requests with {@link - * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented - * Channels (CoC) connection requests with listenUsingL2capCoc(int)}; or start a scan for + * #listenUsingRfcommWithServiceRecord(String, UUID)}; or start a scan for * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. *

*

This class is thread safe.

-- cgit v1.2.3 From af53c8f68036f1067f9f9fb251a0b5194c2bd840 Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Wed, 4 Apr 2018 18:33:46 -0700 Subject: Cleanup documentation for LE CoC in BluetoothAdapter Test: Compile Bug: 77631591 Change-Id: Ic3c7f13e560534a048bf5c8b274fe62190c214c7 (cherry picked from commit dac8e140184f3ac52210ff3638af3f53edca1ba0) --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ee667c2207..1b6b5a01ec 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -80,8 +80,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * {@link #getBondedDevices()}; start device discovery with * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to * listen for incoming RFComm connection requests with {@link - * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented - * Channels (CoC) connection requests with listenUsingL2capCoc(int)}; or start a scan for + * #listenUsingRfcommWithServiceRecord(String, UUID)}; or start a scan for * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. *

*

This class is thread safe.

-- cgit v1.2.3 From 4143ed3ac8c059ea32f6f33b6ecadfd133428beb Mon Sep 17 00:00:00 2001 From: Pulkit Bhuwalka Date: Wed, 28 Mar 2018 13:51:43 -0700 Subject: Get/Set IO capability of Bluetooth device Creates the hidden BluetoothAdapter APIs which can be used to control IO capability settings on the local Bluetooth device. Bug: 36015413 Test: Used a test activity to control getting/setting the value and attempting pairing. Change-Id: Ibbfdc5ae5a1d56c6e3d003ab3bf5d095dcb583e4 (cherry picked from commit 6043b7b90a27a836241bfc05e71eb46ce04c66cf) --- .../java/android/bluetooth/BluetoothAdapter.java | 152 +++++++++++++++++++++ 1 file changed, 152 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3d95669f4c..df75b0d0b7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -389,6 +389,58 @@ public final class BluetoothAdapter { */ public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; + /** + * Device only has a display. + * + * @hide + */ + public static final int IO_CAPABILITY_OUT = 0; + + /** + * Device has a display and the ability to input Yes/No. + * + * @hide + */ + public static final int IO_CAPABILITY_IO = 1; + + /** + * Device only has a keyboard for entry but no display. + * + * @hide + */ + public static final int IO_CAPABILITY_IN = 2; + + /** + * Device has no Input or Output capability. + * + * @hide + */ + public static final int IO_CAPABILITY_NONE = 3; + + /** + * Device has a display and a full keyboard. + * + * @hide + */ + public static final int IO_CAPABILITY_KBDISP = 4; + + /** + * Maximum range value for Input/Output capabilities. + * + *

This should be updated when adding a new Input/Output capability. Other code + * like validation depends on this being accurate. + * + * @hide + */ + public static final int IO_CAPABILITY_MAX = 5; + + /** + * The Input/Output capability of the device is unknown. + * + * @hide + */ + public static final int IO_CAPABILITY_UNKNOWN = 255; + /** * Broadcast Action: The local Bluetooth adapter has started the remote * device discovery process. @@ -1224,6 +1276,106 @@ public final class BluetoothAdapter { return false; } + /** + * Returns the Input/Output capability of the device for classic Bluetooth. + * + * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, + * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE}, + * {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}. + * + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public int getIoCapability() { + if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.getIoCapability(); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } finally { + mServiceLock.readLock().unlock(); + } + return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; + } + + /** + * Sets the Input/Output capability of the device for classic Bluetooth. + * + *

Changing the Input/Output capability of a device only takes effect on restarting the + * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()} + * and {@link BluetoothAdapter#enable()} to see the changes. + * + * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, + * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, + * {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}. + * + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean setIoCapability(int capability) { + if (getState() != STATE_ON) return false; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.setIoCapability(capability); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; + } + + /** + * Returns the Input/Output capability of the device for BLE operations. + * + * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, + * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE}, + * {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}. + * + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public int getLeIoCapability() { + if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.getLeIoCapability(); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } finally { + mServiceLock.readLock().unlock(); + } + return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; + } + + /** + * Sets the Input/Output capability of the device for BLE operations. + * + *

Changing the Input/Output capability of a device only takes effect on restarting the + * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()} + * and {@link BluetoothAdapter#enable()} to see the changes. + * + * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, + * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, + * {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}. + * + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean setLeIoCapability(int capability) { + if (getState() != STATE_ON) return false; + try { + mServiceLock.readLock().lock(); + if (mService != null) return mService.setLeIoCapability(capability); + } catch (RemoteException e) { + Log.e(TAG, e.getMessage(), e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; + } + /** * Get the current Bluetooth scan mode of the local Bluetooth adapter. *

The Bluetooth scan mode determines if the local adapter is -- cgit v1.2.3 From 46f6c56ff30e00a62d144a84df8dd592c53e6b37 Mon Sep 17 00:00:00 2001 From: Pulkit Bhuwalka Date: Fri, 20 Apr 2018 16:56:53 -0700 Subject: Add IntDef to BluetoothAdapter IO_CAP constants Bug: None Test: Builds Change-Id: I04f8f6cdcc1a552ae2f2a358308b9a5c862989d3 --- framework/java/android/bluetooth/BluetoothAdapter.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index df75b0d0b7..bd65639605 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -441,6 +441,12 @@ public final class BluetoothAdapter { */ public static final int IO_CAPABILITY_UNKNOWN = 255; + /** @hide */ + @IntDef({IO_CAPABILITY_OUT, IO_CAPABILITY_IO, IO_CAPABILITY_IN, IO_CAPABILITY_NONE, + IO_CAPABILITY_KBDISP}) + @Retention(RetentionPolicy.SOURCE) + public @interface IoCapability {} + /** * Broadcast Action: The local Bluetooth adapter has started the remote * device discovery process. @@ -1286,6 +1292,7 @@ public final class BluetoothAdapter { * @hide */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @IoCapability public int getIoCapability() { if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; try { @@ -1313,7 +1320,7 @@ public final class BluetoothAdapter { * @hide */ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean setIoCapability(int capability) { + public boolean setIoCapability(@IoCapability int capability) { if (getState() != STATE_ON) return false; try { mServiceLock.readLock().lock(); @@ -1336,6 +1343,7 @@ public final class BluetoothAdapter { * @hide */ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @IoCapability public int getLeIoCapability() { if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; try { @@ -1363,7 +1371,7 @@ public final class BluetoothAdapter { * @hide */ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean setLeIoCapability(int capability) { + public boolean setLeIoCapability(@IoCapability int capability) { if (getState() != STATE_ON) return false; try { mServiceLock.readLock().lock(); -- cgit v1.2.3 From 7d543894e0497651fc160728d659543483500f87 Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Wed, 1 Aug 2018 15:07:20 +0100 Subject: Add @UnsupportedAppUsage annotations For packages: android.bluetooth.le android.bluetooth This is an automatically generated CL. See go/UnsupportedAppUsage for more details. Exempted-From-Owner-Approval: Mechanical changes to the codebase which have been approved by Android API council and announced on android-eng@ Bug: 110868826 Test: m Change-Id: Ifcf24c0617acd7facc0e03f30a95c3a6b09b205c Merged-In: I88a1311e27c5f9a5f9d1035db76034f86f650efc --- framework/java/android/bluetooth/BluetoothAdapter.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index df75b0d0b7..2bf444c23b 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -23,6 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; +import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; @@ -629,6 +630,7 @@ public final class BluetoothAdapter { private static PeriodicAdvertisingManager sPeriodicAdvertisingManager; private final IBluetoothManager mManagerService; + @UnsupportedAppUsage private IBluetooth mService; private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); @@ -988,6 +990,7 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH) @AdapterState + @UnsupportedAppUsage public int getLeState() { int state = BluetoothAdapter.STATE_OFF; @@ -1098,6 +1101,7 @@ public final class BluetoothAdapter { * @return true to indicate adapter shutdown has begun, or false on immediate error * @hide */ + @UnsupportedAppUsage public boolean disable(boolean persist) { try { @@ -1149,6 +1153,7 @@ public final class BluetoothAdapter { * @return true to indicate that the config file was successfully cleared * @hide */ + @UnsupportedAppUsage public boolean factoryReset() { try { mServiceLock.readLock().lock(); @@ -1172,6 +1177,7 @@ public final class BluetoothAdapter { * @return the UUIDs supported by the local Bluetooth Adapter. * @hide */ + @UnsupportedAppUsage public ParcelUuid[] getUuids() { if (getState() != STATE_ON) { return null; @@ -1438,6 +1444,7 @@ public final class BluetoothAdapter { * @return true if the scan mode was set, false otherwise * @hide */ + @UnsupportedAppUsage public boolean setScanMode(@ScanMode int mode, int duration) { if (getState() != STATE_ON) { return false; @@ -1456,6 +1463,7 @@ public final class BluetoothAdapter { } /** @hide */ + @UnsupportedAppUsage public boolean setScanMode(int mode) { if (getState() != STATE_ON) { return false; @@ -1465,6 +1473,7 @@ public final class BluetoothAdapter { } /** @hide */ + @UnsupportedAppUsage public int getDiscoverableTimeout() { if (getState() != STATE_ON) { return -1; @@ -1483,6 +1492,7 @@ public final class BluetoothAdapter { } /** @hide */ + @UnsupportedAppUsage public void setDiscoverableTimeout(int timeout) { if (getState() != STATE_ON) { return; @@ -2007,6 +2017,7 @@ public final class BluetoothAdapter { * #STATE_CONNECTING} or {@link #STATE_DISCONNECTED} * @hide */ + @UnsupportedAppUsage public int getConnectionState() { if (getState() != STATE_ON) { return BluetoothAdapter.STATE_DISCONNECTED; @@ -2094,6 +2105,7 @@ public final class BluetoothAdapter { * permissions, or channel in use. * @hide */ + @UnsupportedAppUsage public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm, boolean min16DigitPin) throws IOException { BluetoothServerSocket socket = @@ -2206,6 +2218,7 @@ public final class BluetoothAdapter { * permissions, or channel in use. * @hide */ + @UnsupportedAppUsage public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid) throws IOException { return createNewRfcommSocketAndRecord(name, uuid, false, true); @@ -2749,6 +2762,7 @@ public final class BluetoothAdapter { return true; } + @UnsupportedAppUsage /*package*/ IBluetoothManager getBluetoothManager() { return mManagerService; } @@ -2756,6 +2770,7 @@ public final class BluetoothAdapter { private final ArrayList mProxyServiceStateCallbacks = new ArrayList(); + @UnsupportedAppUsage /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { synchronized (mProxyServiceStateCallbacks) { if (cb == null) { -- cgit v1.2.3 From 412cbec0c57647b955747e9b55bce071870b9a1e Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Fri, 29 Jun 2018 14:05:04 -0700 Subject: Unhide the LE CoC APIs Expose the LE Connection-oriented Channels APIs for applications to use. Test: Run the SL4A ACTS test: BleCocTest Bug: 70683224 Change-Id: I68128bc7154966ec065091c973351f8892da9b4d --- .../java/android/bluetooth/BluetoothAdapter.java | 59 ++++++++++++++-------- 1 file changed, 38 insertions(+), 21 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 4c655b5ac0..654bfaf293 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -81,7 +81,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * {@link #getBondedDevices()}; start device discovery with * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to * listen for incoming RFComm connection requests with {@link - * #listenUsingRfcommWithServiceRecord(String, UUID)}; or start a scan for + * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented + * Channels (CoC) connection requests with {@link #listenUsingL2capChannel()}; or start a scan for * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. *

*

This class is thread safe.

@@ -2967,7 +2968,7 @@ public final class BluetoothAdapter { /** * Create a secure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and * assign a dynamic protocol/service multiplexer (PSM) value. This socket can be used to listen - * for incoming connections. + * for incoming connections. The supported Bluetooth transport is LE only. *

A remote device connecting to this socket will be authenticated and communication on this * socket will be encrypted. *

Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening @@ -2977,21 +2978,16 @@ public final class BluetoothAdapter { * closed, Bluetooth is turned off, or the application exits unexpectedly. *

The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is * defined and performed by the application. - *

Use {@link BluetoothDevice#createL2capCocSocket(int, int)} to connect to this server + *

Use {@link BluetoothDevice#createL2capChannel(int)} to connect to this server * socket from another Android device that is given the PSM value. * - * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE} * @return an L2CAP CoC BluetoothServerSocket * @throws IOException on error, for example Bluetooth not available, or insufficient * permissions, or unable to start this CoC - * @hide */ @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothServerSocket listenUsingL2capCoc(int transport) + public BluetoothServerSocket listenUsingL2capChannel() throws IOException { - if (transport != BluetoothDevice.TRANSPORT_LE) { - throw new IllegalArgumentException("Unsupported transport: " + transport); - } BluetoothServerSocket socket = new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true, SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false); @@ -3005,7 +3001,7 @@ public final class BluetoothAdapter { throw new IOException("Error: Unable to assign PSM value"); } if (DBG) { - Log.d(TAG, "listenUsingL2capCoc: set assigned PSM to " + Log.d(TAG, "listenUsingL2capChannel: set assigned PSM to " + assignedPsm); } socket.setChannel(assignedPsm); @@ -3013,11 +3009,24 @@ public final class BluetoothAdapter { return socket; } + /** + * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new + * API name, listenUsingL2capChannel. + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public BluetoothServerSocket listenUsingL2capCoc(int transport) + throws IOException { + Log.e(TAG, "listenUsingL2capCoc: PLEASE USE THE OFFICIAL API, listenUsingL2capChannel"); + return listenUsingL2capChannel(); + } + /** * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and - * assign a dynamic PSM value. This socket can be used to listen for incoming connections. + * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The + * supported Bluetooth transport is LE only. *

The link key is not required to be authenticated, i.e the communication may be vulnerable - * to man-in-the-middle attacks. Use {@link #listenUsingL2capCoc}, if an encrypted and + * to man-in-the-middle attacks. Use {@link #listenUsingL2capChannel}, if an encrypted and * authenticated communication channel is desired. *

Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening * {@link BluetoothServerSocket}. @@ -3027,21 +3036,16 @@ public final class BluetoothAdapter { * unexpectedly. *

The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is * defined and performed by the application. - *

Use {@link BluetoothDevice#createInsecureL2capCocSocket(int, int)} to connect to this - * server socket from another Android device that is given the PSM value. + *

Use {@link BluetoothDevice#createInsecureL2capChannel(int)} to connect to this server + * socket from another Android device that is given the PSM value. * - * @param transport Bluetooth transport to use, must be {@link BluetoothDevice#TRANSPORT_LE} * @return an L2CAP CoC BluetoothServerSocket * @throws IOException on error, for example Bluetooth not available, or insufficient * permissions, or unable to start this CoC - * @hide */ @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport) + public BluetoothServerSocket listenUsingInsecureL2capChannel() throws IOException { - if (transport != BluetoothDevice.TRANSPORT_LE) { - throw new IllegalArgumentException("Unsupported transport: " + transport); - } BluetoothServerSocket socket = new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false, SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false); @@ -3055,11 +3059,24 @@ public final class BluetoothAdapter { throw new IOException("Error: Unable to assign PSM value"); } if (DBG) { - Log.d(TAG, "listenUsingInsecureL2capOn: set assigned PSM to " + Log.d(TAG, "listenUsingInsecureL2capChannel: set assigned PSM to " + assignedPsm); } socket.setChannel(assignedPsm); return socket; } + + /** + * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new + * API name, listenUsingInsecureL2capChannel. + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport) + throws IOException { + Log.e(TAG, "listenUsingInsecureL2capCoc: PLEASE USE THE OFFICIAL API, " + + "listenUsingInsecureL2capChannel"); + return listenUsingInsecureL2capChannel(); + } } -- cgit v1.2.3 From ee9e4f6b77d8b9ecd011177e1e6cbd62e0ff2d77 Mon Sep 17 00:00:00 2001 From: Andrew Solovay Date: Tue, 2 Oct 2018 14:14:42 -0700 Subject: docs: Replacing {#link with {@link Several java files had the typo {#link (for cross-references to other Javadocs) instead of the proper {@link format. This was confusing the new doc publish tool (Mivi) since that's the format used for {# Django comments #}. Fixed a couple of links that had other errors (which prevented building once the {# -> {@ was done) and other typos. Replaced throughout the frameworks/base project; I'll need a separate CL for the AndroidX fixes. Staged to: go/dac-stage/reference/android/app/Instrumentation.html go/dac-stage/reference/android/bluetooth/BluetoothAdapter.html go/dac-stage/reference/android/bluetooth/BluetoothDevice.html go/dac-stage/reference/android/bluetooth/BluetoothServerSocket.html go/dac-stage/reference/android/inputmethodservice/InputMethodService.html go/dac-stage/reference/android/view/KeyCharacterMap.html go/dac-stage/reference/android/view/KeyEvent.html go/dac-stage/reference/android/media/AudioManager.html go/dac-stage/reference/android/net/wifi/WifiConfiguration.html (Other files were not in the public Javadocs.) Bug: 111925950 Test: make ds-docs Exempt-From-Owner-Approval: Docs-only change Change-Id: Ia06e1fffd814671289a1caebd5962aedc18a28d7 Merged-In: Ia06e1fffd814671289a1caebd5962aedc18a28d7 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 1b6b5a01ec..44051081b5 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2797,7 +2797,7 @@ public final class BluetoothAdapter { * socket will be encrypted. *

Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening * {@link BluetoothServerSocket}. - *

The system will assign a dynamic PSM value. This PSM value can be read from the {#link + *

The system will assign a dynamic PSM value. This PSM value can be read from the {@link * BluetoothServerSocket#getPsm()} and this value will be released when this server socket is * closed, Bluetooth is turned off, or the application exits unexpectedly. *

The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is @@ -2847,7 +2847,7 @@ public final class BluetoothAdapter { *

Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening * {@link BluetoothServerSocket}. *

The system will assign a dynamic protocol/service multiplexer (PSM) value. This PSM value - * can be read from the {#link BluetoothServerSocket#getPsm()} and this value will be released + * can be read from the {@link BluetoothServerSocket#getPsm()} and this value will be released * when this server socket is closed, Bluetooth is turned off, or the application exits * unexpectedly. *

The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is -- cgit v1.2.3 From 9ef032b089f5340abc204ee26091b459e636b810 Mon Sep 17 00:00:00 2001 From: Zach Johnson Date: Wed, 12 Dec 2018 17:11:25 -0800 Subject: Pass package name as part of startDiscovery Test: manual Bug: 118347252 Change-Id: Icbc2e7e756b16ffd181924b586a0292c2bf32ec5 --- .../java/android/bluetooth/BluetoothAdapter.java | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 654bfaf293..10c8b15a7a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -643,6 +643,7 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; @UnsupportedAppUsage private IBluetooth mService; + private Context mContext; private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); private final Object mLock = new Object(); @@ -1540,6 +1541,23 @@ public final class BluetoothAdapter { return -1; } + /** + * Set the context for this BluetoothAdapter (only called from BluetoothManager) + * @hide + */ + public void setContext(Context context) { + mContext = context; + } + + private String getOpPackageName() { + // Workaround for legacy API for getting a BluetoothAdapter not + // passing a context + if (mContext != null) { + return mContext.getOpPackageName(); + } + return ActivityThread.currentOpPackageName(); + } + /** * Start the remote device discovery process. *

The discovery process usually involves an inquiry scan of about 12 @@ -1577,7 +1595,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.startDiscovery(); + return mService.startDiscovery(getOpPackageName()); } } catch (RemoteException e) { Log.e(TAG, "", e); -- cgit v1.2.3 From 8bb9c7d4acc24f45fad0b1b964f4973e71fab3e3 Mon Sep 17 00:00:00 2001 From: Jack He Date: Thu, 3 Jan 2019 16:23:41 -0800 Subject: Deprecate BluetoothHealth APIs * Mark all BluetoothHealth related APIs as deprecated * Make BluetoothAdapter#getProfileProxy(context, BluetoothProfile.HEALTH) always return false * Remove all logic behind BluetoothHealth APIs and add deprecation error log * Health Device Profile (HDP) and MCAP protocol has been largely replaced by BLE. New applications should use Bluetooth Low Energy instead of legacy Bluetooth Health Device Profile Bug: 111562841 Test: make, unit test, use Bluetooth Change-Id: If99a9d79e9e1b89b75b9b74bd3b1c965247a1892 Merged-In: If99a9d79e9e1b89b75b9b74bd3b1c965247a1892 (cherry picked from commit 07ffaa447fdd967689901cca38eba386a8d97b23) --- .../java/android/bluetooth/BluetoothAdapter.java | 27 ++++++++-------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 10c8b15a7a..38245fb2ad 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2066,8 +2066,7 @@ public final class BluetoothAdapter { * Get the current connection state of a profile. * This function can be used to check whether the local Bluetooth adapter * is connected to any remote device for a specific profile. - * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, - * {@link BluetoothProfile#A2DP}. + * Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. * *

Return value can be one of * {@link BluetoothProfile#STATE_DISCONNECTED}, @@ -2441,16 +2440,15 @@ public final class BluetoothAdapter { /** * Get the profile proxy object associated with the profile. * - *

Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, - * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or - * {@link BluetoothProfile#GATT_SERVER}. Clients must implement - * {@link BluetoothProfile.ServiceListener} to get notified of - * the connection status and to get the proxy object. + *

Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}, + * {@link BluetoothProfile#GATT}, or {@link BluetoothProfile#GATT_SERVER}. Clients must + * implement {@link BluetoothProfile.ServiceListener} to get notified of the connection status + * and to get the proxy object. * * @param context Context of the application * @param listener The service Listener for connection callbacks. - * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH}, {@link - * BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. {@link BluetoothProfile#GATT} or + * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEADSET}, + * {@link BluetoothProfile#A2DP}. {@link BluetoothProfile#GATT} or * {@link BluetoothProfile#GATT_SERVER}. * @return true on success, false on error */ @@ -2479,8 +2477,8 @@ public final class BluetoothAdapter { BluetoothPan pan = new BluetoothPan(context, listener); return true; } else if (profile == BluetoothProfile.HEALTH) { - BluetoothHealth health = new BluetoothHealth(context, listener); - return true; + Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated"); + return false; } else if (profile == BluetoothProfile.MAP) { BluetoothMap map = new BluetoothMap(context, listener); return true; @@ -2512,8 +2510,7 @@ public final class BluetoothAdapter { * *

Clients should call this when they are no longer using * the proxy obtained from {@link #getProfileProxy}. - * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or - * {@link BluetoothProfile#A2DP} + * Profile can be one of {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP} * * @param profile * @param proxy Profile proxy object @@ -2548,10 +2545,6 @@ public final class BluetoothAdapter { BluetoothPan pan = (BluetoothPan) proxy; pan.close(); break; - case BluetoothProfile.HEALTH: - BluetoothHealth health = (BluetoothHealth) proxy; - health.close(); - break; case BluetoothProfile.GATT: BluetoothGatt gatt = (BluetoothGatt) proxy; gatt.close(); -- cgit v1.2.3 From d22fb8f068841b8848589cb99eea7ef9c2e09d29 Mon Sep 17 00:00:00 2001 From: Ugo Yu Date: Tue, 8 Jan 2019 09:00:09 +0800 Subject: Skeleton implementation of Bluetooth metadata APIs Bug: 121051445 Test: Build pass Change-Id: I5e80210205b37294b1eb8356502ebf242e627ce4 --- .../java/android/bluetooth/BluetoothAdapter.java | 175 +++++++++++++++++++++ 1 file changed, 175 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 38245fb2ad..e04aac49cf 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -36,6 +36,7 @@ import android.bluetooth.le.ScanSettings; import android.content.Context; import android.os.BatteryStats; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; @@ -648,6 +649,32 @@ public final class BluetoothAdapter { private final Object mLock = new Object(); private final Map mLeScanClients; + private static final Map>> + sMetadataListeners = new HashMap<>(); + + /** + * Bluetooth metadata listener. Overrides the default BluetoothMetadataListener + * implementation. + */ + private static final IBluetoothMetadataListener sBluetoothMetadataListener = + new IBluetoothMetadataListener.Stub() { + @Override + public void onMetadataChanged(BluetoothDevice device, int key, String value) { + synchronized (sMetadataListeners) { + if (sMetadataListeners.containsKey(device)) { + List> list = sMetadataListeners.get(device); + for (Pair pair : list) { + MetadataListener listener = pair.first; + Handler handler = pair.second; + handler.post(() -> { + listener.onMetadataChanged(device, key, value); + }); + } + } + } + return; + } + }; /** * Get a handle to the default local Bluetooth adapter. @@ -2607,6 +2634,16 @@ public final class BluetoothAdapter { } } } + synchronized (sMetadataListeners) { + sMetadataListeners.forEach((device, pair) -> { + try { + mService.registerMetadataListener(sBluetoothMetadataListener, + device); + } catch (RemoteException e) { + Log.e(TAG, "Failed to register metadata listener", e); + } + }); + } } public void onBluetoothServiceDown() { @@ -3090,4 +3127,142 @@ public final class BluetoothAdapter { + "listenUsingInsecureL2capChannel"); return listenUsingInsecureL2capChannel(); } + + /** + * Register a {@link #MetadataListener} to receive update about metadata + * changes for this {@link BluetoothDevice}. + * Registration must be done when Bluetooth is ON and will last until + * {@link #unregisterMetadataListener(BluetoothDevice)} is called, even when Bluetooth + * restarted in the middle. + * All input parameters should not be null or {@link NullPointerException} will be triggered. + * The same {@link BluetoothDevice} and {@link #MetadataListener} pair can only be registered + * once, double registration would cause {@link IllegalArgumentException}. + * + * @param device {@link BluetoothDevice} that will be registered + * @param listener {@link #MetadataListener} that will receive asynchronous callbacks + * @param handler the handler for listener callback + * @return true on success, false on error + * @throws NullPointerException If one of {@code listener}, {@code device} or {@code handler} + * is null. + * @throws IllegalArgumentException The same {@link #MetadataListener} and + * {@link BluetoothDevice} are registered twice. + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean registerMetadataListener(BluetoothDevice device, MetadataListener listener, + Handler handler) { + if (DBG) Log.d(TAG, "registerMetdataListener()"); + + final IBluetooth service = mService; + if (service == null) { + Log.e(TAG, "Bluetooth is not enabled. Cannot register metadata listener"); + return false; + } + if (listener == null) { + throw new NullPointerException("listener is null"); + } + if (device == null) { + throw new NullPointerException("device is null"); + } + if (handler == null) { + throw new NullPointerException("handler is null"); + } + + synchronized (sMetadataListeners) { + List> listenerList = sMetadataListeners.get(device); + if (listenerList == null) { + // Create new listener/handler list for registeration + listenerList = new ArrayList<>(); + sMetadataListeners.put(device, listenerList); + } else { + // Check whether this device was already registed by the lisenter + if (listenerList.stream().anyMatch((pair) -> (pair.first.equals(listener)))) { + throw new IllegalArgumentException("listener was already regestered" + + " for the device"); + } + } + + Pair listenerPair = new Pair(listener, handler); + listenerList.add(listenerPair); + + boolean ret = false; + try { + ret = service.registerMetadataListener(sBluetoothMetadataListener, device); + } catch (RemoteException e) { + Log.e(TAG, "registerMetadataListener fail", e); + } finally { + if (!ret) { + // Remove listener registered earlier when fail. + listenerList.remove(listenerPair); + if (listenerList.isEmpty()) { + // Remove the device if its listener list is empty + sMetadataListeners.remove(device); + } + } + } + return ret; + } + } + + /** + * Unregister all {@link MetadataListener} from this {@link BluetoothDevice}. + * Unregistration can be done when Bluetooth is either ON or OFF. + * {@link #registerMetadataListener(MetadataListener, BluetoothDevice, Handler)} must + * be called before unregisteration. + * Unregistering a device that is not regestered would cause {@link IllegalArgumentException}. + * + * @param device {@link BluetoothDevice} that will be unregistered. it + * should not be null or {@link NullPointerException} will be triggered. + * @return true on success, false on error + * @throws NullPointerException If {@code device} is null. + * @throws IllegalArgumentException If {@code device} has not been registered before. + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean unregisterMetadataListener(BluetoothDevice device) { + if (DBG) Log.d(TAG, "unregisterMetdataListener()"); + if (device == null) { + throw new NullPointerException("device is null"); + } + + synchronized (sMetadataListeners) { + if (sMetadataListeners.containsKey(device)) { + sMetadataListeners.remove(device); + } else { + throw new IllegalArgumentException("device was not registered"); + } + + final IBluetooth service = mService; + if (service == null) { + // Bluetooth is OFF, do nothing to Bluetooth service. + return true; + } + try { + return service.unregisterMetadataListener(device); + } catch (RemoteException e) { + Log.e(TAG, "unregisterMetadataListener fail", e); + return false; + } + } + } + + /** + * This abstract class is used to implement {@link BluetoothAdapter} metadata listener. + * @hide + */ + @SystemApi + public abstract class MetadataListener { + /** + * Callback triggered if the metadata of {@link BluetoothDevice} registered in + * {@link #registerMetadataListener}. + * + * @param device changed {@link BluetoothDevice}. + * @param key changed metadata key, one of BluetoothDevice.METADATA_*. + * @param value the new value of metadata. + */ + public void onMetadataChanged(BluetoothDevice device, int key, String value) { + } + } } -- cgit v1.2.3 From 370a8ae8d0e015a5e01a3c1c2c3b1387e3026b08 Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Sun, 13 Jan 2019 16:04:31 -0800 Subject: Add 2 new ways to check for Support for Hearing Aids Profile The getProfileProxy will return false if Hearing Aids Profile is not supported. Also the getSupportedProfiles will return the correct support for Hearing Aids even when Bluetooth is disabled. Test: Manual testing with configuration enabled and disabled. Bug: 119617521 Change-Id: I146bd3bc36d4c474f7bca18a05b679fb8e70ca63 --- .../java/android/bluetooth/BluetoothAdapter.java | 26 ++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 38245fb2ad..db8674b524 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1872,6 +1872,20 @@ public final class BluetoothAdapter { return 0; } + /** + * Return true if Hearing Aid Profile is supported. + * + * @return true if phone supports Hearing Aid Profile + */ + private boolean isHearingAidProfileSupported() { + try { + return mManagerService.isHearingAidProfileSupported(); + } catch (RemoteException e) { + Log.e(TAG, "remote expection when calling isHearingAidProfileSupported", e); + return false; + } + } + /** * Get the maximum number of connected audio devices. * @@ -2024,6 +2038,11 @@ public final class BluetoothAdapter { supportedProfiles.add(i); } } + } else { + // Bluetooth is disabled. Just fill in known supported Profiles + if (isHearingAidProfileSupported()) { + supportedProfiles.add(BluetoothProfile.HEARING_AID); + } } } } catch (RemoteException e) { @@ -2498,8 +2517,11 @@ public final class BluetoothAdapter { BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener); return true; } else if (profile == BluetoothProfile.HEARING_AID) { - BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener); - return true; + if (isHearingAidProfileSupported()) { + BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener); + return true; + } + return false; } else { return false; } -- cgit v1.2.3 From d171d884786d129a20adf7685d869d887ab5d430 Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Thu, 15 Nov 2018 17:11:36 -0800 Subject: Add Android APIs for Hearing Aids Profile Add the new public Android APIs for the ASHA Hearing Aids Profile. Bug: 119617521 Bug: 120222233 Test: Run with the new HearingAidProfileTest CTS test Change-Id: I05fc3d565bd22b5000765122da7714d961dbc15b --- framework/java/android/bluetooth/BluetoothAdapter.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index db8674b524..724fef028d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2460,15 +2460,16 @@ public final class BluetoothAdapter { * Get the profile proxy object associated with the profile. * *

Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}, - * {@link BluetoothProfile#GATT}, or {@link BluetoothProfile#GATT_SERVER}. Clients must - * implement {@link BluetoothProfile.ServiceListener} to get notified of the connection status - * and to get the proxy object. + * {@link BluetoothProfile#GATT}, {@link BluetoothProfile#HEARING_AID}, or {@link + * BluetoothProfile#GATT_SERVER}. Clients must implement {@link + * BluetoothProfile.ServiceListener} to get notified of the connection status and to get the + * proxy object. * * @param context Context of the application * @param listener The service Listener for connection callbacks. * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEADSET}, - * {@link BluetoothProfile#A2DP}. {@link BluetoothProfile#GATT} or - * {@link BluetoothProfile#GATT_SERVER}. + * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, {@link + * BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#GATT_SERVER}. * @return true on success, false on error */ public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, -- cgit v1.2.3 From 064375d6031318fdf0e5a95eabafe9c4ce677014 Mon Sep 17 00:00:00 2001 From: Ugo Yu Date: Thu, 24 Jan 2019 09:13:00 +0800 Subject: Change MetadataListener to a abstract static class Bug: 121051445 Test: build pass Change-Id: I8148d13d2eb0899d54817197ae0be236e2914e47 --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e04aac49cf..010a7b2049 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3253,7 +3253,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - public abstract class MetadataListener { + public abstract static class MetadataListener { /** * Callback triggered if the metadata of {@link BluetoothDevice} registered in * {@link #registerMetadataListener}. -- cgit v1.2.3 From a2285ae16646af4b391212b5e0057458de42909a Mon Sep 17 00:00:00 2001 From: Stanley Tng Date: Tue, 12 Mar 2019 10:19:49 -0700 Subject: Add @NonNull annotations to LE CoC APIs Added NonNull annotations to the 4 LE Connection-oriented channel API in BluetoothDevice and BluetoothAdapter. Bug: 126701988 Bug: 126701989 Test: Compile only Change-Id: I2d4dc8fbd06e30c782123e01f8481d249e40ee02 --- framework/java/android/bluetooth/BluetoothAdapter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ab8c196edc..b8a741ab2b 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -19,6 +19,7 @@ package android.bluetooth; import android.Manifest; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -3057,7 +3058,7 @@ public final class BluetoothAdapter { * permissions, or unable to start this CoC */ @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothServerSocket listenUsingL2capChannel() + public @NonNull BluetoothServerSocket listenUsingL2capChannel() throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true, @@ -3115,7 +3116,7 @@ public final class BluetoothAdapter { * permissions, or unable to start this CoC */ @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothServerSocket listenUsingInsecureL2capChannel() + public @NonNull BluetoothServerSocket listenUsingInsecureL2capChannel() throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false, -- cgit v1.2.3 From 876095721954013abe4d33a359fcae34d8d7f2aa Mon Sep 17 00:00:00 2001 From: Ugo Yu Date: Tue, 5 Mar 2019 16:20:27 +0800 Subject: Refine Bluetooth Metadata API - Modify MetadataListener to as an interface and rename it to OnMetadataChangedListener - Fix typo UNTHETHERED -> UNTETHERED - Add NonNull annotation for metadata API parameters - Re-design metadata unregister API - Change metadata type to byte array Bug: 124448651 Bug: 126701203 Bug: 126699213 Test: build pass Change-Id: I79460071c7693f648e92cf849738c24f8bc269d9 Merged-In: I79460071c7693f648e92cf849738c24f8bc269d9 --- .../java/android/bluetooth/BluetoothAdapter.java | 116 ++++++++++++--------- 1 file changed, 65 insertions(+), 51 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b8a741ab2b..31bbd16497 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -20,6 +20,7 @@ package android.bluetooth; import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -37,7 +38,6 @@ import android.bluetooth.le.ScanSettings; import android.content.Context; import android.os.BatteryStats; import android.os.Binder; -import android.os.Handler; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; @@ -61,6 +61,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -650,7 +651,7 @@ public final class BluetoothAdapter { private final Object mLock = new Object(); private final Map mLeScanClients; - private static final Map>> + private static final Map>> sMetadataListeners = new HashMap<>(); /** @@ -660,14 +661,15 @@ public final class BluetoothAdapter { private static final IBluetoothMetadataListener sBluetoothMetadataListener = new IBluetoothMetadataListener.Stub() { @Override - public void onMetadataChanged(BluetoothDevice device, int key, String value) { + public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) { synchronized (sMetadataListeners) { if (sMetadataListeners.containsKey(device)) { - List> list = sMetadataListeners.get(device); - for (Pair pair : list) { - MetadataListener listener = pair.first; - Handler handler = pair.second; - handler.post(() -> { + List> list = + sMetadataListeners.get(device); + for (Pair pair : list) { + OnMetadataChangedListener listener = pair.first; + Executor executor = pair.second; + executor.execute(() -> { listener.onMetadataChanged(device, key, value); }); } @@ -3153,30 +3155,30 @@ public final class BluetoothAdapter { } /** - * Register a {@link #MetadataListener} to receive update about metadata + * Register a {@link #OnMetadataChangedListener} to receive update about metadata * changes for this {@link BluetoothDevice}. * Registration must be done when Bluetooth is ON and will last until - * {@link #unregisterMetadataListener(BluetoothDevice)} is called, even when Bluetooth + * {@link #removeOnMetadataChangedListener(BluetoothDevice)} is called, even when Bluetooth * restarted in the middle. * All input parameters should not be null or {@link NullPointerException} will be triggered. - * The same {@link BluetoothDevice} and {@link #MetadataListener} pair can only be registered - * once, double registration would cause {@link IllegalArgumentException}. + * The same {@link BluetoothDevice} and {@link #OnMetadataChangedListener} pair can only be + * registered once, double registration would cause {@link IllegalArgumentException}. * * @param device {@link BluetoothDevice} that will be registered - * @param listener {@link #MetadataListener} that will receive asynchronous callbacks - * @param handler the handler for listener callback + * @param executor the executor for listener callback + * @param listener {@link #OnMetadataChangedListener} that will receive asynchronous callbacks * @return true on success, false on error - * @throws NullPointerException If one of {@code listener}, {@code device} or {@code handler} + * @throws NullPointerException If one of {@code listener}, {@code device} or {@code executor} * is null. - * @throws IllegalArgumentException The same {@link #MetadataListener} and + * @throws IllegalArgumentException The same {@link #OnMetadataChangedListener} and * {@link BluetoothDevice} are registered twice. * @hide */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean registerMetadataListener(BluetoothDevice device, MetadataListener listener, - Handler handler) { - if (DBG) Log.d(TAG, "registerMetdataListener()"); + public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device, + @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) { + if (DBG) Log.d(TAG, "addOnMetadataChangedListener()"); final IBluetooth service = mService; if (service == null) { @@ -3189,14 +3191,15 @@ public final class BluetoothAdapter { if (device == null) { throw new NullPointerException("device is null"); } - if (handler == null) { - throw new NullPointerException("handler is null"); + if (executor == null) { + throw new NullPointerException("executor is null"); } synchronized (sMetadataListeners) { - List> listenerList = sMetadataListeners.get(device); + List> listenerList = + sMetadataListeners.get(device); if (listenerList == null) { - // Create new listener/handler list for registeration + // Create new listener/executor list for registeration listenerList = new ArrayList<>(); sMetadataListeners.put(device, listenerList); } else { @@ -3207,7 +3210,7 @@ public final class BluetoothAdapter { } } - Pair listenerPair = new Pair(listener, handler); + Pair listenerPair = new Pair(listener, executor); listenerList.add(listenerPair); boolean ret = false; @@ -3230,63 +3233,74 @@ public final class BluetoothAdapter { } /** - * Unregister all {@link MetadataListener} from this {@link BluetoothDevice}. + * Unregister a {@link #OnMetadataChangedListener} from a registered {@link BluetoothDevice}. * Unregistration can be done when Bluetooth is either ON or OFF. - * {@link #registerMetadataListener(MetadataListener, BluetoothDevice, Handler)} must - * be called before unregisteration. - * Unregistering a device that is not regestered would cause {@link IllegalArgumentException}. + * {@link #addOnMetadataChangedListener(OnMetadataChangedListener, BluetoothDevice, Executor)} + * must be called before unregisteration. * - * @param device {@link BluetoothDevice} that will be unregistered. it + * @param device {@link BluetoothDevice} that will be unregistered. It + * should not be null or {@link NullPointerException} will be triggered. + * @param listener {@link OnMetadataChangedListener} that will be unregistered. It * should not be null or {@link NullPointerException} will be triggered. * @return true on success, false on error - * @throws NullPointerException If {@code device} is null. + * @throws NullPointerException If {@code listener} or {@code device} is null. * @throws IllegalArgumentException If {@code device} has not been registered before. * @hide */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean unregisterMetadataListener(BluetoothDevice device) { - if (DBG) Log.d(TAG, "unregisterMetdataListener()"); + public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device, + @NonNull OnMetadataChangedListener listener) { + if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()"); if (device == null) { throw new NullPointerException("device is null"); } + if (listener == null) { + throw new NullPointerException("listener is null"); + } synchronized (sMetadataListeners) { - if (sMetadataListeners.containsKey(device)) { - sMetadataListeners.remove(device); - } else { + if (!sMetadataListeners.containsKey(device)) { throw new IllegalArgumentException("device was not registered"); } + // Remove issued listener from the registered device + sMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener))); - final IBluetooth service = mService; - if (service == null) { - // Bluetooth is OFF, do nothing to Bluetooth service. - return true; - } - try { - return service.unregisterMetadataListener(device); - } catch (RemoteException e) { - Log.e(TAG, "unregisterMetadataListener fail", e); - return false; + if (sMetadataListeners.get(device).isEmpty()) { + // Unregister to Bluetooth service if all listeners are removed from + // the registered device + sMetadataListeners.remove(device); + final IBluetooth service = mService; + if (service == null) { + // Bluetooth is OFF, do nothing to Bluetooth service. + return true; + } + try { + return service.unregisterMetadataListener(device); + } catch (RemoteException e) { + Log.e(TAG, "unregisterMetadataListener fail", e); + return false; + } } } + return true; } /** - * This abstract class is used to implement {@link BluetoothAdapter} metadata listener. + * This interface is used to implement {@link BluetoothAdapter} metadata listener. * @hide */ @SystemApi - public abstract static class MetadataListener { + public interface OnMetadataChangedListener { /** * Callback triggered if the metadata of {@link BluetoothDevice} registered in - * {@link #registerMetadataListener}. + * {@link #addOnMetadataChangedListener}. * * @param device changed {@link BluetoothDevice}. * @param key changed metadata key, one of BluetoothDevice.METADATA_*. - * @param value the new value of metadata. + * @param value the new value of metadata as byte array. */ - public void onMetadataChanged(BluetoothDevice device, int key, String value) { - } + void onMetadataChanged(@NonNull BluetoothDevice device, int key, + @Nullable byte[] value); } } -- cgit v1.2.3 From 147146fb21165bdf7812fa9745ca797b7d12b437 Mon Sep 17 00:00:00 2001 From: Andrei Onea Date: Mon, 17 Jun 2019 11:26:14 +0100 Subject: Document public alternatives to greylisted APIs Add known public alternatives or recommendations for greylisted APIs in Bluetooth. Bug: 135171386 Test: m Change-Id: I86e708be37eb7d1b0fafa2d64283b7f81bc02e51 --- framework/java/android/bluetooth/BluetoothAdapter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 31bbd16497..39d63de87d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1028,7 +1028,8 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH) @AdapterState - @UnsupportedAppUsage + @UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine " + + "whether you can use BLE & BT classic.") public int getLeState() { int state = BluetoothAdapter.STATE_OFF; @@ -1484,7 +1485,8 @@ public final class BluetoothAdapter { * @return true if the scan mode was set, false otherwise * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which " + + "shows UI that confirms the user wants to go into discoverable mode.") public boolean setScanMode(@ScanMode int mode, int duration) { if (getState() != STATE_ON) { return false; -- cgit v1.2.3 From 80b52652df3f3cb2f2d334b9e135ec9830d7bdc5 Mon Sep 17 00:00:00 2001 From: Dan Harms Date: Tue, 6 Aug 2019 09:18:02 -0700 Subject: Include BLE<->SPP transition states in isLeEnabled Fixes: 138997297 Test: Start scan while in transition and observe no exceptions Change-Id: Ib8b05c30c3db8e398194572a179028647e703a9f --- framework/java/android/bluetooth/BluetoothAdapter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 39d63de87d..e7ba85ad5d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -858,7 +858,10 @@ public final class BluetoothAdapter { if (DBG) { Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state)); } - return (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON); + return (state == BluetoothAdapter.STATE_ON + || state == BluetoothAdapter.STATE_BLE_ON + || state == BluetoothAdapter.STATE_TURNING_ON + || state == BluetoothAdapter.STATE_TURNING_OFF); } /** -- cgit v1.2.3 From 5eb1894128ce092c434706dcb6412419db6baeed Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Fri, 25 Oct 2019 13:15:12 -0700 Subject: Refactor BluetoothAdapter APIs used by Settings Bug: 143238544 Test: Manual Change-Id: Ia831d2b4b628b746493602857bcb54b585f13e12 --- .../java/android/bluetooth/BluetoothAdapter.java | 51 ++++++++++++++++------ 1 file changed, 37 insertions(+), 14 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e7ba85ad5d..566b38738d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1189,13 +1189,11 @@ public final class BluetoothAdapter { /** * Factory reset bluetooth settings. * - *

Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} - * permission - * * @return true to indicate that the config file was successfully cleared * @hide */ - @UnsupportedAppUsage + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean factoryReset() { try { mServiceLock.readLock().lock(); @@ -1214,13 +1212,12 @@ public final class BluetoothAdapter { /** * Get the UUIDs supported by the local Bluetooth adapter. * - *

Requires {@link android.Manifest.permission#BLUETOOTH} - * * @return the UUIDs supported by the local Bluetooth Adapter. * @hide */ @UnsupportedAppUsage - public ParcelUuid[] getUuids() { + @RequiresPermission(Manifest.permission.BLUETOOTH) + public @NonNull ParcelUuid[] getUuids() { if (getState() != STATE_ON) { return null; } @@ -1476,7 +1473,6 @@ public final class BluetoothAdapter { * will return false. After turning on Bluetooth, * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} * to get the updated value. - *

Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} *

Applications cannot set the scan mode. They should use * startActivityForResult( * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) @@ -1488,8 +1484,8 @@ public final class BluetoothAdapter { * @return true if the scan mode was set, false otherwise * @hide */ - @UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which " - + "shows UI that confirms the user wants to go into discoverable mode.") + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean setScanMode(@ScanMode int mode, int duration) { if (getState() != STATE_ON) { return false; @@ -1507,9 +1503,34 @@ public final class BluetoothAdapter { return false; } - /** @hide */ - @UnsupportedAppUsage - public boolean setScanMode(int mode) { + /** + * Set the Bluetooth scan mode of the local Bluetooth adapter. + *

The Bluetooth scan mode determines if the local adapter is + * connectable and/or discoverable from remote Bluetooth devices. + *

For privacy reasons, discoverable mode is automatically turned off + * after duration seconds. For example, 120 seconds should be + * enough for a remote device to initiate and complete its discovery + * process. + *

Valid scan mode values are: + * {@link #SCAN_MODE_NONE}, + * {@link #SCAN_MODE_CONNECTABLE}, + * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. + *

If Bluetooth state is not {@link #STATE_ON}, this API + * will return false. After turning on Bluetooth, + * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} + * to get the updated value. + *

Applications cannot set the scan mode. They should use + * startActivityForResult( + * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) + * instead. + * + * @param mode valid scan mode + * @return true if the scan mode was set, false otherwise + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH) + public boolean setScanMode(@ScanMode int mode) { if (getState() != STATE_ON) { return false; } @@ -1562,6 +1583,8 @@ public final class BluetoothAdapter { * been called recently. * @hide */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH) public long getDiscoveryEndMillis() { try { mServiceLock.readLock().lock(); @@ -2060,7 +2083,7 @@ public final class BluetoothAdapter { * BluetoothProfile}. * @hide */ - public List getSupportedProfiles() { + public @NonNull List getSupportedProfiles() { final ArrayList supportedProfiles = new ArrayList(); try { -- cgit v1.2.3 From 634b8b303b1c8d3e56a9fff79a7528a7856ab2b7 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Wed, 13 Nov 2019 16:21:12 -0800 Subject: Create systemapis to connect/disconnect all bt profiles Bug: 143495377 Test: Manual Change-Id: I80d816083ef568df319afddfd4557ef74d37d16f --- .../java/android/bluetooth/BluetoothAdapter.java | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 566b38738d..9d152a7faf 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1733,6 +1733,56 @@ public final class BluetoothAdapter { return false; } + /** + * Connects all enabled and supported bluetooth profiles between the local and remote device + * + * @param device is the remote device with which to connect these profiles + * @return true if all profiles successfully connected, false if an error occurred + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.connectAllEnabledProfiles(device); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + + return false; + } + + /** + * Disconnects all enabled and supported bluetooth profiles between the local and remote device + * + * @param device is the remote device with which to disconnect these profiles + * @return true if all profiles successfully disconnected, false if an error occurred + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.disconnectAllEnabledProfiles(device); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + + return false; + } + /** * Return true if the multi advertisement is supported by the chipset * -- cgit v1.2.3 From b997c1f1fa16b9658adfb10a770dc9b1baedb018 Mon Sep 17 00:00:00 2001 From: Zach Johnson Date: Tue, 26 Nov 2019 21:30:07 -0800 Subject: Implement isEnabled in terms of getState Bug: 145171640 Test: compile & check everything works normally Change-Id: I169e220ab83546d76317e518652c66c9bd2229a2 --- framework/java/android/bluetooth/BluetoothAdapter.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 9d152a7faf..6ec942c07f 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -830,18 +830,7 @@ public final class BluetoothAdapter { */ @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean isEnabled() { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isEnabled(); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - - return false; + return getState() == BluetoothAdapter.STATE_ON; } /** -- cgit v1.2.3 From e8bac9b871a87aa38e99956c380069c3c377eb79 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Wed, 27 Nov 2019 18:09:33 -0800 Subject: Rename priority to connection policy in bluetooth apis Bug: 145005327 Test: Manual Change-Id: I43ad57feb7dd70f39005ad7a01bc7dac6fb7b639 --- .../java/android/bluetooth/BluetoothAdapter.java | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 9d152a7faf..9d6be568a2 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -27,6 +27,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.bluetooth.BluetoothProfile.ConnectionPolicy; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.PeriodicAdvertisingManager; @@ -3381,4 +3382,48 @@ public final class BluetoothAdapter { void onMetadataChanged(@NonNull BluetoothDevice device, int key, @Nullable byte[] value); } + + /** + * Converts old constant of priority to the new for connection policy + * + * @param priority is the priority to convert to connection policy + * @return the equivalent connection policy constant to the priority + * + * @hide + */ + public static @ConnectionPolicy int priorityToConnectionPolicy(int priority) { + switch(priority) { + case BluetoothProfile.PRIORITY_AUTO_CONNECT: + return BluetoothProfile.CONNECTION_POLICY_ALLOWED; + case BluetoothProfile.PRIORITY_ON: + return BluetoothProfile.CONNECTION_POLICY_ALLOWED; + case BluetoothProfile.PRIORITY_OFF: + return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; + case BluetoothProfile.PRIORITY_UNDEFINED: + return BluetoothProfile.CONNECTION_POLICY_UNKNOWN; + default: + Log.e(TAG, "setPriority: Invalid priority: " + priority); + return BluetoothProfile.CONNECTION_POLICY_UNKNOWN; + } + } + + /** + * Converts new constant of connection policy to the old for priority + * + * @param connectionPolicy is the connection policy to convert to priority + * @return the equivalent priority constant to the connectionPolicy + * + * @hide + */ + public static int connectionPolicyToPriority(@ConnectionPolicy int connectionPolicy) { + switch(connectionPolicy) { + case BluetoothProfile.CONNECTION_POLICY_ALLOWED: + return BluetoothProfile.PRIORITY_ON; + case BluetoothProfile.CONNECTION_POLICY_FORBIDDEN: + return BluetoothProfile.PRIORITY_OFF; + case BluetoothProfile.CONNECTION_POLICY_UNKNOWN: + return BluetoothProfile.PRIORITY_UNDEFINED; + } + return BluetoothProfile.PRIORITY_UNDEFINED; + } } -- cgit v1.2.3 From 4a9070a30ac81d1cfdcd4162ad55e48f7b10d582 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Mon, 25 Nov 2019 11:16:10 -0800 Subject: Add SystemApi to setActiveDevice in BluetoothAdapter Bug: 145004683 Test: Manual Change-Id: I70f46bb0153a8a0f3755dc2b3e26e556bd092daa --- .../java/android/bluetooth/BluetoothAdapter.java | 66 ++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 9d152a7faf..89f9cbc048 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -456,6 +456,37 @@ public final class BluetoothAdapter { @Retention(RetentionPolicy.SOURCE) public @interface IoCapability {} + /** @hide */ + @IntDef(prefix = "ACTIVE_DEVICE_", value = {ACTIVE_DEVICE_AUDIO, + ACTIVE_DEVICE_PHONE_CALL, ACTIVE_DEVICE_ALL}) + @Retention(RetentionPolicy.SOURCE) + public @interface ActiveDeviceUse {} + + /** + * Use the specified device for audio (a2dp and hearing aid profile) + * + * @hide + */ + @SystemApi + public static final int ACTIVE_DEVICE_AUDIO = 0; + + /** + * Use the specified device for phone calls (headset profile and hearing + * aid profile) + * + * @hide + */ + @SystemApi + public static final int ACTIVE_DEVICE_PHONE_CALL = 1; + + /** + * Use the specified device for a2dp, hearing aid profile, and headset profile + * + * @hide + */ + @SystemApi + public static final int ACTIVE_DEVICE_ALL = 2; + /** * Broadcast Action: The local Bluetooth adapter has started the remote * device discovery process. @@ -1733,6 +1764,41 @@ public final class BluetoothAdapter { return false; } + /** + * + * @param device is the remote bluetooth device + * @param profiles represents the purpose for which we are setting this as the active device. + * Possible values are: + * {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO}, + * {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL}, + * {@link BluetoothAdapter#ACTIVE_DEVICE_ALL} + * @return false on immediate error, true otherwise + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public boolean setActiveDevice(@Nullable BluetoothDevice device, + @ActiveDeviceUse int profiles) { + if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL + && profiles != ACTIVE_DEVICE_ALL) { + Log.e(TAG, "Invalid profiles param value in setActiveDevice"); + return false; + } + + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.setActiveDevice(device, profiles); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + + return false; + } + /** * Connects all enabled and supported bluetooth profiles between the local and remote device * -- cgit v1.2.3 From 658617b40f1526657c0ad59a406068af78598ccb Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Fri, 15 Nov 2019 12:41:09 -0800 Subject: Pipe featureId from app to noteOp in BT code FeatureIds are not yet available, hence in BTManager we assume always a "null" featureId. The effect of this change is that for apps that opt into using featureIds, they will have one BluetoothAdapter per feature, not one per process as before. In my testing this caused no problem. Most apps won't use featureIds, hence for most apps there is no change in behavior. Test: used bluetooth Bug: 136595429 Change-Id: Ic40326ea331c60f764f213bb2673cb4c49a81604 --- framework/java/android/bluetooth/BluetoothAdapter.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3f8cb627e3..291d1d99fd 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -847,7 +847,8 @@ public final class BluetoothAdapter { } synchronized (mLock) { if (sBluetoothLeScanner == null) { - sBluetoothLeScanner = new BluetoothLeScanner(mManagerService); + sBluetoothLeScanner = new BluetoothLeScanner(mManagerService, getOpPackageName(), + getFeatureId()); } } return sBluetoothLeScanner; @@ -1637,6 +1638,15 @@ public final class BluetoothAdapter { return ActivityThread.currentOpPackageName(); } + private String getFeatureId() { + // Workaround for legacy API for getting a BluetoothAdapter not + // passing a context + if (mContext != null) { + return null; + } + return null; + } + /** * Start the remote device discovery process. *

The discovery process usually involves an inquiry scan of about 12 @@ -1674,7 +1684,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.startDiscovery(getOpPackageName()); + return mService.startDiscovery(getOpPackageName(), getFeatureId()); } } catch (RemoteException e) { Log.e(TAG, "", e); -- cgit v1.2.3 From a188ac2ea6791550982fa6a3bf3636eb0d050b80 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Fri, 15 Nov 2019 12:41:09 -0800 Subject: Pipe featureId from app to noteOp in BT code Test: atest CtsAppOpsTestCases (Now with canary test for this code) Bug: 136595429 Change-Id: I90bb6b017da4f03038fce76760a860390b727f00 --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 291d1d99fd..8404705633 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1642,7 +1642,7 @@ public final class BluetoothAdapter { // Workaround for legacy API for getting a BluetoothAdapter not // passing a context if (mContext != null) { - return null; + return mContext.getFeatureId(); } return null; } -- cgit v1.2.3 From cb33332a4259dc9e5cc3833cd3d38c1caa165c7b Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Tue, 10 Dec 2019 17:47:52 +0000 Subject: Use new UnsupportedAppUsage annotation. Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library. Bug: 145132366 Test: m && diff unsupportedappusage_index.csv Change-Id: I6ab53570aca580fbee1fcc927871caa09780f58f --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8404705633..b1b6f0d61f 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -25,7 +25,6 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.bluetooth.BluetoothProfile.ConnectionPolicy; import android.bluetooth.le.BluetoothLeAdvertiser; @@ -36,6 +35,7 @@ import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.BatteryStats; import android.os.Binder; -- cgit v1.2.3 From 5cd5a06efa7942b232f2a5c934150d635080ef18 Mon Sep 17 00:00:00 2001 From: Chienyuan Date: Wed, 8 Jan 2020 17:50:08 +0800 Subject: Support PBAP for get/close profile proxy Bug: 147078847 Test: manual Change-Id: Iabcf9ab81b052be8f6f7388843681450a1cd7da4 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 291d1d99fd..220b77b299 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2670,6 +2670,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.PAN) { BluetoothPan pan = new BluetoothPan(context, listener); return true; + } else if (profile == BluetoothProfile.PBAP) { + BluetoothPbap pbap = new BluetoothPbap(context, listener); + return true; } else if (profile == BluetoothProfile.HEALTH) { Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated"); return false; @@ -2742,6 +2745,10 @@ public final class BluetoothAdapter { BluetoothPan pan = (BluetoothPan) proxy; pan.close(); break; + case BluetoothProfile.PBAP: + BluetoothPbap pbap = (BluetoothPbap) proxy; + pbap.close(); + break; case BluetoothProfile.GATT: BluetoothGatt gatt = (BluetoothGatt) proxy; gatt.close(); -- cgit v1.2.3 From 3625be4eb7d52fe10c659b649d945a4cea0d0beb Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Tue, 10 Dec 2019 17:47:52 +0000 Subject: Use new UnsupportedAppUsage annotation. Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library. Bug: 145132366 Test: m && diff unsupportedappusage_index.csv Change-Id: I6ab53570aca580fbee1fcc927871caa09780f58f Merged-In: I6ab53570aca580fbee1fcc927871caa09780f58f --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 220b77b299..1869c6fa76 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -25,7 +25,6 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.bluetooth.BluetoothProfile.ConnectionPolicy; import android.bluetooth.le.BluetoothLeAdvertiser; @@ -36,6 +35,7 @@ import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.BatteryStats; import android.os.Binder; -- cgit v1.2.3 From 7a0602e3d45617e7e51f93dec7d0c00aeab45b6f Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Fri, 17 Jan 2020 15:09:44 -0800 Subject: Add error log to BluetoothAdapter.factoryReset() and make BluetoothAdapter.getUuids() marked with @Nullable Bug: 144765076 Test: Manual Change-Id: I2a38fbb2256177ad29e2739ccbec8c13aae9df6a --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 220b77b299..57ccaa83ae 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1222,6 +1222,7 @@ public final class BluetoothAdapter { if (mService != null) { return mService.factoryReset(); } + Log.e(TAG, "factoryReset(): IBluetooth Service is null"); SystemProperties.set("persist.bluetooth.factoryreset", "true"); } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1239,7 +1240,7 @@ public final class BluetoothAdapter { */ @UnsupportedAppUsage @RequiresPermission(Manifest.permission.BLUETOOTH) - public @NonNull ParcelUuid[] getUuids() { + public @Nullable ParcelUuid[] getUuids() { if (getState() != STATE_ON) { return null; } -- cgit v1.2.3 From 2a9950384b458e76ee998559590fef7b7e14a17f Mon Sep 17 00:00:00 2001 From: Hansong Zhang Date: Thu, 19 Dec 2019 16:09:20 -0800 Subject: Bluetooth LE COC: Delete unused testing API Some methods are for SL4A test only, and now they have been migrated. Test: compile Change-Id: I86e22814fc9a3fd296c359804a465b9ead4d926f --- .../java/android/bluetooth/BluetoothAdapter.java | 25 ---------------------- 1 file changed, 25 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index bd0a39c06b..8415ecd38b 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3235,18 +3235,6 @@ public final class BluetoothAdapter { return socket; } - /** - * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new - * API name, listenUsingL2capChannel. - * @hide - */ - @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothServerSocket listenUsingL2capCoc(int transport) - throws IOException { - Log.e(TAG, "listenUsingL2capCoc: PLEASE USE THE OFFICIAL API, listenUsingL2capChannel"); - return listenUsingL2capChannel(); - } - /** * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The @@ -3293,19 +3281,6 @@ public final class BluetoothAdapter { return socket; } - /** - * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new - * API name, listenUsingInsecureL2capChannel. - * @hide - */ - @RequiresPermission(Manifest.permission.BLUETOOTH) - public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport) - throws IOException { - Log.e(TAG, "listenUsingInsecureL2capCoc: PLEASE USE THE OFFICIAL API, " - + "listenUsingInsecureL2capChannel"); - return listenUsingInsecureL2capChannel(); - } - /** * Register a {@link #OnMetadataChangedListener} to receive update about metadata * changes for this {@link BluetoothDevice}. -- cgit v1.2.3 From 8b5b3b2ed91abad0a081f509c0bc23c8b3181aaa Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Wed, 29 Jan 2020 11:53:10 -0800 Subject: Add api BluetoothAdapter.getMostRecentlyConnectedDevices() to be able to get connected devices ordered by how recently they were connected Bug: 130984590 Test: Manual Change-Id: Ie5d0c7a8e6bc5daad5ff14064b0c65b7c4c5e6b0 --- .../java/android/bluetooth/BluetoothAdapter.java | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8415ecd38b..b6d096c252 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2161,6 +2161,33 @@ public final class BluetoothAdapter { } } + /** + * Fetches a list of the most recently connected bluetooth devices ordered by how recently they + * were connected with most recently first and least recently last + * + * @return {@link List} of bonded {@link BluetoothDevice} ordered by how recently they were + * connected + * + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + public @NonNull List getMostRecentlyConnectedDevices() { + if (getState() != STATE_ON) { + return new ArrayList<>(); + } + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.getMostRecentlyConnectedDevices(); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + return new ArrayList<>(); + } + /** * Return the set of {@link BluetoothDevice} objects that are bonded * (paired) to the local adapter. -- cgit v1.2.3 From 5358c2101682f6179c8826b8a7fb1e170c3f66d1 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Thu, 30 Jan 2020 16:59:02 -0800 Subject: Add new API BluetoothAdapter#removeActiveDevice to replace calls to BluetoothAdapter#setActiveDevice with a null device Bug: 147428526 Test: Manual Change-Id: I838448a504515d5a8b1eec254ccc1d9414239475 --- .../java/android/bluetooth/BluetoothAdapter.java | 55 ++++++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b6d096c252..3bc83dbcd0 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1766,6 +1766,45 @@ public final class BluetoothAdapter { } /** + * Removes the active device for the grouping of @ActiveDeviceUse specified + * + * @param profiles represents the purpose for which we are setting this as the active device. + * Possible values are: + * {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO}, + * {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL}, + * {@link BluetoothAdapter#ACTIVE_DEVICE_ALL} + * @return false on immediate error, true otherwise + * @throws IllegalArgumentException if device is null or profiles is not one of + * {@link ActiveDeviceUse} + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean removeActiveDevice(@ActiveDeviceUse int profiles) { + if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL + && profiles != ACTIVE_DEVICE_ALL) { + Log.e(TAG, "Invalid profiles param value in removeActiveDevice"); + throw new IllegalArgumentException("Profiles must be one of " + + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, " + + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or " + + "BluetoothAdapter.ACTIVE_DEVICE_ALL"); + } + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.removeActiveDevice(profiles); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + + return false; + } + + /** + * Sets device as the active devices for the profiles passed into the function * * @param device is the remote bluetooth device * @param profiles represents the purpose for which we are setting this as the active device. @@ -1774,18 +1813,26 @@ public final class BluetoothAdapter { * {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL}, * {@link BluetoothAdapter#ACTIVE_DEVICE_ALL} * @return false on immediate error, true otherwise + * @throws IllegalArgumentException if device is null or profiles is not one of + * {@link ActiveDeviceUse} * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) - public boolean setActiveDevice(@Nullable BluetoothDevice device, + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean setActiveDevice(@NonNull BluetoothDevice device, @ActiveDeviceUse int profiles) { + if (device == null) { + Log.e(TAG, "setActiveDevice: Null device passed as parameter"); + throw new IllegalArgumentException("device cannot be null"); + } if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL && profiles != ACTIVE_DEVICE_ALL) { Log.e(TAG, "Invalid profiles param value in setActiveDevice"); - return false; + throw new IllegalArgumentException("Profiles must be one of " + + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, " + + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or " + + "BluetoothAdapter.ACTIVE_DEVICE_ALL"); } - try { mServiceLock.readLock().lock(); if (mService != null) { -- cgit v1.2.3 From 2e2758221e5f4a9b727aa6afdeff77415edb81a8 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Fri, 31 Jan 2020 11:40:15 -0800 Subject: Change data type of duration param from int representing seconds to long representing milliseconds in BluetoothAdapter#setScanMode Bug: 144380530 Test: Manual Change-Id: I76528478a64d22afefd4ec964d1a78295dd3c94f --- .../java/android/bluetooth/BluetoothAdapter.java | 33 +++++++++++++++------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3bc83dbcd0..56424c9f5a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1485,9 +1485,8 @@ public final class BluetoothAdapter { *

The Bluetooth scan mode determines if the local adapter is * connectable and/or discoverable from remote Bluetooth devices. *

For privacy reasons, discoverable mode is automatically turned off - * after duration seconds. For example, 120 seconds should be - * enough for a remote device to initiate and complete its discovery - * process. + * after durationMillis milliseconds. For example, 120000 milliseconds should be + * enough for a remote device to initiate and complete its discovery process. *

Valid scan mode values are: * {@link #SCAN_MODE_NONE}, * {@link #SCAN_MODE_CONNECTABLE}, @@ -1502,24 +1501,29 @@ public final class BluetoothAdapter { * instead. * * @param mode valid scan mode - * @param duration time in seconds to apply scan mode, only used for {@link + * @param durationMillis time in milliseconds to apply scan mode, only used for {@link * #SCAN_MODE_CONNECTABLE_DISCOVERABLE} * @return true if the scan mode was set, false otherwise * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH) - public boolean setScanMode(@ScanMode int mode, int duration) { + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean setScanMode(@ScanMode int mode, long durationMillis) { if (getState() != STATE_ON) { return false; } try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.setScanMode(mode, duration); + int durationSeconds = Math.toIntExact(durationMillis / 1000); + return mService.setScanMode(mode, durationSeconds); } } catch (RemoteException e) { Log.e(TAG, "", e); + } catch (ArithmeticException ex) { + Log.e(TAG, "setScanMode: Duration in seconds outside of the bounds of an int"); + throw new IllegalArgumentException("Duration not in bounds. In seconds, the " + + "durationMillis must be in the range of an int"); } finally { mServiceLock.readLock().unlock(); } @@ -1552,13 +1556,22 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setScanMode(@ScanMode int mode) { if (getState() != STATE_ON) { return false; } - /* getDiscoverableTimeout() to use the latest from NV than use 0 */ - return setScanMode(mode, getDiscoverableTimeout()); + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.setScanMode(mode, getDiscoverableTimeout()); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; } /** @hide */ -- cgit v1.2.3 From 71b54554e6d291e688ad24d76fe06e0a07a11c7d Mon Sep 17 00:00:00 2001 From: Lee Shombert Date: Mon, 30 Dec 2019 10:57:12 -0800 Subject: Binder cache for Bluetooth getState(). Bug: 140788621 Test: A special build that puts the PropertyInvalidatedCache in verification mode was loaded on the device. Then one iteration of MPTS was executed. No cache inconsistencies were found and no SELinux violations (associated with the binder cache) were found. The number of cache misses was approximately 3% of the total binder calls. All binder calls went through the cache. Repeated the test with a work profile installed (to provide a second user ID). Change-Id: I2f1d0b6d61dedc5d1badb06a20c5932eca415904 --- .../java/android/bluetooth/BluetoothAdapter.java | 58 +++++++++++++--------- 1 file changed, 34 insertions(+), 24 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 2e93d43f7c..f39847429a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -26,6 +26,7 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.app.ActivityThread; +import android.app.PropertyInvalidatedCache; import android.bluetooth.BluetoothProfile.ConnectionPolicy; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; @@ -994,6 +995,37 @@ public final class BluetoothAdapter { return false; } + private static final String BLUETOOTH_GET_STATE_CACHE_PROPERTY = "cache_key.bluetooth.get_state"; + + private final PropertyInvalidatedCache mBluetoothGetStateCache = + new PropertyInvalidatedCache( + 8, BLUETOOTH_GET_STATE_CACHE_PROPERTY) { + @Override + protected Integer recompute(Void query) { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.getState(); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + return BluetoothAdapter.STATE_OFF; + } + }; + + /** @hide */ + public void disableBluetoothGetStateCache() { + mBluetoothGetStateCache.disableLocal(); + } + + /** @hide */ + public static void invalidateBluetoothGetStateCache() { + PropertyInvalidatedCache.invalidateCache(BLUETOOTH_GET_STATE_CACHE_PROPERTY); + } + /** * Get the current state of the local Bluetooth adapter. *

Possible return values are @@ -1007,18 +1039,7 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) @AdapterState public int getState() { - int state = BluetoothAdapter.STATE_OFF; - - try { - mServiceLock.readLock().lock(); - if (mService != null) { - state = mService.getState(); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } + int state = mBluetoothGetStateCache.query(null); // Consider all internal states as OFF if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON @@ -1056,18 +1077,7 @@ public final class BluetoothAdapter { @UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine " + "whether you can use BLE & BT classic.") public int getLeState() { - int state = BluetoothAdapter.STATE_OFF; - - try { - mServiceLock.readLock().lock(); - if (mService != null) { - state = mService.getState(); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } + int state = mBluetoothGetStateCache.query(null); if (VDBG) { Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state)); -- cgit v1.2.3 From 3da3b7a21ab53068b194c1fd54ce6c8c2374196d Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Wed, 5 Feb 2020 14:03:19 -0800 Subject: BluetoothAdapter#connectAllEnabledProfiles and BluetoothAdapter#disconnectAllEnabledProfiles updated to require BLUETOOTH_PRIVILEGED permission and update documentation to indicate connection and disconnection is asynchronous Bug: 147321746 Test: Manual Change-Id: I961f02a539a247b1397ce4f478b9dc804d9973ab --- .../java/android/bluetooth/BluetoothAdapter.java | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 56424c9f5a..0a9dbb608b 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1861,15 +1861,19 @@ public final class BluetoothAdapter { } /** - * Connects all enabled and supported bluetooth profiles between the local and remote device + * Connects all enabled and supported bluetooth profiles between the local and remote device. + * Connection is asynchronous and you should listen to each profile's broadcast intent + * ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful. For example, + * to verify a2dp is connected, you would listen for + * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} * * @param device is the remote device with which to connect these profiles - * @return true if all profiles successfully connected, false if an error occurred + * @return true if message sent to try to connect all profiles, false if an error occurred * * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) { try { mServiceLock.readLock().lock(); @@ -1886,15 +1890,19 @@ public final class BluetoothAdapter { } /** - * Disconnects all enabled and supported bluetooth profiles between the local and remote device + * Disconnects all enabled and supported bluetooth profiles between the local and remote device. + * Disconnection is asynchronous and you should listen to each profile's broadcast intent + * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example, + * to verify a2dp is disconnected, you would listen for + * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} * * @param device is the remote device with which to disconnect these profiles - * @return true if all profiles successfully disconnected, false if an error occurred + * @return true if message sent to try to disconnect all profiles, false if an error occurred * * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) { try { mServiceLock.readLock().lock(); -- cgit v1.2.3 From 3b91300c6368be029c1616b9d0e8ab1c724e8658 Mon Sep 17 00:00:00 2001 From: Lee Shombert Date: Mon, 30 Dec 2019 11:54:37 -0800 Subject: Binder caches for Bluetooth * A cache for isOffloadedFilteringSupported(). * A cache for getProfileConnectionState(). Bug: 140788621 Test: A special build that puts the PropertyInvalidatedCache in verification mode was loaded on the device. Then one iteration of MPTS was executed. No cache inconsistencies were found and no SELinux violations (associated with the binder cache) were found. The number of cache misses was approximately 15% of the total binder calls. A second test was run in which bluetooth headphones were connected and disconnected. Then bluetooth itself was disabled and then enabled. The caches were invalidated as expected and no errors were uncovered. Change-Id: Icfad1071725e2d1e320fd252a49f0c4ae8ce6ad0 --- .../java/android/bluetooth/BluetoothAdapter.java | 93 +++++++++++++++++----- 1 file changed, 71 insertions(+), 22 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 587c92e014..66bfcbd27c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1970,6 +1970,38 @@ public final class BluetoothAdapter { } } + private static final String BLUETOOTH_FILTERING_CACHE_PROPERTY = + "cache_key.bluetooth.is_offloaded_filtering_supported"; + private final PropertyInvalidatedCache mBluetoothFilteringCache = + new PropertyInvalidatedCache( + 8, BLUETOOTH_FILTERING_CACHE_PROPERTY) { + @Override + protected Boolean recompute(Void query) { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.isOffloadedFilteringSupported(); + } + } catch (RemoteException e) { + Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; + + } + }; + + /** @hide */ + public void disableIsOffloadedFilteringSupportedCache() { + mBluetoothFilteringCache.disableLocal(); + } + + /** @hide */ + public static void invalidateIsOffloadedFilteringSupportedCache() { + PropertyInvalidatedCache.invalidateCache(BLUETOOTH_FILTERING_CACHE_PROPERTY); + } + /** * Return true if offloaded filters are supported * @@ -1979,17 +2011,7 @@ public final class BluetoothAdapter { if (!getLeAccess()) { return false; } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.isOffloadedFilteringSupported(); - } - } catch (RemoteException e) { - Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); - } finally { - mServiceLock.readLock().unlock(); - } - return false; + return mBluetoothFilteringCache.query(null); } /** @@ -2361,6 +2383,43 @@ public final class BluetoothAdapter { return BluetoothAdapter.STATE_DISCONNECTED; } + private static final String BLUETOOTH_PROFILE_CACHE_PROPERTY = + "cache_key.bluetooth.get_profile_connection_state"; + private final PropertyInvalidatedCache + mGetProfileConnectionStateCache = + new PropertyInvalidatedCache( + 8, BLUETOOTH_PROFILE_CACHE_PROPERTY) { + @Override + protected Integer recompute(Integer query) { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.getProfileConnectionState(query); + } + } catch (RemoteException e) { + Log.e(TAG, "getProfileConnectionState:", e); + } finally { + mServiceLock.readLock().unlock(); + } + return BluetoothProfile.STATE_DISCONNECTED; + } + @Override + public String queryToString(Integer query) { + return String.format("getProfileConnectionState(profile=\"%d\")", + query); + } + }; + + /** @hide */ + public void disableGetProfileConnectionStateCache() { + mGetProfileConnectionStateCache.disableLocal(); + } + + /** @hide */ + public static void invalidateGetProfileConnectionStateCache() { + PropertyInvalidatedCache.invalidateCache(BLUETOOTH_PROFILE_CACHE_PROPERTY); + } + /** * Get the current connection state of a profile. * This function can be used to check whether the local Bluetooth adapter @@ -2378,17 +2437,7 @@ public final class BluetoothAdapter { if (getState() != STATE_ON) { return BluetoothProfile.STATE_DISCONNECTED; } - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getProfileConnectionState(profile); - } - } catch (RemoteException e) { - Log.e(TAG, "getProfileConnectionState:", e); - } finally { - mServiceLock.readLock().unlock(); - } - return BluetoothProfile.STATE_DISCONNECTED; + return mGetProfileConnectionStateCache.query(new Integer(profile)); } /** -- cgit v1.2.3 From e18a909013a8f521a0876ab5fd67c2ec8d151323 Mon Sep 17 00:00:00 2001 From: weichinweng Date: Thu, 5 Mar 2020 10:37:44 +0800 Subject: Fix bluetooth can't turn off during network reset (2/3) Remove disable Bluetooth action from AdapterService and move to BluetoothManagerService. Add factory reset reason into Bluetooth enable/disable reason list. Bug: 110181479 Test: manual Change-Id: I4bff3c3bb75fbb0d1e13c459c0d9d3fd3b8b3195 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 66bfcbd27c..6ae68fcad6 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1229,10 +1229,11 @@ public final class BluetoothAdapter { public boolean factoryReset() { try { mServiceLock.readLock().lock(); - if (mService != null) { - return mService.factoryReset(); + if (mService != null && mService.factoryReset() + && mManagerService != null && mManagerService.onFactoryReset()) { + return true; } - Log.e(TAG, "factoryReset(): IBluetooth Service is null"); + Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later"); SystemProperties.set("persist.bluetooth.factoryreset", "true"); } catch (RemoteException e) { Log.e(TAG, "", e); -- cgit v1.2.3 From f0d36b80b84aace92542ef0f059184b4a6309cf1 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Thu, 5 Mar 2020 15:01:29 -0800 Subject: Rename featureId -> attributionTag In the core functionality this changes everything including aidl's and field names: - Context - ContentProvider - AppOps* - Package parsing For the rest, this is a shallow change to only change to the changed APIs. This keeps the change small-ish Exempt-From-Owner-Approval: Rename Fixes: 148792795 Test: TH Change-Id: I2a2245fe76e09e62cb13d5785d2efb4a304ba54a Merged-In: I2a2245fe76e09e62cb13d5785d2efb4a304ba54a --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 6ae68fcad6..608b563bfc 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -849,7 +849,7 @@ public final class BluetoothAdapter { synchronized (mLock) { if (sBluetoothLeScanner == null) { sBluetoothLeScanner = new BluetoothLeScanner(mManagerService, getOpPackageName(), - getFeatureId()); + getAttributionTag()); } } return sBluetoothLeScanner; @@ -1663,11 +1663,11 @@ public final class BluetoothAdapter { return ActivityThread.currentOpPackageName(); } - private String getFeatureId() { + private String getAttributionTag() { // Workaround for legacy API for getting a BluetoothAdapter not // passing a context if (mContext != null) { - return mContext.getFeatureId(); + return mContext.getAttributionTag(); } return null; } @@ -1709,7 +1709,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.startDiscovery(getOpPackageName(), getFeatureId()); + return mService.startDiscovery(getOpPackageName(), getAttributionTag()); } } catch (RemoteException e) { Log.e(TAG, "", e); -- cgit v1.2.3 From e466ff5d119d7ad9913e98203a92adc2fe875af2 Mon Sep 17 00:00:00 2001 From: weichinweng Date: Thu, 5 Mar 2020 10:37:44 +0800 Subject: Fix bluetooth can't turn off during network reset (2/3) Remove disable Bluetooth action from AdapterService and move to BluetoothManagerService. Add factory reset reason into Bluetooth enable/disable reason list. Bug: 110181479 Test: manual Change-Id: I4bff3c3bb75fbb0d1e13c459c0d9d3fd3b8b3195 Merged-In: I4bff3c3bb75fbb0d1e13c459c0d9d3fd3b8b3195 (cherry picked from commit e18a909013a8f521a0876ab5fd67c2ec8d151323) --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 0a9dbb608b..80f901bcce 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1219,10 +1219,11 @@ public final class BluetoothAdapter { public boolean factoryReset() { try { mServiceLock.readLock().lock(); - if (mService != null) { - return mService.factoryReset(); + if (mService != null && mService.factoryReset() + && mManagerService != null && mManagerService.onFactoryReset()) { + return true; } - Log.e(TAG, "factoryReset(): IBluetooth Service is null"); + Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later"); SystemProperties.set("persist.bluetooth.factoryreset", "true"); } catch (RemoteException e) { Log.e(TAG, "", e); -- cgit v1.2.3 From ce594994e8aa1b4bf9a6917e18c4f2f3b68c1ddc Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Wed, 18 Mar 2020 17:46:33 -0700 Subject: Add BLUETOOTH_PRIVILEGED permission as a requirement for all new Bluetooth SystemApis and for hidden connect/disconnect APIs. Hide some APIs that were previously marked as @UnsupportedAppUsage and re-add annotation as changing the permissions for these SystemApis would break the unsupported app contract that was previously there. Therefore, we're choosing to hide them until we have a good story on how to deal with them next release. Bug: 148689314 Test: Manual Change-Id: I33ee2c7ccd3827db3d23d6447cf82d9ffc36836a --- framework/java/android/bluetooth/BluetoothAdapter.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 608b563bfc..4aad3cbb21 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1224,7 +1224,7 @@ public final class BluetoothAdapter { * @return true to indicate that the config file was successfully cleared * @hide */ - @SystemApi + @UnsupportedAppUsage @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean factoryReset() { try { @@ -1517,8 +1517,9 @@ public final class BluetoothAdapter { * @return true if the scan mode was set, false otherwise * @hide */ - @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which " + + "shows UI that confirms the user wants to go into discoverable mode.") + @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean setScanMode(@ScanMode int mode, long durationMillis) { if (getState() != STATE_ON) { return false; @@ -1566,8 +1567,8 @@ public final class BluetoothAdapter { * @return true if the scan mode was set, false otherwise * @hide */ - @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @UnsupportedAppUsage + @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean setScanMode(@ScanMode int mode) { if (getState() != STATE_ON) { return false; @@ -1631,7 +1632,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public long getDiscoveryEndMillis() { try { mServiceLock.readLock().lock(); @@ -1883,7 +1884,6 @@ public final class BluetoothAdapter { * * @hide */ - @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) { try { @@ -1912,7 +1912,6 @@ public final class BluetoothAdapter { * * @hide */ - @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) { try { -- cgit v1.2.3 From c228ce27e2d7fe26193236eb5d4299214deb17ec Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Wed, 18 Mar 2020 17:46:33 -0700 Subject: Add BLUETOOTH_PRIVILEGED permission as a requirement for all new Bluetooth SystemApis and for hidden connect/disconnect APIs. Hide some APIs that were previously marked as @UnsupportedAppUsage and re-add annotation as changing the permissions for these SystemApis would break the unsupported app contract that was previously there. Therefore, we're choosing to hide them until we have a good story on how to deal with them next release. Bug: 148689314 Test: Manual Merged-In: I33ee2c7ccd3827db3d23d6447cf82d9ffc36836a Change-Id: I33ee2c7ccd3827db3d23d6447cf82d9ffc36836a --- framework/java/android/bluetooth/BluetoothAdapter.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 0a9dbb608b..e6b90d87a5 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1214,7 +1214,7 @@ public final class BluetoothAdapter { * @return true to indicate that the config file was successfully cleared * @hide */ - @SystemApi + @UnsupportedAppUsage @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean factoryReset() { try { @@ -1506,8 +1506,9 @@ public final class BluetoothAdapter { * @return true if the scan mode was set, false otherwise * @hide */ - @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which " + + "shows UI that confirms the user wants to go into discoverable mode.") + @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean setScanMode(@ScanMode int mode, long durationMillis) { if (getState() != STATE_ON) { return false; @@ -1555,8 +1556,8 @@ public final class BluetoothAdapter { * @return true if the scan mode was set, false otherwise * @hide */ - @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @UnsupportedAppUsage + @RequiresPermission(Manifest.permission.BLUETOOTH) public boolean setScanMode(@ScanMode int mode) { if (getState() != STATE_ON) { return false; @@ -1620,7 +1621,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public long getDiscoveryEndMillis() { try { mServiceLock.readLock().lock(); @@ -1872,7 +1873,6 @@ public final class BluetoothAdapter { * * @hide */ - @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) { try { @@ -1901,7 +1901,6 @@ public final class BluetoothAdapter { * * @hide */ - @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) { try { -- cgit v1.2.3 From 78cb0998affedc80b0e4f1c83d58c5250eb07dd1 Mon Sep 17 00:00:00 2001 From: Ugo Yu Date: Mon, 23 Mar 2020 13:48:33 +0800 Subject: Independent methods to enable/disable BLE mode * Use IBluetoothManager.enableBle() and disableBle() to toggle BLE only mode instead of updateBleAppCount() then enable(). * Fix BluetoothAdapter.disableBle sometime won't disable Bluetooth. * Add active log if Bluetooth is disabled via disableBle(). Bug: 139454316 Test: enableBle() -> disableBle() and check Bluetooth is OFF. Change-Id: I173d5fed1b47ff68a6504741e25754e65cbd1455 --- .../java/android/bluetooth/BluetoothAdapter.java | 37 ++++------------------ 1 file changed, 7 insertions(+), 30 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 0a9dbb608b..d407ad1dbe 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -916,23 +916,11 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) { return false; } - - int state = getLeState(); - if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) { - String packageName = ActivityThread.currentPackageName(); - if (DBG) { - Log.d(TAG, "disableBLE(): de-registering " + packageName); - } - try { - mManagerService.updateBleAppCount(mToken, false, packageName); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return true; - } - - if (DBG) { - Log.d(TAG, "disableBLE(): Already disabled"); + String packageName = ActivityThread.currentPackageName(); + try { + return mManagerService.disableBle(packageName, mToken); + } catch (RemoteException e) { + Log.e(TAG, "", e); } return false; } @@ -973,20 +961,9 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) { return false; } - + String packageName = ActivityThread.currentPackageName(); try { - String packageName = ActivityThread.currentPackageName(); - mManagerService.updateBleAppCount(mToken, true, packageName); - if (isLeEnabled()) { - if (DBG) { - Log.d(TAG, "enableBLE(): Bluetooth already enabled"); - } - return true; - } - if (DBG) { - Log.d(TAG, "enableBLE(): Calling enable"); - } - return mManagerService.enable(packageName); + return mManagerService.enableBle(packageName, mToken); } catch (RemoteException e) { Log.e(TAG, "", e); } -- cgit v1.2.3 From ea9e0298b346934247cfb1911299d824a9227d8e Mon Sep 17 00:00:00 2001 From: Ugo Yu Date: Mon, 23 Mar 2020 13:48:33 +0800 Subject: Independent methods to enable/disable BLE mode * Use IBluetoothManager.enableBle() and disableBle() to toggle BLE only mode instead of updateBleAppCount() then enable(). * Fix BluetoothAdapter.disableBle sometime won't disable Bluetooth. * Add active log if Bluetooth is disabled via disableBle(). Bug: 139454316 Test: enableBle() -> disableBle() and check Bluetooth is OFF. Change-Id: I173d5fed1b47ff68a6504741e25754e65cbd1455 --- .../java/android/bluetooth/BluetoothAdapter.java | 37 ++++------------------ 1 file changed, 7 insertions(+), 30 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 4aad3cbb21..f216db6fc7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -917,23 +917,11 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) { return false; } - - int state = getLeState(); - if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) { - String packageName = ActivityThread.currentPackageName(); - if (DBG) { - Log.d(TAG, "disableBLE(): de-registering " + packageName); - } - try { - mManagerService.updateBleAppCount(mToken, false, packageName); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } - return true; - } - - if (DBG) { - Log.d(TAG, "disableBLE(): Already disabled"); + String packageName = ActivityThread.currentPackageName(); + try { + return mManagerService.disableBle(packageName, mToken); + } catch (RemoteException e) { + Log.e(TAG, "", e); } return false; } @@ -974,20 +962,9 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) { return false; } - + String packageName = ActivityThread.currentPackageName(); try { - String packageName = ActivityThread.currentPackageName(); - mManagerService.updateBleAppCount(mToken, true, packageName); - if (isLeEnabled()) { - if (DBG) { - Log.d(TAG, "enableBLE(): Bluetooth already enabled"); - } - return true; - } - if (DBG) { - Log.d(TAG, "enableBLE(): Calling enable"); - } - return mManagerService.enable(packageName); + return mManagerService.enableBle(packageName, mToken); } catch (RemoteException e) { Log.e(TAG, "", e); } -- cgit v1.2.3 From 96914087869e5c82dc88fd2b114854b1589ce276 Mon Sep 17 00:00:00 2001 From: Lee Shombert Date: Fri, 3 Apr 2020 14:00:40 -0700 Subject: Fix exception handling in getState() binder cache Bug: 153103051 A binder cache query function cannot compute a result based on any data that is not known to the binder server. If the code depends on local data that can change, then invalidation will not work properly. The getState() method returns OFF if the bluetooth service is unavailable. This computation now occurs in the getState() method, outside of the binder cache query() method. The query method converts RemoteExceptions to RuntimeExceptions. Then, the conversion is reversed in getState(). This double conversion is needed because the cache query() method has no throw spec. Test: Run 'atest BluetoothInstrumentationTests' with a special debug image that enables binder cache VERIFY. The test found no cache inconsistencies. Change-Id: I80db86f66d8b51fa94207824c8b15972a9066ef5 --- .../java/android/bluetooth/BluetoothAdapter.java | 32 ++++++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index f216db6fc7..fc48e7f18f 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -979,17 +979,14 @@ public final class BluetoothAdapter { 8, BLUETOOTH_GET_STATE_CACHE_PROPERTY) { @Override protected Integer recompute(Void query) { + // This function must be called while holding the + // mServiceLock, and with mService not null. The public + // getState() method makes this guarantee. try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getState(); - } + return mService.getState(); } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); + throw e.rethrowFromSystemServer(); } - return BluetoothAdapter.STATE_OFF; } }; @@ -1016,7 +1013,24 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) @AdapterState public int getState() { - int state = mBluetoothGetStateCache.query(null); + int state = BluetoothAdapter.STATE_OFF; + + try { + mServiceLock.readLock().lock(); + // The test for mService must either be outside the cache, or + // the cache must be invalidated when mService changes. + if (mService != null) { + state = mBluetoothGetStateCache.query(null); + } + } catch (RuntimeException e) { + if (e.getCause() instanceof RemoteException) { + Log.e(TAG, "", e.getCause()); + } else { + throw e; + } + } finally { + mServiceLock.readLock().unlock(); + } // Consider all internal states as OFF if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON -- cgit v1.2.3 From 46483817a8e84c9f1b0bf738366511c370bf5fa6 Mon Sep 17 00:00:00 2001 From: Lee Shombert Date: Wed, 8 Apr 2020 21:02:22 +0000 Subject: Revert "Fix exception handling in getState() binder cache" This reverts commit 96914087869e5c82dc88fd2b114854b1589ce276. Bug: b/153505953 Change-Id: I58c46e534ccadf332d10fff8f99c85ad24340c27 --- .../java/android/bluetooth/BluetoothAdapter.java | 32 ++++++---------------- 1 file changed, 9 insertions(+), 23 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index fc48e7f18f..f216db6fc7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -979,14 +979,17 @@ public final class BluetoothAdapter { 8, BLUETOOTH_GET_STATE_CACHE_PROPERTY) { @Override protected Integer recompute(Void query) { - // This function must be called while holding the - // mServiceLock, and with mService not null. The public - // getState() method makes this guarantee. try { - return mService.getState(); + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.getState(); + } } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); } + return BluetoothAdapter.STATE_OFF; } }; @@ -1013,24 +1016,7 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) @AdapterState public int getState() { - int state = BluetoothAdapter.STATE_OFF; - - try { - mServiceLock.readLock().lock(); - // The test for mService must either be outside the cache, or - // the cache must be invalidated when mService changes. - if (mService != null) { - state = mBluetoothGetStateCache.query(null); - } - } catch (RuntimeException e) { - if (e.getCause() instanceof RemoteException) { - Log.e(TAG, "", e.getCause()); - } else { - throw e; - } - } finally { - mServiceLock.readLock().unlock(); - } + int state = mBluetoothGetStateCache.query(null); // Consider all internal states as OFF if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON -- cgit v1.2.3 From 54846525c509a2d638e059095b12e64accc5b163 Mon Sep 17 00:00:00 2001 From: Lee Shombert Date: Thu, 9 Apr 2020 09:00:46 -0700 Subject: Fix exception handling in getState() binder cache Bug: 153103051 A binder cache recompute() function cannot compute a result based on any data that is not known to the binder server. If the code depends on local data that can change, then invalidation will not work properly. The original getState() method returned OFF if the bluetooth service was unavailable. This computation now occurs in the getStateInternal() method, outside of the binder cache query() method. The recompute() method converts RemoteExceptions to RuntimeExceptions. Then, the conversion is reversed in getStateInternal(). This double conversion is needed because the cache recompute() method has no throw spec. Test: Create a debug image that enables binder cache VERIFY. Run the following tests: * atest BluetoothInstrumentationTests * atest PtsChreTestCases * atest UserLifecycleTests * manual testing connecting to bluetooth devices and toggling airplane mode. No cache inconsistencies found. No test failures seen. Change-Id: I93b9742587c4eb695d9a11fc6ab145f6a40a0ece --- .../java/android/bluetooth/BluetoothAdapter.java | 38 ++++++++++++++++------ 1 file changed, 28 insertions(+), 10 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index f216db6fc7..29a98faf5c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -980,16 +980,10 @@ public final class BluetoothAdapter { @Override protected Integer recompute(Void query) { try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.getState(); - } + return mService.getState(); } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); + throw e.rethrowFromSystemServer(); } - return BluetoothAdapter.STATE_OFF; } }; @@ -1003,6 +997,30 @@ public final class BluetoothAdapter { PropertyInvalidatedCache.invalidateCache(BLUETOOTH_GET_STATE_CACHE_PROPERTY); } + /** + * Fetch the current bluetooth state. If the service is down, return + * OFF. + */ + @AdapterState + private int getStateInternal() { + int state = BluetoothAdapter.STATE_OFF; + try { + mServiceLock.readLock().lock(); + if (mService != null) { + state = mBluetoothGetStateCache.query(null); + } + } catch (RuntimeException e) { + if (e.getCause() instanceof RemoteException) { + Log.e(TAG, "", e.getCause()); + } else { + throw e; + } + } finally { + mServiceLock.readLock().unlock(); + } + return state; + } + /** * Get the current state of the local Bluetooth adapter. *

Possible return values are @@ -1016,7 +1034,7 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH) @AdapterState public int getState() { - int state = mBluetoothGetStateCache.query(null); + int state = getStateInternal(); // Consider all internal states as OFF if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON @@ -1054,7 +1072,7 @@ public final class BluetoothAdapter { @UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine " + "whether you can use BLE & BT classic.") public int getLeState() { - int state = mBluetoothGetStateCache.query(null); + int state = getStateInternal(); if (VDBG) { Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state)); -- cgit v1.2.3 From 3a268eaff222b076857b736fc17f2f373d739110 Mon Sep 17 00:00:00 2001 From: Lee Shombert Date: Mon, 1 Jun 2020 15:33:36 -0700 Subject: Create a binder cache for IBluetooth.getConnectionState Bug: 157935587 This adds a binder cache for the IBluetooth.getConnectionState() method. There is no change in bluetooth functionality. Each atest is run twice. Once with the code to be committed and once with a special build that sets PropertyInvalidatedCache DEBUG and VERIFY to true. In the latter case, the test passes if the atest passes and if there are no errors from the cache verification. Tag: #feature Test: atest BluetoothInstrumentationTests Test results are Passed: 479, Failed: 0, Ignored: 4, Assumption Failed: 75 Change-Id: I2946297ffab557877dc7ec56206834d7c3776662 --- .../java/android/bluetooth/BluetoothAdapter.java | 40 ++++++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 29a98faf5c..8c3268c6fc 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2348,6 +2348,36 @@ public final class BluetoothAdapter { return supportedProfiles; } + private static final String BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY = + "cache_key.bluetooth.get_adapter_connection_state"; + private final PropertyInvalidatedCache + mBluetoothGetAdapterConnectionStateCache = + new PropertyInvalidatedCache ( + 8, BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY) { + /** + * This method must not be called when mService is null. + */ + @Override + protected Integer recompute(Void query) { + try { + return mService.getAdapterConnectionState(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + }; + + /** @hide */ + public void disableGetAdapterConnectionStateCache() { + mBluetoothGetAdapterConnectionStateCache.disableLocal(); + } + + /** @hide */ + public static void invalidateGetAdapterConnectionStateCache() { + PropertyInvalidatedCache.invalidateCache( + BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY); + } + /** * Get the current connection state of the local Bluetooth adapter. * This can be used to check whether the local Bluetooth adapter is connected @@ -2368,10 +2398,14 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getAdapterConnectionState(); + return mBluetoothGetAdapterConnectionStateCache.query(null); + } + } catch (RuntimeException e) { + if (e.getCause() instanceof RemoteException) { + Log.e(TAG, "getConnectionState:", e.getCause()); + } else { + throw e; } - } catch (RemoteException e) { - Log.e(TAG, "getConnectionState:", e); } finally { mServiceLock.readLock().unlock(); } -- cgit v1.2.3 From aa988ed154110bea2ac85e7963c274517715fa49 Mon Sep 17 00:00:00 2001 From: weichinweng Date: Mon, 29 Jun 2020 08:14:49 +0800 Subject: Add debug log for set/remove active device. Bug: 160746277 Test: atest BluetoothInstrumentationTests Tag: #feature Change-Id: I3decaa102345d9e9485882cfeee2fae203264e25 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index f962ea0966..47bd207fee 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1784,6 +1784,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { + if (DBG) Log.d(TAG, "removeActiveDevice, profiles: " + profiles); return mService.removeActiveDevice(profiles); } } catch (RemoteException e) { @@ -1828,6 +1829,9 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { + if (DBG) { + Log.d(TAG, "setActiveDevice, device: " + device + ", profiles: " + profiles); + } return mService.setActiveDevice(device, profiles); } } catch (RemoteException e) { -- cgit v1.2.3 From ea321cd2e938a124f690c8a4a1b98e1e4b0c67a6 Mon Sep 17 00:00:00 2001 From: Zach Johnson Date: Wed, 19 Aug 2020 16:53:06 -0700 Subject: Remove listenUsingEncryptedRfcommOn & listenUsingScoOn both are hidden and not @UnsupportedAppUsage, so are safe to remove Bug: 159815595 Tag: #refactor Test: compile & verify basic functions working Change-Id: I58acb4160207fc0eeaeb7875bfd61f3bd442ad9a --- .../java/android/bluetooth/BluetoothAdapter.java | 46 ---------------------- 1 file changed, 46 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 47bd207fee..4ee22b78c5 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2562,52 +2562,6 @@ public final class BluetoothAdapter { return socket; } - /** - * Construct an encrypted, RFCOMM server socket. - * Call #accept to retrieve connections to this socket. - * - * @return An RFCOMM BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or insufficient - * permissions. - * @hide - */ - public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) throws IOException { - BluetoothServerSocket socket = - new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, true, port); - int errno = socket.mSocket.bindListen(); - if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { - socket.setChannel(socket.mSocket.getPort()); - } - if (errno < 0) { - //TODO(BT): Throw the same exception error code - // that the previous code was using. - //socket.mSocket.throwErrnoNative(errno); - throw new IOException("Error: " + errno); - } - return socket; - } - - /** - * Construct a SCO server socket. - * Call #accept to retrieve connections to this socket. - * - * @return A SCO BluetoothServerSocket - * @throws IOException On error, for example Bluetooth not available, or insufficient - * permissions. - * @hide - */ - public static BluetoothServerSocket listenUsingScoOn() throws IOException { - BluetoothServerSocket socket = - new BluetoothServerSocket(BluetoothSocket.TYPE_SCO, false, false, -1); - int errno = socket.mSocket.bindListen(); - if (errno < 0) { - //TODO(BT): Throw the same exception error code - // that the previous code was using. - //socket.mSocket.throwErrnoNative(errno); - } - return socket; - } - /** * Construct an encrypted, authenticated, L2CAP server socket. * Call #accept to retrieve connections to this socket. -- cgit v1.2.3 From c5386afbc18b5164c381b1d8e099327953205436 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 11 Sep 2020 14:57:21 -0600 Subject: Update language to comply with Android's inclusive language guidance See https://source.android.com/setup/contribute/respectful-code for reference Test: none Bug: 168334533 Exempt-From-Owner-Approval: docs updates Change-Id: I245b8d9cac722da76ea67983738a3cbb9deb68df --- framework/java/android/bluetooth/BluetoothAdapter.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index f062a39c6f..3c7d8fca20 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2470,7 +2470,7 @@ public final class BluetoothAdapter { * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. * * @param channel RFCOMM channel to listen on - * @param mitm enforce man-in-the-middle protection for authentication. + * @param mitm enforce person-in-the-middle protection for authentication. * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 * connections. * @return a listening RFCOMM BluetoothServerSocket @@ -2528,7 +2528,7 @@ public final class BluetoothAdapter { /** * Create a listening, insecure RFCOMM Bluetooth socket with Service Record. *

The link key is not required to be authenticated, i.e the communication may be - * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices, + * vulnerable to Person In the Middle attacks. For Bluetooth 2.1 devices, * the link will be encrypted, as encryption is mandartory. * For legacy devices (pre Bluetooth 2.1 devices) the link will not * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an @@ -2561,7 +2561,7 @@ public final class BluetoothAdapter { * Create a listening, encrypted, * RFCOMM Bluetooth socket with Service Record. *

The link will be encrypted, but the link key is not required to be authenticated - * i.e the communication is vulnerable to Man In the Middle attacks. Use + * i.e the communication is vulnerable to Person In the Middle attacks. Use * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key. *

Use this socket if authentication of link key is not possible. * For example, for Bluetooth 2.1 devices, if any of the devices does not have @@ -2646,7 +2646,7 @@ public final class BluetoothAdapter { * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. * * @param port the PSM to listen on - * @param mitm enforce man-in-the-middle protection for authentication. + * @param mitm enforce person-in-the-middle protection for authentication. * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 * connections. * @return An L2CAP BluetoothServerSocket @@ -3347,7 +3347,7 @@ public final class BluetoothAdapter { * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The * supported Bluetooth transport is LE only. *

The link key is not required to be authenticated, i.e the communication may be vulnerable - * to man-in-the-middle attacks. Use {@link #listenUsingL2capChannel}, if an encrypted and + * to person-in-the-middle attacks. Use {@link #listenUsingL2capChannel}, if an encrypted and * authenticated communication channel is desired. *

Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening * {@link BluetoothServerSocket}. -- cgit v1.2.3 From 7bfef016fe049e35f2456034d17b6f0e57fe1732 Mon Sep 17 00:00:00 2001 From: Myles Watson Date: Mon, 5 Oct 2020 11:23:24 -0700 Subject: Bluetooth: Spell mandatory correctly Bug: 169654068 Test: compilation Change-Id: Ibb0046180760e27d6991ae17849a7405738b6f01 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3c7d8fca20..872c377711 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2529,7 +2529,7 @@ public final class BluetoothAdapter { * Create a listening, insecure RFCOMM Bluetooth socket with Service Record. *

The link key is not required to be authenticated, i.e the communication may be * vulnerable to Person In the Middle attacks. For Bluetooth 2.1 devices, - * the link will be encrypted, as encryption is mandartory. + * the link will be encrypted, as encryption is mandatory. * For legacy devices (pre Bluetooth 2.1 devices) the link will not * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an * encrypted and authenticated communication channel is desired. @@ -2568,7 +2568,7 @@ public final class BluetoothAdapter { * an input and output capability or just has the ability to display a numeric key, * a secure socket connection is not possible and this socket can be used. * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required. - * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory. + * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandatory. * For more details, refer to the Security Model section 5.2 (vol 3) of * Bluetooth Core Specification version 2.1 + EDR. *

Use {@link BluetoothServerSocket#accept} to retrieve incoming -- cgit v1.2.3 From bc9a809f18a3b0ec23cbc39802fb4928c2074ea3 Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Tue, 27 Oct 2020 11:47:29 +0000 Subject: Add maxTargetSdk restriction to unused APIs. These are APIs that have @UnsupportedAppUsage but for which we don't have any evidence of them currently being used, so should be safe to remove from the unsupported list. Bug: 170729553 Test: Treehugger Change-Id: I4c8fd0006f950de9955242e93968fb0996ceb372 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 573892bcf0..475be121b7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -40,6 +40,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.BatteryStats; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; @@ -1170,7 +1171,7 @@ public final class BluetoothAdapter { * @return true to indicate adapter shutdown has begun, or false on immediate error * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean disable(boolean persist) { try { @@ -1219,7 +1220,7 @@ public final class BluetoothAdapter { * @return true to indicate that the config file was successfully cleared * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean factoryReset() { try { @@ -2625,7 +2626,7 @@ public final class BluetoothAdapter { * permissions, or channel in use. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid) throws IOException { return createNewRfcommSocketAndRecord(name, uuid, false, true); -- cgit v1.2.3 From bddbb77484a3694357df750c5e7df9527f409c8a Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Wed, 28 Oct 2020 19:38:11 +0000 Subject: Revert "Add maxTargetSdk restriction to unused APIs." This reverts commit bc9a809f18a3b0ec23cbc39802fb4928c2074ea3. Reason for revert: Droidcop-triggered revert due to breakage https://android-build.googleplex.com/builds/quarterdeck?testMethod=testAppZygotePreload&testClass=android.app.cts.ServiceTest&atpConfigName=suite%2Ftest-mapping-presubmit-retry_cloud-tf&testModule=CtsAppTestCases&fkbb=6936597&lkbb=6936969&lkgb=6936551&testResults=true&branch=git_master&target=cf_x86_phone-userdebug>, bug b/171886397 Bug: 171886397 Change-Id: Ibe0f0430a3451477c1ee8ef56a596e91ea1e7672 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 475be121b7..573892bcf0 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -40,7 +40,6 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.BatteryStats; import android.os.Binder; -import android.os.Build; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; @@ -1171,7 +1170,7 @@ public final class BluetoothAdapter { * @return true to indicate adapter shutdown has begun, or false on immediate error * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public boolean disable(boolean persist) { try { @@ -1220,7 +1219,7 @@ public final class BluetoothAdapter { * @return true to indicate that the config file was successfully cleared * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean factoryReset() { try { @@ -2626,7 +2625,7 @@ public final class BluetoothAdapter { * permissions, or channel in use. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid) throws IOException { return createNewRfcommSocketAndRecord(name, uuid, false, true); -- cgit v1.2.3 From cba870b777fc6d2a03a27758cf1db1c38556efe8 Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Tue, 27 Oct 2020 11:47:29 +0000 Subject: Add maxTargetSdk restriction to unused APIs. These are APIs that have @UnsupportedAppUsage but for which we don't have any evidence of them currently being used, so should be safe to remove from the unsupported list. This is a resubmit of ag/12929664 with some APIs excluded that caused test failures; see bugs 171886397, 171888296, 171864568. APIs excluded: Landroid/bluetooth/le/ScanRecord;->parseFromBytes([B)Landroid/bluetooth/le/ScanRecord; Landroid/os/Process;->myPpid()I Landroid/os/SharedMemory;->getFd()I Landroid/hardware/input/InputManager;->INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH:I Bug: 170729553 Test: Treehugger Change-Id: I8285daa8530260251ecad6f3f38f98e263629ca7 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 573892bcf0..475be121b7 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -40,6 +40,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.BatteryStats; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; @@ -1170,7 +1171,7 @@ public final class BluetoothAdapter { * @return true to indicate adapter shutdown has begun, or false on immediate error * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean disable(boolean persist) { try { @@ -1219,7 +1220,7 @@ public final class BluetoothAdapter { * @return true to indicate that the config file was successfully cleared * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean factoryReset() { try { @@ -2625,7 +2626,7 @@ public final class BluetoothAdapter { * permissions, or channel in use. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid) throws IOException { return createNewRfcommSocketAndRecord(name, uuid, false, true); -- cgit v1.2.3 From 6a221b5f27e76a5d6b90eef4343625bcc3e19ca1 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Wed, 28 Oct 2020 12:12:03 -0700 Subject: Introduce a BluetoothConnectionCallback that will fire off events when a device is connected or disconnected. Tag: #feature Bug: 171902843 Test: Manual Change-Id: I194a35a69fe0c5d960ea88a1a0fa52c8df7738e2 --- .../java/android/bluetooth/BluetoothAdapter.java | 130 +++++++++++++++++++++ 1 file changed, 130 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 872c377711..7047f73393 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -18,6 +18,7 @@ package android.bluetooth; import android.Manifest; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -686,6 +687,8 @@ public final class BluetoothAdapter { private final Map mLeScanClients; private static final Map>> sMetadataListeners = new HashMap<>(); + private final Map + mBluetoothConnectionCallbackExecutorMap = new HashMap<>(); /** * Bluetooth metadata listener. Overrides the default BluetoothMetadataListener @@ -3538,6 +3541,133 @@ public final class BluetoothAdapter { @Nullable byte[] value); } + private final IBluetoothConnectionCallback mConnectionCallback = + new IBluetoothConnectionCallback.Stub() { + @Override + public void onDeviceConnected(BluetoothDevice device) { + for (Map.Entry callbackExecutorEntry: + mBluetoothConnectionCallbackExecutorMap.entrySet()) { + BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); + Executor executor = callbackExecutorEntry.getValue(); + executor.execute(() -> callback.onDeviceConnected(device)); + } + } + + @Override + public void onDeviceDisconnected(BluetoothDevice device) { + for (Map.Entry callbackExecutorEntry: + mBluetoothConnectionCallbackExecutorMap.entrySet()) { + BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); + Executor executor = callbackExecutorEntry.getValue(); + executor.execute(() -> callback.onDeviceDisconnected(device)); + } + } + }; + + /** + * Registers the BluetoothConnectionCallback to receive callback events when a bluetooth device + * (classic or low energy) is connected or disconnected. + * + * @param executor is the callback executor + * @param callback is the connection callback you wish to register + * @return true if the callback was registered successfully, false otherwise + * @throws IllegalArgumentException if the callback is already registered + * @hide + */ + public boolean registerBluetoothConnectionCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull BluetoothConnectionCallback callback) { + if (DBG) Log.d(TAG, "registerBluetoothConnectionCallback()"); + if (callback == null) { + return false; + } + + // If the callback map is empty, we register the service-to-app callback + if (mBluetoothConnectionCallbackExecutorMap.isEmpty()) { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + if (!mService.registerBluetoothConnectionCallback(mConnectionCallback)) { + return false; + } + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + mBluetoothConnectionCallbackExecutorMap.remove(callback); + } finally { + mServiceLock.readLock().unlock(); + } + } + + // Adds the passed in callback to our map of callbacks to executors + synchronized (mBluetoothConnectionCallbackExecutorMap) { + if (mBluetoothConnectionCallbackExecutorMap.containsKey(callback)) { + throw new IllegalArgumentException("This callback has already been registered"); + } + mBluetoothConnectionCallbackExecutorMap.put(callback, executor); + } + + return true; + } + + /** + * Unregisters the BluetoothConnectionCallback that was previously registered by the application + * + * @param callback is the connection callback you wish to unregister + * @return true if the callback was unregistered successfully, false otherwise + * @hide + */ + public boolean unregisterBluetoothConnectionCallback( + @NonNull BluetoothConnectionCallback callback) { + if (DBG) Log.d(TAG, "unregisterBluetoothConnectionCallback()"); + if (callback == null) { + return false; + } + + synchronized (mBluetoothConnectionCallbackExecutorMap) { + if (mBluetoothConnectionCallbackExecutorMap.remove(callback) != null) { + return false; + } + } + + if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) { + return true; + } + + // If the callback map is empty, we unregister the service-to-app callback + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.unregisterBluetoothConnectionCallback(mConnectionCallback); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + + return false; + } + + /** + * This abstract class is used to implement callbacks for when a bluetooth classic or Bluetooth + * Low Energy (BLE) device is either connected or disconnected. + * + * @hide + */ + public abstract class BluetoothConnectionCallback { + /** + * Callback triggered when a bluetooth device (classic or BLE) is connected + * @param device is the connected bluetooth device + */ + public void onDeviceConnected(BluetoothDevice device) {} + + /** + * Callback triggered when a bluetooth device (classic or BLE) is disconnected + * @param device is the disconnected bluetooth device + */ + public void onDeviceDisconnected(BluetoothDevice device) {} + } + /** * Converts old constant of priority to the new for connection policy * -- cgit v1.2.3 From 049f0f5f4196aa3c1897bcbfd1a86c66ab1affcc Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Wed, 4 Nov 2020 09:29:36 +0000 Subject: Add maxTargetSdk restriction to unused APIs. These are APIs that have @UnsupportedAppUsage but for which we don't have any evidence of them currently being used, so should be safe to remove from the unsupported list. Bug: 170729553 Test: Treehugger Merged-In: I626caf7c1fe46c5ab1f39c2895b42a34319f771a Change-Id: I54e5ecd11e76ca1de3c5893e3a98b0108e735413 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 7047f73393..2dfbb3ae81 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -41,6 +41,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.BatteryStats; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.ParcelUuid; import android.os.RemoteException; @@ -1173,7 +1174,7 @@ public final class BluetoothAdapter { * @return true to indicate adapter shutdown has begun, or false on immediate error * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean disable(boolean persist) { try { @@ -1222,7 +1223,7 @@ public final class BluetoothAdapter { * @return true to indicate that the config file was successfully cleared * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean factoryReset() { try { @@ -2594,7 +2595,7 @@ public final class BluetoothAdapter { * permissions, or channel in use. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid) throws IOException { return createNewRfcommSocketAndRecord(name, uuid, false, true); -- cgit v1.2.3 From 9544cacc28a304dcc10b2069f8e547c05d592b4b Mon Sep 17 00:00:00 2001 From: Eugene Susla Date: Wed, 2 Dec 2020 12:21:36 -0800 Subject: Store CDM device profile and apply role when device is connected Test: manual - ensure role privileges are granted/revoked when device is connected/disconnected Bug: 165951651 Change-Id: Id24a4b3a3510781d9105763b1722f44583a7fd7c --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index c07cd52c58..1713a0c158 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3689,7 +3689,7 @@ public final class BluetoothAdapter { * * @hide */ - public abstract class BluetoothConnectionCallback { + public abstract static class BluetoothConnectionCallback { /** * Callback triggered when a bluetooth device (classic or BLE) is connected * @param device is the connected bluetooth device -- cgit v1.2.3 From 00040ba31b89439603026638acd511ade955e543 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Thu, 17 Dec 2020 12:10:51 -0800 Subject: Register the service-to-app callback whenever the service comes up for BluetoothConnectionCallback. This ensures that if the bluetooth process dies, the callbacks will be re-established once it comes back up. Tag: #feature Bug: 175700972 Test: Manual Change-Id: I2a20b229fcc1d8f69ccc1b24b62c26ce8155c29f --- .../java/android/bluetooth/BluetoothAdapter.java | 40 ++++++++++++++-------- 1 file changed, 25 insertions(+), 15 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 2dfbb3ae81..e4b2d7075d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2933,6 +2933,16 @@ public final class BluetoothAdapter { } }); } + synchronized (mBluetoothConnectionCallbackExecutorMap) { + if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) { + try { + mService.registerBluetoothConnectionCallback(mConnectionCallback); + } catch (RemoteException e) { + Log.e(TAG, "onBluetoothServiceUp: Failed to register bluetooth" + + "connection callback", e); + } + } + } } public void onBluetoothServiceDown() { @@ -3582,25 +3592,25 @@ public final class BluetoothAdapter { return false; } - // If the callback map is empty, we register the service-to-app callback - if (mBluetoothConnectionCallbackExecutorMap.isEmpty()) { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - if (!mService.registerBluetoothConnectionCallback(mConnectionCallback)) { - return false; + synchronized (mBluetoothConnectionCallbackExecutorMap) { + // If the callback map is empty, we register the service-to-app callback + if (mBluetoothConnectionCallbackExecutorMap.isEmpty()) { + try { + mServiceLock.readLock().lock(); + if (mService != null) { + if (!mService.registerBluetoothConnectionCallback(mConnectionCallback)) { + return false; + } } + } catch (RemoteException e) { + Log.e(TAG, "", e); + mBluetoothConnectionCallbackExecutorMap.remove(callback); + } finally { + mServiceLock.readLock().unlock(); } - } catch (RemoteException e) { - Log.e(TAG, "", e); - mBluetoothConnectionCallbackExecutorMap.remove(callback); - } finally { - mServiceLock.readLock().unlock(); } - } - // Adds the passed in callback to our map of callbacks to executors - synchronized (mBluetoothConnectionCallbackExecutorMap) { + // Adds the passed in callback to our map of callbacks to executors if (mBluetoothConnectionCallbackExecutorMap.containsKey(callback)) { throw new IllegalArgumentException("This callback has already been registered"); } -- cgit v1.2.3 From b426f901449bce7e901e18fc9d7450a07180dd84 Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Wed, 6 Jan 2021 12:05:47 +0000 Subject: Derestrict some non-SDK APIs. Per request from a partner, these APIs will not be restricted as they are in use. This is conceptually a partial revert of change 049f0f5f419. NoNonSdkCheck: b/170729553 Bug: 171933273 Test: Treehugger Change-Id: Ibb525e9a9e2fc90248b74f45f3cdcb0be7487c3a --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e4b2d7075d..b7203e3e36 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1174,7 +1174,7 @@ public final class BluetoothAdapter { * @return true to indicate adapter shutdown has begun, or false on immediate error * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage(trackingBug = 171933273) public boolean disable(boolean persist) { try { -- cgit v1.2.3 From 65b57adaa21dde636880ab8c133de2b1206d2a3b Mon Sep 17 00:00:00 2001 From: Eugene Susla Date: Tue, 12 Jan 2021 11:39:43 -0800 Subject: [DO NOT MERGE] Scan and notify apps when their companion devices are nearby Test: manual Bug: 168052577 Change-Id: Ib2187fb76e604878b1d4dd9c0cd6cea610b2a04d (cherry picked from commit 017c2c41456e3938145cf33facea339f9918b20c) --- .../java/android/bluetooth/BluetoothAdapter.java | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 7eda50e5c9..ea7e5ea7c8 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3197,6 +3197,61 @@ public final class BluetoothAdapter { void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); } + /** + * Register a callback to receive events whenever the bluetooth stack goes down and back up, + * e.g. in the event the bluetooth is turned off/on via settings. + * + * If the bluetooth stack is currently up, there will not be an initial callback call. + * You can use the return value as an indication of this being the case. + * + * Callbacks will be delivered on a binder thread. + * + * @return whether bluetooth is already up currently + * + * @hide + */ + public boolean registerServiceLifecycleCallback(ServiceLifecycleCallback callback) { + return getBluetoothService(callback.mRemote) != null; + } + + /** + * Unregister a callback registered via {@link #registerServiceLifecycleCallback} + * + * @hide + */ + public void unregisterServiceLifecycleCallback(ServiceLifecycleCallback callback) { + removeServiceStateCallback(callback.mRemote); + } + + /** + * A callback for {@link #registerServiceLifecycleCallback} + * + * @hide + */ + public abstract static class ServiceLifecycleCallback { + + /** Called when the bluetooth stack is up */ + public abstract void onBluetoothServiceUp(); + + /** Called when the bluetooth stack is down */ + public abstract void onBluetoothServiceDown(); + + IBluetoothManagerCallback mRemote = new IBluetoothManagerCallback.Stub() { + @Override + public void onBluetoothServiceUp(IBluetooth bluetoothService) { + ServiceLifecycleCallback.this.onBluetoothServiceUp(); + } + + @Override + public void onBluetoothServiceDown() { + ServiceLifecycleCallback.this.onBluetoothServiceDown(); + } + + @Override + public void onBrEdrDown() {} + }; + } + /** * Starts a scan for Bluetooth LE devices. * -- cgit v1.2.3 From 182e8c12f27517c7c11f535472c65fae6c17c500 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Fri, 29 Jan 2021 12:38:13 -0800 Subject: Skips the consent pairing dialog for recently associated CDM app and device combos because they have already been shown the CDM prompt which implicitly provides consent to bond. Tag: #feature Bug: 172006481 Test: Manual Change-Id: I541b720c6b8b6e55be10e04f202e0a58cf33715f --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ea7e5ea7c8..ec46da0dcf 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1654,7 +1654,7 @@ public final class BluetoothAdapter { mContext = context; } - private String getOpPackageName() { + String getOpPackageName() { // Workaround for legacy API for getting a BluetoothAdapter not // passing a context if (mContext != null) { -- cgit v1.2.3 From bec67a5c678926b62fd1337316027e2fd0ff854f Mon Sep 17 00:00:00 2001 From: Andrew Cheng Date: Fri, 19 Feb 2021 18:42:38 +0000 Subject: Make BluetoothConnectionCallback static Tag: #refactor Fixes: 180727461 Test: atest BluetoothInstrumentationTests Change-Id: I4bd084cb6c0371b649adb1d1a65b3327ae3e488a Merged-In: Id24a4b3a3510781d9105763b1722f44583a7fd7c --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b7203e3e36..d254340f49 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3665,7 +3665,7 @@ public final class BluetoothAdapter { * * @hide */ - public abstract class BluetoothConnectionCallback { + public abstract static class BluetoothConnectionCallback { /** * Callback triggered when a bluetooth device (classic or BLE) is connected * @param device is the connected bluetooth device -- cgit v1.2.3 From 8ab39e54b5bcde03c762e7af325645da2a2d5652 Mon Sep 17 00:00:00 2001 From: Andrew Cheng Date: Thu, 14 Jan 2021 16:21:48 -0800 Subject: Surface ACL disconnect reasons from native to Java HCI disconnect commands and events have an accompanying "reason" parameter comprising of a HCI error code. This can be useful in both debugging and re-connection logic at the Java level. This CL grabs the HCI codes from native and passes it up to Java via an extra parameter to existing ACL connection callbacks. Tag: #feature Bug: 177668957 Test: atest BluetoothInstrumentationTests Change-Id: Ic729140b8ffb1273a9ca53cdfd39c9f5d71e1522 --- .../java/android/bluetooth/BluetoothAdapter.java | 153 ++++++++++++++++++++- 1 file changed, 150 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index d254340f49..cc0b22afe3 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3565,12 +3565,12 @@ public final class BluetoothAdapter { } @Override - public void onDeviceDisconnected(BluetoothDevice device) { + public void onDeviceDisconnected(BluetoothDevice device, int hciReason) { for (Map.Entry callbackExecutorEntry: mBluetoothConnectionCallbackExecutorMap.entrySet()) { BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); Executor executor = callbackExecutorEntry.getValue(); - executor.execute(() -> callback.onDeviceDisconnected(device)); + executor.execute(() -> callback.onDeviceDisconnected(device, hciReason)); } } }; @@ -3675,8 +3675,155 @@ public final class BluetoothAdapter { /** * Callback triggered when a bluetooth device (classic or BLE) is disconnected * @param device is the disconnected bluetooth device + * @param reason is the disconnect reason */ - public void onDeviceDisconnected(BluetoothDevice device) {} + public void onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason) {} + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "REASON_" }, value = { + REASON_UNKNOWN, + REASON_LOCAL_REQUEST, + REASON_REMOTE_REQUEST, + REASON_LOCAL_ERROR, + REASON_REMOTE_ERROR, + REASON_TIMEOUT, + REASON_SECURITY, + REASON_SYSTEM_POLICY, + REASON_RESOURCE_LIMIT_REACHED, + REASON_CONNECTION_EXISTS, + REASON_BAD_PARAMETERS}) + public @interface DisconnectReason {} + + /** + * Indicates that the ACL disconnected due to an unknown reason. + */ + public static final int REASON_UNKNOWN = 0; + + /** + * Indicates that the ACL disconnected due to an explicit request from the local device. + *

+ * Example cause: This is a normal disconnect reason, e.g., user/app initiates + * disconnection. + */ + public static final int REASON_LOCAL_REQUEST = 1; + + /** + * Indicates that the ACL disconnected due to an explicit request from the remote device. + *

+ * Example cause: This is a normal disconnect reason, e.g., user/app initiates + * disconnection. + *

+ * Example solution: The app can also prompt the user to check their remote device. + */ + public static final int REASON_REMOTE_REQUEST = 2; + + /** + * Generic disconnect reason indicating the ACL disconnected due to an error on the local + * device. + *

+ * Example solution: Prompt the user to check their local device (e.g., phone, car + * headunit). + */ + public static final int REASON_LOCAL_ERROR = 3; + + /** + * Generic disconnect reason indicating the ACL disconnected due to an error on the remote + * device. + *

+ * Example solution: Prompt the user to check their remote device (e.g., headset, car + * headunit, watch). + */ + public static final int REASON_REMOTE_ERROR = 4; + + /** + * Indicates that the ACL disconnected due to a timeout. + *

+ * Example cause: remote device might be out of range. + *

+ * Example solution: Prompt user to verify their remote device is on or in + * connection/pairing mode. + */ + public static final int REASON_TIMEOUT = 5; + + /** + * Indicates that the ACL disconnected due to link key issues. + *

+ * Example cause: Devices are either unpaired or remote device is refusing our pairing + * request. + *

+ * Example solution: Prompt user to unpair and pair again. + */ + public static final int REASON_SECURITY = 6; + + /** + * Indicates that the ACL disconnected due to the local device's system policy. + *

+ * Example cause: privacy policy, power management policy, permissions, etc. + *

+ * Example solution: Prompt the user to check settings, or check with their system + * administrator (e.g. some corp-managed devices do not allow OPP connection). + */ + public static final int REASON_SYSTEM_POLICY = 7; + + /** + * Indicates that the ACL disconnected due to resource constraints, either on the local + * device or the remote device. + *

+ * Example cause: controller is busy, memory limit reached, maximum number of connections + * reached. + *

+ * Example solution: The app should wait and try again. If still failing, prompt the user + * to disconnect some devices, or toggle Bluetooth on the local and/or the remote device. + */ + public static final int REASON_RESOURCE_LIMIT_REACHED = 8; + + /** + * Indicates that the ACL disconnected because another ACL connection already exists. + */ + public static final int REASON_CONNECTION_EXISTS = 9; + + /** + * Indicates that the ACL disconnected due to incorrect parameters passed in from the app. + *

+ * Example solution: Change parameters and try again. If error persists, the app can report + * telemetry and/or log the error in a bugreport. + */ + public static final int REASON_BAD_PARAMETERS = 10; + + /** + * Returns human-readable strings corresponding to {@link DisconnectReason}. + */ + public static String disconnectReasonText(@DisconnectReason int reason) { + switch (reason) { + case REASON_UNKNOWN: + return "Reason unknown"; + case REASON_LOCAL_REQUEST: + return "Local request"; + case REASON_REMOTE_REQUEST: + return "Remote request"; + case REASON_LOCAL_ERROR: + return "Local error"; + case REASON_REMOTE_ERROR: + return "Remote error"; + case REASON_TIMEOUT: + return "Timeout"; + case REASON_SECURITY: + return "Security"; + case REASON_SYSTEM_POLICY: + return "System policy"; + case REASON_RESOURCE_LIMIT_REACHED: + return "Resource constrained"; + case REASON_CONNECTION_EXISTS: + return "Connection already exists"; + case REASON_BAD_PARAMETERS: + return "Bad parameters"; + default: + return "Unrecognized disconnect reason: " + reason; + } + } } /** -- cgit v1.2.3 From 6eb9300814c54c1096c67b124bbfc245495f9588 Mon Sep 17 00:00:00 2001 From: Martin Brabham Date: Tue, 16 Mar 2021 21:14:40 -0700 Subject: Add new @SystemApi for specifying AddressType and IRK Bug: 178234318 Test: compiles and runs Tag: #feature Change-Id: Ib67e681af01260df98602003b2aca47963494c6f --- .../java/android/bluetooth/BluetoothAdapter.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index cc0b22afe3..38863c2c8c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -52,6 +52,8 @@ import android.os.SystemProperties; import android.util.Log; import android.util.Pair; +import com.android.internal.util.Preconditions; + import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -3118,6 +3120,25 @@ public final class BluetoothAdapter { return true; } + /** + * Determines whether a String Bluetooth address, such as "00:43:A8:23:10:F0" + * is a RANDOM STATIC address. + * + * RANDOM STATIC: (addr & 0b11) == 0b11 + * RANDOM RESOLVABLE: (addr & 0b11) == 0b10 + * RANDOM non-RESOLVABLE: (addr & 0b11) == 0b00 + * + * @param address Bluetooth address as string + * @return true if the 2 Least Significant Bits of the address equals 0b11. + * + * @hide + */ + public static boolean isAddressRandomStatic(@NonNull String address) { + Preconditions.checkNotNull(address); + return checkBluetoothAddress(address) + && (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11; + } + @UnsupportedAppUsage /*package*/ IBluetoothManager getBluetoothManager() { return mManagerService; -- cgit v1.2.3 From 723962b9f7bc5da3c3ac18e735e4a1f6fa100e7c Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Wed, 24 Feb 2021 04:09:05 +0000 Subject: Runtime permission attribution improvements When an app is proxying access to runtime permission protected data it needs to check whether the calling app has a permission to the data it is about to proxy which leaves a trace in app ops that the requesting app perofmed a data access. However, then the app doing the work needs to get the protected data itself from the OS which access gets attributed only to itself. As a result there are two data accesses in app ops where only the first one is a proxy one that app A got access to Foo through app B - that is the one we want to show in the permission tracking UIs - and one for the data access - that is the one we would want to blame on the calling app, and in fact, these two accesses should be one - that app A accessed Foo though B. This limitation requires fragile one off workarounds where both accesses use the same attribution tag and sys UI has hardcoded rules to dedupe. Since this is not documented we cannot expect that the ecosystem would reliably do this workaround in apps that that the workaround in the OS would be respected by every OEM. This change adds a mechaism to resolve this issue. It allows for an app to create an attribution context for another app and then any private data access thorugh this context would result in a single app op blame that A accessed Foo though B, i.e. we no longer have double accounting. Also this can be nested through apps, e.g. app A asks app B which asks app C for contacts. In this case app B creates an attribution context for app A and calls into app C which creates an attribution context for app B. When app C gets contacts the entire attribution chain would get a porper, single blame: that C accessed the data, that B got the data from C, and that A got the data form B. Furthermore, this mechanism ensures that apps cannot forget to check permissions for the caller before proxying private data. In our example B and C don't need to check the permisisons for A and B, respectively, since the permisisons for the entire attribution chain are checked before data delivery. Attribution chains are not forgeable preventing a bad actor to create an arbitrary one - each attribution is created by the app it refers to and points to a chain of attributions created by their corresponding apps. This change also fixes a bug where all content provider accesses were double counted in app ops due to double noting. While at this it also fixes that apps can now access their own last ops. There was a bug where one could not pass null getting the attributed ops from a historical package ops while this is a valid use case since if there is no attribution everything is mapped to the null tag. There were some app op APIs not being piped thorough the app ops delegate and by extension through the app ops policy. Also now that we have nice way to express the permission chain in a call we no longer need the special casing in activity manager to handle content provider accesses through the OS. Fixed a bug where we don't properly handle the android.os.shell calls with an invlaid tag which was failing while the shell can do any tag. Finally, to ensure the mechanims is validated and works end-to-end we are adding support for a voice recognizer to blame the client app for the mic access. The recognition service can create a blaming context when opening the mic and if the mic is open, which would do all permission checks, we would not do so again. Since changes to PermissionChercker for handling attribution sources were made the CL also hooks up renounced permissoins in the request permission flow and in the permission checks. bug:158792096 bug:180647319 Test:atest CtsPermissionsTestCases atest CtsPermissions2TestCases atest CtsPermissions3TestCases atest CtsPermissions4TestCases atest CtsPermissions5TestCases atest CtsAppOpsTestCases atest CtsAppOps2TestCases Change-Id: Ib04585515d3dc3956966005ae9d94955b2f3ee08 --- framework/java/android/bluetooth/BluetoothAdapter.java | 1 - 1 file changed, 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index a3d19ca642..0be7b732b4 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -745,7 +745,6 @@ public final class BluetoothAdapter { * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. */ BluetoothAdapter(IBluetoothManager managerService) { - if (managerService == null) { throw new IllegalArgumentException("bluetooth manager service is null"); } -- cgit v1.2.3 From 5131226e72c1933c210a0b30635bf8f636363235 Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Thu, 1 Apr 2021 11:00:16 +0100 Subject: Pass AttributionSource to bluetooth scanning methods. This passes the AttributionSource to AdapterService and GattService methods that perform scanning or discovery. Bug: 183203469 Test: atest GattServiceTest Test: atest AdapterServiceTest Test: atest CtsPermissionTestCases:android.permission.cts.NearbyDevicesPermissionTest Change-Id: Id68558624fbae69eac3a8613b9536eb6e0df75bf --- framework/java/android/bluetooth/BluetoothAdapter.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 0be7b732b4..5446deb560 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -38,12 +38,14 @@ import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.compat.annotation.UnsupportedAppUsage; +import android.content.AttributionSource; import android.content.Context; import android.os.BatteryStats; import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.ParcelUuid; +import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -853,8 +855,8 @@ public final class BluetoothAdapter { } synchronized (mLock) { if (sBluetoothLeScanner == null) { - sBluetoothLeScanner = new BluetoothLeScanner(mManagerService, getOpPackageName(), - getAttributionTag()); + sBluetoothLeScanner = + new BluetoothLeScanner(mManagerService, getAttributionSource()); } } return sBluetoothLeScanner; @@ -1664,13 +1666,11 @@ public final class BluetoothAdapter { return ActivityThread.currentOpPackageName(); } - private String getAttributionTag() { - // Workaround for legacy API for getting a BluetoothAdapter not - // passing a context + private AttributionSource getAttributionSource() { if (mContext != null) { - return mContext.getAttributionTag(); + return mContext.getAttributionSource(); } - return null; + return new AttributionSource(Process.myUid(), ActivityThread.currentOpPackageName(), null); } /** @@ -1710,7 +1710,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.startDiscovery(getOpPackageName(), getAttributionTag()); + return mService.startDiscovery(getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); -- cgit v1.2.3 From c382c0edc39e4dc6e286a4bc07ea69a7ee32fb02 Mon Sep 17 00:00:00 2001 From: Martin Brabham Date: Fri, 19 Mar 2021 00:07:02 -0700 Subject: OOB: Implement generateLocalOutOfBand API CTS-Coverage-Bug: 184395281 Bug: 178007935 Tag: #feature Test: manual Change-Id: I5bc11ac13d9cbb8f76f422aa4aea8295ebec95b4 --- .../java/android/bluetooth/BluetoothAdapter.java | 163 +++++++++++++++++++++ 1 file changed, 163 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 0be7b732b4..b6ca8d8131 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -28,6 +28,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.app.ActivityThread; import android.app.PropertyInvalidatedCache; +import android.bluetooth.BluetoothDevice.Transport; import android.bluetooth.BluetoothProfile.ConnectionPolicy; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; @@ -3046,6 +3047,168 @@ public final class BluetoothAdapter { return false; } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "OOB_ERROR_" }, value = { + OOB_ERROR_UNKNOWN, + OOB_ERROR_ANOTHER_ACTIVE_REQUEST, + OOB_ERROR_ADAPTER_DISABLED + }) + public @interface OobError {} + + /** + * An unknown error has occurred in the controller, stack, or callback pipeline. + * + * @hide + */ + @SystemApi + public static final int OOB_ERROR_UNKNOWN = 0; + + /** + * If another application has already requested {@link OobData} then another fetch will be + * disallowed until the callback is removed. + * + * @hide + */ + @SystemApi + public static final int OOB_ERROR_ANOTHER_ACTIVE_REQUEST = 1; + + /** + * The adapter is currently disabled, please enable it. + * + * @hide + */ + @SystemApi + public static final int OOB_ERROR_ADAPTER_DISABLED = 2; + + /** + * Provides callback methods for receiving {@link OobData} from the host stack, as well as an + * error interface in order to allow the caller to determine next steps based on the {@link + * ErrorCode}. + * + * @hide + */ + @SystemApi + public interface OobDataCallback { + /** + * Handles the {@link OobData} received from the host stack. + * + * @param transport - whether the {@link OobData} is generated for LE or Classic. + * @param oobData - data generated in the host stack(LE) or controller (Classic) + * + * @hide + */ + void onOobData(@Transport int transport, @Nullable OobData oobData); + + /** + * Provides feedback when things don't go as expected. + * + * @param errorCode - the code descibing the type of error that occurred. + * + * @hide + */ + void onError(@OobError int errorCode); + } + + /** + * Wraps an AIDL interface around an {@link OobDataCallback} interface. + * + * @see {@link IBluetoothOobDataCallback} for interface definition. + * + * @hide + */ + public class WrappedOobDataCallback extends IBluetoothOobDataCallback.Stub { + private final OobDataCallback mCallback; + private final Executor mExecutor; + + /** + * @param callback - object to receive {@link OobData} must be a non null argument + * + * @throws NullPointerException if the callback is null. + */ + WrappedOobDataCallback(@NonNull OobDataCallback callback, + @NonNull @CallbackExecutor Executor executor) { + Preconditions.checkNotNull(callback); + Preconditions.checkNotNull(executor); + mCallback = callback; + mExecutor = executor; + } + /** + * Wrapper function to relay to the {@link OobDataCallback#onOobData} + * + * @param transport - whether the {@link OobData} is generated for LE or Classic. + * @param oobData - data generated in the host stack(LE) or controller (Classic) + * + * @hide + */ + public void onOobData(@Transport int transport, OobData oobData) { + mExecutor.execute(new Runnable() { + public void run() { + mCallback.onOobData(transport, oobData); + } + }); + } + /** + * Wrapper function to relay to the {@link OobDataCallback#onError} + * + * @param errorCode - the code descibing the type of error that occurred. + * + * @hide + */ + public void onError(@OobError int errorCode) { + mExecutor.execute(new Runnable() { + public void run() { + mCallback.onError(errorCode); + } + }); + } + } + + /** + * Fetches a secret data value that can be used for a secure and simple pairing experience. + * + *

This is the Local Out of Band data the comes from the + * + *

This secret is the local Out of Band data. This data is used to securely and quickly + * pair two devices with minimal user interaction. + * + *

For example, this secret can be transferred to a remote device out of band (meaning any + * other way besides using bluetooth). Once the remote device finds this device using the + * information given in the data, such as the PUBLIC ADDRESS, the remote device could then + * connect to this device using this secret when the pairing sequenece asks for the secret. + * This device will respond by automatically accepting the pairing due to the secret being so + * trustworthy. + * + * @param transport - provide type of transport (e.g. LE or Classic). + * @param callback - target object to receive the {@link OobData} value. + * + * @throws NullPointerException if callback is null. + * @throws IllegalArgumentException if the transport is not valid. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public void generateLocalOobData(@Transport int transport, + @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback) { + if (transport != BluetoothDevice.TRANSPORT_BREDR && transport + != BluetoothDevice.TRANSPORT_LE) { + throw new IllegalArgumentException("Invalid transport '" + transport + "'!"); + } + Preconditions.checkNotNull(callback); + if (!isEnabled()) { + Log.w(TAG, "generateLocalOobData(): Adapter isn't enabled!"); + callback.onError(OOB_ERROR_ADAPTER_DISABLED); + } else { + try { + mService.generateLocalOobData(transport, new WrappedOobDataCallback(callback, + executor)); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + } + } + /** * Enable control of the Bluetooth Adapter for a single application. * -- cgit v1.2.3 From e47bc17c5796bad3f28347c9965f4e5204058255 Mon Sep 17 00:00:00 2001 From: Martin Brabham Date: Fri, 19 Mar 2021 00:07:02 -0700 Subject: OOB: Implement getLocalOutOfBand API CTS-Coverage-Bug: 184395281 Bug: 178007935 Tag: #feature Test: manual Change-Id: I5bc11ac13d9cbb8f76f422aa4aea8295ebec95b4 Merged-In: I5bc11ac13d9cbb8f76f422aa4aea8295ebec95b4 --- .../java/android/bluetooth/BluetoothAdapter.java | 163 +++++++++++++++++++++ 1 file changed, 163 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 38863c2c8c..7d62327738 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -28,6 +28,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.app.ActivityThread; import android.app.PropertyInvalidatedCache; +import android.bluetooth.BluetoothDevice.Transport; import android.bluetooth.BluetoothProfile.ConnectionPolicy; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; @@ -3013,6 +3014,168 @@ public final class BluetoothAdapter { return false; } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "OOB_ERROR_" }, value = { + OOB_ERROR_UNKNOWN, + OOB_ERROR_ANOTHER_ACTIVE_REQUEST, + OOB_ERROR_ADAPTER_DISABLED + }) + public @interface OobError {} + + /** + * An unknown error has occurred in the controller, stack, or callback pipeline. + * + * @hide + */ + @SystemApi + public static final int OOB_ERROR_UNKNOWN = 0; + + /** + * If another application has already requested {@link OobData} then another fetch will be + * disallowed until the callback is removed. + * + * @hide + */ + @SystemApi + public static final int OOB_ERROR_ANOTHER_ACTIVE_REQUEST = 1; + + /** + * The adapter is currently disabled, please enable it. + * + * @hide + */ + @SystemApi + public static final int OOB_ERROR_ADAPTER_DISABLED = 2; + + /** + * Provides callback methods for receiving {@link OobData} from the host stack, as well as an + * error interface in order to allow the caller to determine next steps based on the {@link + * ErrorCode}. + * + * @hide + */ + @SystemApi + public interface OobDataCallback { + /** + * Handles the {@link OobData} received from the host stack. + * + * @param transport - whether the {@link OobData} is generated for LE or Classic. + * @param oobData - data generated in the host stack(LE) or controller (Classic) + * + * @hide + */ + void onOobData(@Transport int transport, @Nullable OobData oobData); + + /** + * Provides feedback when things don't go as expected. + * + * @param errorCode - the code descibing the type of error that occurred. + * + * @hide + */ + void onError(@OobError int errorCode); + } + + /** + * Wraps an AIDL interface around an {@link OobDataCallback} interface. + * + * @see {@link IBluetoothOobDataCallback} for interface definition. + * + * @hide + */ + public class WrappedOobDataCallback extends IBluetoothOobDataCallback.Stub { + private final OobDataCallback mCallback; + private final Executor mExecutor; + + /** + * @param callback - object to receive {@link OobData} must be a non null argument + * + * @throws NullPointerException if the callback is null. + */ + WrappedOobDataCallback(@NonNull OobDataCallback callback, + @NonNull @CallbackExecutor Executor executor) { + Preconditions.checkNotNull(callback); + Preconditions.checkNotNull(executor); + mCallback = callback; + mExecutor = executor; + } + /** + * Wrapper function to relay to the {@link OobDataCallback#onOobData} + * + * @param transport - whether the {@link OobData} is generated for LE or Classic. + * @param oobData - data generated in the host stack(LE) or controller (Classic) + * + * @hide + */ + public void onOobData(@Transport int transport, OobData oobData) { + mExecutor.execute(new Runnable() { + public void run() { + mCallback.onOobData(transport, oobData); + } + }); + } + /** + * Wrapper function to relay to the {@link OobDataCallback#onError} + * + * @param errorCode - the code descibing the type of error that occurred. + * + * @hide + */ + public void onError(@OobError int errorCode) { + mExecutor.execute(new Runnable() { + public void run() { + mCallback.onError(errorCode); + } + }); + } + } + + /** + * Fetches a secret data value that can be used for a secure and simple pairing experience. + * + *

This is the Local Out of Band data the comes from the + * + *

This secret is the local Out of Band data. This data is used to securely and quickly + * pair two devices with minimal user interaction. + * + *

For example, this secret can be transferred to a remote device out of band (meaning any + * other way besides using bluetooth). Once the remote device finds this device using the + * information given in the data, such as the PUBLIC ADDRESS, the remote device could then + * connect to this device using this secret when the pairing sequenece asks for the secret. + * This device will respond by automatically accepting the pairing due to the secret being so + * trustworthy. + * + * @param transport - provide type of transport (e.g. LE or Classic). + * @param callback - target object to receive the {@link OobData} value. + * + * @throws NullPointerException if callback is null. + * @throws IllegalArgumentException if the transport is not valid. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public void generateLocalOobData(@Transport int transport, + @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback) { + if (transport != BluetoothDevice.TRANSPORT_BREDR && transport + != BluetoothDevice.TRANSPORT_LE) { + throw new IllegalArgumentException("Invalid transport '" + transport + "'!"); + } + Preconditions.checkNotNull(callback); + if (!isEnabled()) { + Log.w(TAG, "generateLocalOobData(): Adapter isn't enabled!"); + callback.onError(OOB_ERROR_ADAPTER_DISABLED); + } else { + try { + mService.generateLocalOobData(transport, new WrappedOobDataCallback(callback, + executor)); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + } + } + /** * Enable control of the Bluetooth Adapter for a single application. * -- cgit v1.2.3 From 63a11e8871f9aed864dbafd55cfe4c3646b01288 Mon Sep 17 00:00:00 2001 From: Martin Brabham Date: Wed, 14 Apr 2021 11:45:35 -0700 Subject: OOB generateLocalOobData unhide @SystemApi callback methods CTS-Coverage-Bug: 184395281 Bug: 178007935 Tag: #feature Test: compiles Change-Id: I2d4167a6c92ee0cc24da12df206838161c8f3318 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ---- 1 file changed, 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 79fd8072f9..236185e2a2 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3095,8 +3095,6 @@ public final class BluetoothAdapter { * * @param transport - whether the {@link OobData} is generated for LE or Classic. * @param oobData - data generated in the host stack(LE) or controller (Classic) - * - * @hide */ void onOobData(@Transport int transport, @Nullable OobData oobData); @@ -3104,8 +3102,6 @@ public final class BluetoothAdapter { * Provides feedback when things don't go as expected. * * @param errorCode - the code descibing the type of error that occurred. - * - * @hide */ void onError(@OobError int errorCode); } -- cgit v1.2.3 From 8f80e4a05b3f1b227f40de5ec0e9a6297154ffc0 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 2 Apr 2021 08:06:09 -0600 Subject: Update Bluetooth API annotations. Recent work has introduced a new "Nearby devices" runtime permission which protects all existing Bluetooth APIs; we've done this by defining a to convert the old BLUETOOTH and BLUETOOTH_ADMIN permissions into one of three new permissions: * BLUETOOTH_ADVERTISE: Required to be able to advertise to nearby Bluetooth devices. * BLUETOOTH_CONNECT: Allows applications to connect to paired bluetooth devices. * BLUETOOTH_SCAN: Required to be able to discover and pair nearby Bluetooth devices. At its core, this change begins updating the Bluetooth APIs to have correct @RequiresPermission indicating which permission is actually enforced internally. To ensure alignment across Binder, the newly added "RequiresPermissionChecker" Error Prone checker was used to discover any inconsistencies, ensuring correctness from server-side enforcement up through to the public APIs. In addition, since developers will continue building apps for both modern and legacy platforms, this change introduces new auto-doc annotations which will emit helpful consistent documentation describing the behavior of older devices that are still using the old permission model. Bug: 183626724 Test: ./build/soong/soong_ui.bash --make-mode Bluetooth RUN_ERROR_PRONE=true Change-Id: I02aa127e8e07f239561f4f2a3bbdfc6fccb82f7f --- .../java/android/bluetooth/BluetoothAdapter.java | 269 +++++++++++++++------ 1 file changed, 200 insertions(+), 69 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 236185e2a2..972e9e6d73 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -17,7 +17,6 @@ package android.bluetooth; -import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; @@ -25,11 +24,18 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.app.ActivityThread; import android.app.PropertyInvalidatedCache; import android.bluetooth.BluetoothDevice.Transport; import android.bluetooth.BluetoothProfile.ConnectionPolicy; +import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; +import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission; +import android.bluetooth.annotations.RequiresBluetoothConnectPermission; +import android.bluetooth.annotations.RequiresBluetoothLocationPermission; +import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; +import android.bluetooth.annotations.RequiresBluetoothScanPermission; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.PeriodicAdvertisingManager; @@ -98,11 +104,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. *

*

This class is thread safe.

- *

Note: - * Most methods require the {@link android.Manifest.permission#BLUETOOTH} - * permission and some also require the - * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. - *

*
*

Developer Guides

*

@@ -144,8 +145,8 @@ public final class BluetoothAdapter { *

Always contains the extra fields {@link #EXTRA_STATE} and {@link * #EXTRA_PREVIOUS_STATE} containing the new and old states * respectively. - *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ + @RequiresLegacyBluetoothPermission @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED"; @@ -278,8 +279,10 @@ public final class BluetoothAdapter { *

Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED} * for global notification whenever the scan mode changes. For example, an * application can be notified when the device has ended discoverability. - *

Requires {@link android.Manifest.permission#BLUETOOTH} */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothAdvertisePermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"; @@ -305,8 +308,10 @@ public final class BluetoothAdapter { * has rejected the request or an error has occurred. *

Applications can also listen for {@link #ACTION_STATE_CHANGED} * for global notification whenever Bluetooth is turned on or off. - *

Requires {@link android.Manifest.permission#BLUETOOTH} */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"; @@ -325,10 +330,12 @@ public final class BluetoothAdapter { * has rejected the request or an error has occurred. *

Applications can also listen for {@link #ACTION_STATE_CHANGED} * for global notification whenever Bluetooth is turned on or off. - *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @hide */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE"; @@ -355,8 +362,10 @@ public final class BluetoothAdapter { *

Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes * respectively. - *

Requires {@link android.Manifest.permission#BLUETOOTH} */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothScanPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; @@ -508,15 +517,19 @@ public final class BluetoothAdapter { * progress, and existing connections will experience limited bandwidth * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing * discovery. - *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothScanPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED"; /** * Broadcast Action: The local Bluetooth adapter has finished the device * discovery process. - *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothScanPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED"; @@ -526,8 +539,10 @@ public final class BluetoothAdapter { *

This name is visible to remote Bluetooth devices. *

Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing * the name. - *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED"; /** @@ -559,9 +574,10 @@ public final class BluetoothAdapter { * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE} * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. - * - *

Requires {@link android.Manifest.permission#BLUETOOTH} to receive. */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"; @@ -870,7 +886,7 @@ public final class BluetoothAdapter { * * @return true if the local adapter is turned on */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission public boolean isEnabled() { return getState() == BluetoothAdapter.STATE_ON; } @@ -921,6 +937,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disableBLE() { if (!isBleScanAlwaysAvailable()) { return false; @@ -966,6 +983,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableBLE() { if (!isBleScanAlwaysAvailable()) { return false; @@ -986,6 +1004,7 @@ public final class BluetoothAdapter { new PropertyInvalidatedCache( 8, BLUETOOTH_GET_STATE_CACHE_PROPERTY) { @Override + @SuppressLint("AndroidFrameworkRequiresPermission") protected Integer recompute(Void query) { try { return mService.getState(); @@ -1039,7 +1058,7 @@ public final class BluetoothAdapter { * * @return current state of Bluetooth adapter */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission @AdapterState public int getState() { int state = getStateInternal(); @@ -1075,7 +1094,7 @@ public final class BluetoothAdapter { * @return current state of Bluetooth adapter * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission @AdapterState @UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine " + "whether you can use BLE & BT classic.") @@ -1122,7 +1141,9 @@ public final class BluetoothAdapter { * * @return true to indicate adapter startup has begun, or false on immediate error */ - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enable() { if (isEnabled()) { if (DBG) { @@ -1159,7 +1180,9 @@ public final class BluetoothAdapter { * * @return true to indicate adapter shutdown has begun, or false on immediate error */ - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disable() { try { return mManagerService.disable(ActivityThread.currentPackageName(), true); @@ -1172,13 +1195,13 @@ public final class BluetoothAdapter { /** * Turn off the local Bluetooth adapter and don't persist the setting. * - *

Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} - * permission - * * @return true to indicate adapter shutdown has begun, or false on immediate error * @hide */ @UnsupportedAppUsage(trackingBug = 171933273) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disable(boolean persist) { try { @@ -1195,7 +1218,12 @@ public final class BluetoothAdapter { * * @return Bluetooth hardware address as string */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.LOCAL_MAC_ADDRESS, + }) public String getAddress() { try { return mManagerService.getAddress(); @@ -1208,10 +1236,12 @@ public final class BluetoothAdapter { /** * Get the friendly Bluetooth name of the local Bluetooth adapter. *

This name is visible to remote Bluetooth devices. - *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @return the Bluetooth name, or null on error */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getName() { try { return mManagerService.getName(); @@ -1228,7 +1258,7 @@ public final class BluetoothAdapter { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean factoryReset() { try { mServiceLock.readLock().lock(); @@ -1253,7 +1283,9 @@ public final class BluetoothAdapter { * @hide */ @UnsupportedAppUsage - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public @Nullable ParcelUuid[] getUuids() { if (getState() != STATE_ON) { return null; @@ -1285,7 +1317,9 @@ public final class BluetoothAdapter { * @param name a valid Bluetooth name * @return true if the name was set, false otherwise */ - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setName(String name) { if (getState() != STATE_ON) { return false; @@ -1311,7 +1345,9 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothClass getBluetoothClass() { if (getState() != STATE_ON) { return null; @@ -1340,7 +1376,7 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBluetoothClass(BluetoothClass bluetoothClass) { if (getState() != STATE_ON) { return false; @@ -1367,7 +1403,9 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @IoCapability public int getIoCapability() { if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; @@ -1395,7 +1433,7 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setIoCapability(@IoCapability int capability) { if (getState() != STATE_ON) return false; try { @@ -1418,7 +1456,9 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @IoCapability public int getLeIoCapability() { if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; @@ -1446,7 +1486,7 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setLeIoCapability(@IoCapability int capability) { if (getState() != STATE_ON) return false; try { @@ -1475,7 +1515,9 @@ public final class BluetoothAdapter { * * @return scan mode */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothScanPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) @ScanMode public int getScanMode() { if (getState() != STATE_ON) { @@ -1522,7 +1564,9 @@ public final class BluetoothAdapter { */ @UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which " + "shows UI that confirms the user wants to go into discoverable mode.") - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothScanPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean setScanMode(@ScanMode int mode, long durationMillis) { if (getState() != STATE_ON) { return false; @@ -1571,7 +1615,9 @@ public final class BluetoothAdapter { * @hide */ @UnsupportedAppUsage - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothScanPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean setScanMode(@ScanMode int mode) { if (getState() != STATE_ON) { return false; @@ -1591,6 +1637,7 @@ public final class BluetoothAdapter { /** @hide */ @UnsupportedAppUsage + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public int getDiscoverableTimeout() { if (getState() != STATE_ON) { return -1; @@ -1610,6 +1657,7 @@ public final class BluetoothAdapter { /** @hide */ @UnsupportedAppUsage + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void setDiscoverableTimeout(int timeout) { if (getState() != STATE_ON) { return; @@ -1635,7 +1683,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public long getDiscoveryEndMillis() { try { mServiceLock.readLock().lock(); @@ -1703,7 +1751,10 @@ public final class BluetoothAdapter { * * @return true on success, false on error */ - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothScanPermission + @RequiresBluetoothLocationPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startDiscovery() { if (getState() != STATE_ON) { return false; @@ -1737,7 +1788,9 @@ public final class BluetoothAdapter { * * @return true on success, false on error */ - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothScanPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean cancelDiscovery() { if (getState() != STATE_ON) { return false; @@ -1773,7 +1826,9 @@ public final class BluetoothAdapter { * * @return true if discovering */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothScanPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean isDiscovering() { if (getState() != STATE_ON) { return false; @@ -1805,7 +1860,11 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + android.Manifest.permission.MODIFY_PHONE_STATE, + }) public boolean removeActiveDevice(@ActiveDeviceUse int profiles) { if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL && profiles != ACTIVE_DEVICE_ALL) { @@ -1845,7 +1904,11 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + android.Manifest.permission.MODIFY_PHONE_STATE, + }) public boolean setActiveDevice(@NonNull BluetoothDevice device, @ActiveDeviceUse int profiles) { if (device == null) { @@ -1889,7 +1952,11 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + android.Manifest.permission.MODIFY_PHONE_STATE, + }) public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) { try { mServiceLock.readLock().lock(); @@ -1917,7 +1984,10 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) { try { mServiceLock.readLock().lock(); @@ -1938,6 +2008,7 @@ public final class BluetoothAdapter { * * @return true if Multiple Advertisement feature is supported */ + @RequiresLegacyBluetoothPermission public boolean isMultipleAdvertisementSupported() { if (getState() != STATE_ON) { return false; @@ -1981,6 +2052,7 @@ public final class BluetoothAdapter { new PropertyInvalidatedCache( 8, BLUETOOTH_FILTERING_CACHE_PROPERTY) { @Override + @SuppressLint("AndroidFrameworkRequiresPermission") protected Boolean recompute(Void query) { try { mServiceLock.readLock().lock(); @@ -2012,6 +2084,7 @@ public final class BluetoothAdapter { * * @return true if chipset supports on-chip filtering */ + @RequiresLegacyBluetoothPermission public boolean isOffloadedFilteringSupported() { if (!getLeAccess()) { return false; @@ -2024,6 +2097,7 @@ public final class BluetoothAdapter { * * @return true if chipset supports on-chip scan batching */ + @RequiresLegacyBluetoothPermission public boolean isOffloadedScanBatchingSupported() { if (!getLeAccess()) { return false; @@ -2046,6 +2120,7 @@ public final class BluetoothAdapter { * * @return true if chipset supports LE 2M PHY feature */ + @RequiresLegacyBluetoothPermission public boolean isLe2MPhySupported() { if (!getLeAccess()) { return false; @@ -2068,6 +2143,7 @@ public final class BluetoothAdapter { * * @return true if chipset supports LE Coded PHY feature */ + @RequiresLegacyBluetoothPermission public boolean isLeCodedPhySupported() { if (!getLeAccess()) { return false; @@ -2090,6 +2166,7 @@ public final class BluetoothAdapter { * * @return true if chipset supports LE Extended Advertising feature */ + @RequiresLegacyBluetoothPermission public boolean isLeExtendedAdvertisingSupported() { if (!getLeAccess()) { return false; @@ -2112,6 +2189,7 @@ public final class BluetoothAdapter { * * @return true if chipset supports LE Periodic Advertising feature */ + @RequiresLegacyBluetoothPermission public boolean isLePeriodicAdvertisingSupported() { if (!getLeAccess()) { return false; @@ -2135,6 +2213,7 @@ public final class BluetoothAdapter { * * @return the maximum LE advertising data length. */ + @RequiresLegacyBluetoothPermission public int getLeMaximumAdvertisingDataLength() { if (!getLeAccess()) { return 0; @@ -2172,7 +2251,9 @@ public final class BluetoothAdapter { * @return the maximum number of connected audio devices * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getMaxConnectedAudioDevices() { try { mServiceLock.readLock().lock(); @@ -2193,6 +2274,7 @@ public final class BluetoothAdapter { * @return true if there are hw entries available for matching beacons * @hide */ + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isHardwareTrackingFiltersAvailable() { if (!getLeAccess()) { return false; @@ -2223,6 +2305,7 @@ public final class BluetoothAdapter { * instead. */ @Deprecated + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { SynchronousResultReceiver receiver = new SynchronousResultReceiver(); requestControllerActivityEnergyInfo(receiver); @@ -2248,6 +2331,7 @@ public final class BluetoothAdapter { * @param result The callback to which to send the activity info. * @hide */ + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void requestControllerActivityEnergyInfo(ResultReceiver result) { try { mServiceLock.readLock().lock(); @@ -2275,7 +2359,9 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public @NonNull List getMostRecentlyConnectedDevices() { if (getState() != STATE_ON) { return new ArrayList<>(); @@ -2303,7 +2389,9 @@ public final class BluetoothAdapter { * * @return unmodifiable set of {@link BluetoothDevice}, or null on error */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public Set getBondedDevices() { if (getState() != STATE_ON) { return toDeviceSet(new BluetoothDevice[0]); @@ -2368,6 +2456,7 @@ public final class BluetoothAdapter { * This method must not be called when mService is null. */ @Override + @SuppressLint("AndroidFrameworkRequiresPermission") protected Integer recompute(Void query) { try { return mService.getAdapterConnectionState(); @@ -2401,6 +2490,7 @@ public final class BluetoothAdapter { * @hide */ @UnsupportedAppUsage + @RequiresLegacyBluetoothPermission public int getConnectionState() { if (getState() != STATE_ON) { return BluetoothAdapter.STATE_DISCONNECTED; @@ -2429,6 +2519,7 @@ public final class BluetoothAdapter { new PropertyInvalidatedCache( 8, BLUETOOTH_PROFILE_CACHE_PROPERTY) { @Override + @SuppressLint("AndroidFrameworkRequiresPermission") protected Integer recompute(Integer query) { try { mServiceLock.readLock().lock(); @@ -2471,7 +2562,10 @@ public final class BluetoothAdapter { * {@link BluetoothProfile#STATE_CONNECTED}, * {@link BluetoothProfile#STATE_DISCONNECTING} */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @SuppressLint("AndroidFrameworkRequiresPermission") public int getProfileConnectionState(int profile) { if (getState() != STATE_ON) { return BluetoothProfile.STATE_DISCONNECTED; @@ -2486,7 +2580,6 @@ public final class BluetoothAdapter { *

Use {@link BluetoothServerSocket#accept} to retrieve incoming * connections from a listening {@link BluetoothServerSocket}. *

Valid RFCOMM channels are in range 1 to 30. - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * * @param channel RFCOMM channel to listen on * @return a listening RFCOMM BluetoothServerSocket @@ -2494,6 +2587,9 @@ public final class BluetoothAdapter { * permissions, or channel in use. * @hide */ + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException { return listenUsingRfcommOn(channel, false, false); } @@ -2505,7 +2601,6 @@ public final class BluetoothAdapter { *

Use {@link BluetoothServerSocket#accept} to retrieve incoming * connections from a listening {@link BluetoothServerSocket}. *

Valid RFCOMM channels are in range 1 to 30. - *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} *

To auto assign a channel without creating a SDP record use * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. * @@ -2519,6 +2614,9 @@ public final class BluetoothAdapter { * @hide */ @UnsupportedAppUsage + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm, boolean min16DigitPin) throws IOException { BluetoothServerSocket socket = @@ -2559,7 +2657,9 @@ public final class BluetoothAdapter { * @throws IOException on error, for example Bluetooth not available, or insufficient * permissions, or channel in use. */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) throws IOException { return createNewRfcommSocketAndRecord(name, uuid, true, true); @@ -2591,7 +2691,9 @@ public final class BluetoothAdapter { * @throws IOException on error, for example Bluetooth not available, or insufficient * permissions, or channel in use. */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid) throws IOException { return createNewRfcommSocketAndRecord(name, uuid, false, false); @@ -2622,7 +2724,6 @@ public final class BluetoothAdapter { * closed, or if this application closes unexpectedly. *

Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to * connect to this socket from another device using the same {@link UUID}. - *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @param name service name for SDP record * @param uuid uuid for SDP record @@ -2632,12 +2733,15 @@ public final class BluetoothAdapter { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid) throws IOException { return createNewRfcommSocketAndRecord(name, uuid, false, true); } - + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt) throws IOException { BluetoothServerSocket socket; @@ -2663,6 +2767,7 @@ public final class BluetoothAdapter { * permissions. * @hide */ + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { BluetoothServerSocket socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, false, port); @@ -2694,6 +2799,7 @@ public final class BluetoothAdapter { * permissions. * @hide */ + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin) throws IOException { BluetoothServerSocket socket = @@ -2726,11 +2832,11 @@ public final class BluetoothAdapter { * permissions. * @hide */ + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { return listenUsingL2capOn(port, false, false); } - /** * Construct an insecure L2CAP server socket. * Call #accept to retrieve connections to this socket. @@ -2743,6 +2849,7 @@ public final class BluetoothAdapter { * permissions. * @hide */ + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException { Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port); BluetoothServerSocket socket = @@ -2769,11 +2876,14 @@ public final class BluetoothAdapter { /** * Read the local Out of Band Pairing Data - *

Requires {@link android.Manifest.permission#BLUETOOTH} * * @return Pair of Hash and Randomizer * @hide */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @SuppressLint("AndroidFrameworkRequiresPermission") public Pair readOutOfBandData() { return null; } @@ -2863,6 +2973,7 @@ public final class BluetoothAdapter { * @param profile * @param proxy Profile proxy object */ + @SuppressLint("AndroidFrameworkRequiresPermission") public void closeProfileProxy(int profile, BluetoothProfile proxy) { if (proxy == null) { return; @@ -2937,6 +3048,7 @@ public final class BluetoothAdapter { private final IBluetoothManagerCallback mManagerCallback = new IBluetoothManagerCallback.Stub() { + @SuppressLint("AndroidFrameworkRequiresPermission") public void onBluetoothServiceUp(IBluetooth bluetoothService) { if (DBG) { Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); @@ -3031,7 +3143,9 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableNoAutoConnect() { if (isEnabled()) { if (DBG) { @@ -3184,7 +3298,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void generateLocalOobData(@Transport int transport, @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback) { if (transport != BluetoothDevice.TRANSPORT_BREDR && transport @@ -3228,12 +3342,14 @@ public final class BluetoothAdapter { * reason. If Bluetooth is already on and if this function is called to turn * it on, the api will return true and a callback will be called. * - *

Requires {@link android.Manifest.permission#BLUETOOTH} - * * @param on True for on, false for off. * @param callback The callback to notify changes to the state. * @hide */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @SuppressLint("AndroidFrameworkRequiresPermission") public boolean changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback) { return false; @@ -3252,6 +3368,7 @@ public final class BluetoothAdapter { /** * @hide */ + @SuppressLint("AndroidFrameworkRequiresPermission") public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub { private BluetoothStateChangeCallback mCallback; @@ -3443,7 +3560,10 @@ public final class BluetoothAdapter { * instead. */ @Deprecated - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothScanPermission + @RequiresBluetoothLocationPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startLeScan(LeScanCallback callback) { return startLeScan(null, callback); } @@ -3462,7 +3582,10 @@ public final class BluetoothAdapter { * instead. */ @Deprecated - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothScanPermission + @RequiresBluetoothLocationPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) { if (DBG) { Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids)); @@ -3559,7 +3682,9 @@ public final class BluetoothAdapter { * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead. */ @Deprecated - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothScanPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void stopLeScan(LeScanCallback callback) { if (DBG) { Log.d(TAG, "stopLeScan()"); @@ -3600,7 +3725,9 @@ public final class BluetoothAdapter { * @throws IOException on error, for example Bluetooth not available, or insufficient * permissions, or unable to start this CoC */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public @NonNull BluetoothServerSocket listenUsingL2capChannel() throws IOException { BluetoothServerSocket socket = @@ -3646,7 +3773,9 @@ public final class BluetoothAdapter { * @throws IOException on error, for example Bluetooth not available, or insufficient * permissions, or unable to start this CoC */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public @NonNull BluetoothServerSocket listenUsingInsecureL2capChannel() throws IOException { BluetoothServerSocket socket = @@ -3691,7 +3820,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device, @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) { if (DBG) Log.d(TAG, "addOnMetadataChangedListener()"); @@ -3764,7 +3893,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device, @NonNull OnMetadataChangedListener listener) { if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()"); @@ -3853,6 +3982,7 @@ public final class BluetoothAdapter { * @throws IllegalArgumentException if the callback is already registered * @hide */ + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean registerBluetoothConnectionCallback(@NonNull @CallbackExecutor Executor executor, @NonNull BluetoothConnectionCallback callback) { if (DBG) Log.d(TAG, "registerBluetoothConnectionCallback()"); @@ -3895,6 +4025,7 @@ public final class BluetoothAdapter { * @return true if the callback was unregistered successfully, false otherwise * @hide */ + @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean unregisterBluetoothConnectionCallback( @NonNull BluetoothConnectionCallback callback) { if (DBG) Log.d(TAG, "unregisterBluetoothConnectionCallback()"); -- cgit v1.2.3 From 28253294ce8948cde84ce1e883b93ce1c75ac494 Mon Sep 17 00:00:00 2001 From: Martin Brabham Date: Wed, 14 Apr 2021 11:45:35 -0700 Subject: OOB generateLocalOobData unhide @SystemApi callback methods Bug: 178007935 Tag: #feature Test: compiles Change-Id: I2d4167a6c92ee0cc24da12df206838161c8f3318 Merged-In: I2d4167a6c92ee0cc24da12df206838161c8f3318 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ---- 1 file changed, 4 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 7d62327738..3802289dd6 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3062,8 +3062,6 @@ public final class BluetoothAdapter { * * @param transport - whether the {@link OobData} is generated for LE or Classic. * @param oobData - data generated in the host stack(LE) or controller (Classic) - * - * @hide */ void onOobData(@Transport int transport, @Nullable OobData oobData); @@ -3071,8 +3069,6 @@ public final class BluetoothAdapter { * Provides feedback when things don't go as expected. * * @param errorCode - the code descibing the type of error that occurred. - * - * @hide */ void onError(@OobError int errorCode); } -- cgit v1.2.3 From 36582c19d128599272825eea29793dc475f6c9fd Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 15 Apr 2021 08:31:42 -0600 Subject: Refine BluetoothLeAdvertiser permissions. Technically these APIs required both ADVERTISE and CONNECT, since internally it would attempt getting the device name as part of calculating packet lengths. These methods shouldn't require the CONNECT permission, so we add a getNameLengthForAdvertise() method internally to remove this dependency. Bug: 183626724 Test: ./build/soong/soong_ui.bash --make-mode Bluetooth RUN_ERROR_PRONE=true Change-Id: I245417bfc26d6d3a4f8be14077c7f1d271b5959e --- framework/java/android/bluetooth/BluetoothAdapter.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 972e9e6d73..df2c512ebf 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1251,6 +1251,18 @@ public final class BluetoothAdapter { return null; } + /** {@hide} */ + @RequiresBluetoothAdvertisePermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) + public int getNameLengthForAdvertise() { + try { + return mService.getNameLengthForAdvertise(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + return -1; + } + /** * Factory reset bluetooth settings. * -- cgit v1.2.3 From 5ba8bfca7e9adf5c6d8ee8180aebad6f04037d6c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 16 Apr 2021 09:53:23 -0600 Subject: More Bluetooth API annotation updates. This change adds a "BluetoothPermissionChecker" that ensures that all Bluetooth permission annotations are consistent. In addition, it verifies that all Bluetooth public APIs have been audited to be permission protected where relevant. We've currently standardized on saying that APIs that return device or Bluetooth state information (without sharing details about any particular remote Bluetooth device) do not need to be permission protected. This change is only annotations and has no behavior changes. Bug: 183626724 Test: ./build/soong/soong_ui.bash --make-mode Bluetooth RUN_ERROR_PRONE=true Change-Id: Ie80b15b058359bf1e9a6ee881b89cb3e5b584ca1 --- .../java/android/bluetooth/BluetoothAdapter.java | 56 +++++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index df2c512ebf..052a7733c2 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -21,6 +21,7 @@ import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresNoPermission; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -716,6 +717,7 @@ public final class BluetoothAdapter { * Bluetooth metadata listener. Overrides the default BluetoothMetadataListener * implementation. */ + @SuppressLint("AndroidFrameworkBluetoothPermission") private static final IBluetoothMetadataListener sBluetoothMetadataListener = new IBluetoothMetadataListener.Stub() { @Override @@ -747,6 +749,7 @@ public final class BluetoothAdapter { * @return the default local adapter, or null if Bluetooth is not supported on this hardware * platform */ + @RequiresNoPermission public static synchronized BluetoothAdapter getDefaultAdapter() { if (sAdapter == null) { IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE); @@ -792,6 +795,7 @@ public final class BluetoothAdapter { * @param address valid Bluetooth MAC address * @throws IllegalArgumentException if address is invalid */ + @RequiresNoPermission public BluetoothDevice getRemoteDevice(String address) { return new BluetoothDevice(address); } @@ -807,6 +811,7 @@ public final class BluetoothAdapter { * @param address Bluetooth MAC address (6 bytes) * @throws IllegalArgumentException if address is invalid */ + @RequiresNoPermission public BluetoothDevice getRemoteDevice(byte[] address) { if (address == null || address.length != 6) { throw new IllegalArgumentException("Bluetooth address must have 6 bytes"); @@ -824,6 +829,7 @@ public final class BluetoothAdapter { * Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported * on this device before calling this method. */ + @RequiresNoPermission public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { if (!getLeAccess()) { return null; @@ -846,6 +852,7 @@ public final class BluetoothAdapter { * * @hide */ + @RequiresNoPermission public PeriodicAdvertisingManager getPeriodicAdvertisingManager() { if (!getLeAccess()) { return null; @@ -866,6 +873,7 @@ public final class BluetoothAdapter { /** * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. */ + @RequiresNoPermission public BluetoothLeScanner getBluetoothLeScanner() { if (!getLeAccess()) { return null; @@ -887,6 +895,7 @@ public final class BluetoothAdapter { * @return true if the local adapter is turned on */ @RequiresLegacyBluetoothPermission + @RequiresNoPermission public boolean isEnabled() { return getState() == BluetoothAdapter.STATE_ON; } @@ -900,6 +909,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi + @RequiresNoPermission public boolean isLeEnabled() { final int state = getLeState(); if (DBG) { @@ -937,6 +947,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi + @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disableBLE() { if (!isBleScanAlwaysAvailable()) { @@ -983,6 +994,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi + @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableBLE() { if (!isBleScanAlwaysAvailable()) { @@ -1015,6 +1027,7 @@ public final class BluetoothAdapter { }; /** @hide */ + @RequiresNoPermission public void disableBluetoothGetStateCache() { mBluetoothGetStateCache.disableLocal(); } @@ -1059,6 +1072,7 @@ public final class BluetoothAdapter { * @return current state of Bluetooth adapter */ @RequiresLegacyBluetoothPermission + @RequiresNoPermission @AdapterState public int getState() { int state = getStateInternal(); @@ -1095,6 +1109,7 @@ public final class BluetoothAdapter { * @hide */ @RequiresLegacyBluetoothPermission + @RequiresNoPermission @AdapterState @UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine " + "whether you can use BLE & BT classic.") @@ -1649,6 +1664,7 @@ public final class BluetoothAdapter { /** @hide */ @UnsupportedAppUsage + @RequiresBluetoothScanPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public int getDiscoverableTimeout() { if (getState() != STATE_ON) { @@ -1669,6 +1685,7 @@ public final class BluetoothAdapter { /** @hide */ @UnsupportedAppUsage + @RequiresBluetoothScanPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void setDiscoverableTimeout(int timeout) { if (getState() != STATE_ON) { @@ -1714,6 +1731,7 @@ public final class BluetoothAdapter { * Set the context for this BluetoothAdapter (only called from BluetoothManager) * @hide */ + @RequiresNoPermission public void setContext(Context context) { mContext = context; } @@ -1872,6 +1890,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi + @RequiresBluetoothConnectPermission @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, @@ -1916,6 +1935,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi + @RequiresBluetoothConnectPermission @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, @@ -1964,6 +1984,7 @@ public final class BluetoothAdapter { * * @hide */ + @RequiresBluetoothConnectPermission @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, @@ -1996,6 +2017,7 @@ public final class BluetoothAdapter { * * @hide */ + @RequiresBluetoothConnectPermission @RequiresPermission(allOf = { android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, @@ -2021,6 +2043,7 @@ public final class BluetoothAdapter { * @return true if Multiple Advertisement feature is supported */ @RequiresLegacyBluetoothPermission + @RequiresNoPermission public boolean isMultipleAdvertisementSupported() { if (getState() != STATE_ON) { return false; @@ -2049,6 +2072,7 @@ public final class BluetoothAdapter { * @hide */ @SystemApi + @RequiresNoPermission public boolean isBleScanAlwaysAvailable() { try { return mManagerService.isBleScanAlwaysAvailable(); @@ -2082,6 +2106,7 @@ public final class BluetoothAdapter { }; /** @hide */ + @RequiresNoPermission public void disableIsOffloadedFilteringSupportedCache() { mBluetoothFilteringCache.disableLocal(); } @@ -2097,6 +2122,7 @@ public final class BluetoothAdapter { * @return true if chipset supports on-chip filtering */ @RequiresLegacyBluetoothPermission + @RequiresNoPermission public boolean isOffloadedFilteringSupported() { if (!getLeAccess()) { return false; @@ -2110,6 +2136,7 @@ public final class BluetoothAdapter { * @return true if chipset supports on-chip scan batching */ @RequiresLegacyBluetoothPermission + @RequiresNoPermission public boolean isOffloadedScanBatchingSupported() { if (!getLeAccess()) { return false; @@ -2133,6 +2160,7 @@ public final class BluetoothAdapter { * @return true if chipset supports LE 2M PHY feature */ @RequiresLegacyBluetoothPermission + @RequiresNoPermission public boolean isLe2MPhySupported() { if (!getLeAccess()) { return false; @@ -2156,6 +2184,7 @@ public final class BluetoothAdapter { * @return true if chipset supports LE Coded PHY feature */ @RequiresLegacyBluetoothPermission + @RequiresNoPermission public boolean isLeCodedPhySupported() { if (!getLeAccess()) { return false; @@ -2179,6 +2208,7 @@ public final class BluetoothAdapter { * @return true if chipset supports LE Extended Advertising feature */ @RequiresLegacyBluetoothPermission + @RequiresNoPermission public boolean isLeExtendedAdvertisingSupported() { if (!getLeAccess()) { return false; @@ -2202,6 +2232,7 @@ public final class BluetoothAdapter { * @return true if chipset supports LE Periodic Advertising feature */ @RequiresLegacyBluetoothPermission + @RequiresNoPermission public boolean isLePeriodicAdvertisingSupported() { if (!getLeAccess()) { return false; @@ -2226,6 +2257,7 @@ public final class BluetoothAdapter { * @return the maximum LE advertising data length. */ @RequiresLegacyBluetoothPermission + @RequiresNoPermission public int getLeMaximumAdvertisingDataLength() { if (!getLeAccess()) { return 0; @@ -2248,6 +2280,7 @@ public final class BluetoothAdapter { * * @return true if phone supports Hearing Aid Profile */ + @RequiresNoPermission private boolean isHearingAidProfileSupported() { try { return mManagerService.isHearingAidProfileSupported(); @@ -2286,6 +2319,7 @@ public final class BluetoothAdapter { * @return true if there are hw entries available for matching beacons * @hide */ + @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isHardwareTrackingFiltersAvailable() { if (!getLeAccess()) { @@ -2432,6 +2466,7 @@ public final class BluetoothAdapter { * BluetoothProfile}. * @hide */ + @RequiresNoPermission public @NonNull List getSupportedProfiles() { final ArrayList supportedProfiles = new ArrayList(); @@ -2479,6 +2514,7 @@ public final class BluetoothAdapter { }; /** @hide */ + @RequiresNoPermission public void disableGetAdapterConnectionStateCache() { mBluetoothGetAdapterConnectionStateCache.disableLocal(); } @@ -2503,6 +2539,7 @@ public final class BluetoothAdapter { */ @UnsupportedAppUsage @RequiresLegacyBluetoothPermission + @RequiresNoPermission public int getConnectionState() { if (getState() != STATE_ON) { return BluetoothAdapter.STATE_DISCONNECTED; @@ -2553,6 +2590,7 @@ public final class BluetoothAdapter { }; /** @hide */ + @RequiresNoPermission public void disableGetProfileConnectionStateCache() { mGetProfileConnectionStateCache.disableLocal(); } @@ -2753,6 +2791,7 @@ public final class BluetoothAdapter { return createNewRfcommSocketAndRecord(name, uuid, false, true); } + @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt) throws IOException { @@ -2779,6 +2818,7 @@ public final class BluetoothAdapter { * permissions. * @hide */ + @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { BluetoothServerSocket socket = @@ -2811,6 +2851,7 @@ public final class BluetoothAdapter { * permissions. * @hide */ + @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin) throws IOException { @@ -2844,6 +2885,7 @@ public final class BluetoothAdapter { * permissions. * @hide */ + @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { return listenUsingL2capOn(port, false, false); @@ -2861,6 +2903,7 @@ public final class BluetoothAdapter { * permissions. * @hide */ + @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException { Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port); @@ -2916,6 +2959,10 @@ public final class BluetoothAdapter { * BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#GATT_SERVER}. * @return true on success, false on error */ + @SuppressLint({ + "AndroidFrameworkRequiresPermission", + "AndroidFrameworkBluetoothPermission" + }) public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile) { if (context == null || listener == null) { @@ -2985,7 +3032,10 @@ public final class BluetoothAdapter { * @param profile * @param proxy Profile proxy object */ - @SuppressLint("AndroidFrameworkRequiresPermission") + @SuppressLint({ + "AndroidFrameworkRequiresPermission", + "AndroidFrameworkBluetoothPermission" + }) public void closeProfileProxy(int profile, BluetoothProfile proxy) { if (proxy == null) { return; @@ -3058,6 +3108,7 @@ public final class BluetoothAdapter { } } + @SuppressLint("AndroidFrameworkBluetoothPermission") private final IBluetoothManagerCallback mManagerCallback = new IBluetoothManagerCallback.Stub() { @SuppressLint("AndroidFrameworkRequiresPermission") @@ -3380,7 +3431,6 @@ public final class BluetoothAdapter { /** * @hide */ - @SuppressLint("AndroidFrameworkRequiresPermission") public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub { private BluetoothStateChangeCallback mCallback; @@ -3631,6 +3681,7 @@ public final class BluetoothAdapter { return false; } + @SuppressLint("AndroidFrameworkBluetoothPermission") ScanCallback scanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { @@ -3961,6 +4012,7 @@ public final class BluetoothAdapter { @Nullable byte[] value); } + @SuppressLint("AndroidFrameworkBluetoothPermission") private final IBluetoothConnectionCallback mConnectionCallback = new IBluetoothConnectionCallback.Stub() { @Override -- cgit v1.2.3 From f0a1cae1d658c6915f9d663f1eca70f02c8c3581 Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Tue, 20 Apr 2021 09:56:45 +0100 Subject: Pass AttributionSource to AdapterService methods. This adds attribution source to AdapterService bluetooth method calls. This is now required to allow the app ops for the new bluetooth permissions (BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE, and BLUETOOTH_SCAN) to be noted. Bug: 183626112 Test: atest AdapterServiceTest Test: atest CtsPermissionTestCases:android.permission.cts.NearbyDevicesPermissionTest Change-Id: I8d1fe41ca9945a3baab584f248a17b3a1eb255f7 --- .../java/android/bluetooth/BluetoothAdapter.java | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 052a7733c2..bf492efba6 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -31,12 +31,12 @@ import android.app.ActivityThread; import android.app.PropertyInvalidatedCache; import android.bluetooth.BluetoothDevice.Transport; import android.bluetooth.BluetoothProfile.ConnectionPolicy; -import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission; import android.bluetooth.annotations.RequiresBluetoothConnectPermission; import android.bluetooth.annotations.RequiresBluetoothLocationPermission; -import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.bluetooth.annotations.RequiresBluetoothScanPermission; +import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; +import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.PeriodicAdvertisingManager; @@ -797,7 +797,7 @@ public final class BluetoothAdapter { */ @RequiresNoPermission public BluetoothDevice getRemoteDevice(String address) { - return new BluetoothDevice(address); + return new BluetoothDevice(address, getAttributionSource()); } /** @@ -818,7 +818,7 @@ public final class BluetoothAdapter { } return new BluetoothDevice( String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1], - address[2], address[3], address[4], address[5])); + address[2], address[3], address[4], address[5]), getAttributionSource()); } /** @@ -1320,7 +1320,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getUuids(); + return mService.getUuids(getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1354,7 +1354,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.setName(name); + return mService.setName(name, getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1382,7 +1382,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getBluetoothClass(); + return mService.getBluetoothClass(getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1438,7 +1438,7 @@ public final class BluetoothAdapter { if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getIoCapability(); + if (mService != null) return mService.getIoCapability(getAttributionSource()); } catch (RemoteException e) { Log.e(TAG, e.getMessage(), e); } finally { @@ -1491,7 +1491,7 @@ public final class BluetoothAdapter { if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getLeIoCapability(); + if (mService != null) return mService.getLeIoCapability(getAttributionSource()); } catch (RemoteException e) { Log.e(TAG, e.getMessage(), e); } finally { @@ -1553,7 +1553,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getScanMode(); + return mService.getScanMode(getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1602,7 +1602,7 @@ public final class BluetoothAdapter { mServiceLock.readLock().lock(); if (mService != null) { int durationSeconds = Math.toIntExact(durationMillis / 1000); - return mService.setScanMode(mode, durationSeconds); + return mService.setScanMode(mode, durationSeconds, getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1652,7 +1652,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.setScanMode(mode, getDiscoverableTimeout()); + return mService.setScanMode(mode, getDiscoverableTimeout(), getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1673,7 +1673,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getDiscoverableTimeout(); + return mService.getDiscoverableTimeout(getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1694,7 +1694,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - mService.setDiscoverableTimeout(timeout); + mService.setDiscoverableTimeout(timeout, getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1745,7 +1745,7 @@ public final class BluetoothAdapter { return ActivityThread.currentOpPackageName(); } - private AttributionSource getAttributionSource() { + AttributionSource getAttributionSource() { if (mContext != null) { return mContext.getAttributionSource(); } @@ -1828,7 +1828,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.cancelDiscovery(); + return mService.cancelDiscovery(getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1866,7 +1866,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.isDiscovering(); + return mService.isDiscovering(getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2303,7 +2303,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getMaxConnectedAudioDevices(); + return mService.getMaxConnectedAudioDevices(getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "failed to get getMaxConnectedAudioDevices, error: ", e); @@ -2415,7 +2415,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getMostRecentlyConnectedDevices(); + return mService.getMostRecentlyConnectedDevices(getAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2445,7 +2445,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return toDeviceSet(mService.getBondedDevices()); + return toDeviceSet(mService.getBondedDevices(getAttributionSource())); } return toDeviceSet(new BluetoothDevice[0]); } catch (RemoteException e) { -- cgit v1.2.3 From d7c55664839ca7e6237cd0ef0f36eb51a4ee7ae6 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 20 Apr 2021 12:30:37 -0600 Subject: Annotations for Bluetooth broadcast intents. Recent work has been using Error Prone rules and annotations to reflect the current state of permission enforcement across the Bluetooth stack, and we're now in a position were we can add new permission enforcement that had been missing. We've currently standardized on saying that APIs that return device or Bluetooth state information (without sharing details about any particular remote Bluetooth device) do not need to be permission protected. Bug: 183626724 Test: ./build/soong/soong_ui.bash --make-mode Bluetooth RUN_ERROR_PRONE=true Change-Id: I53ac7a4fe1dea57316048c3cac4fa237b6ba3d38 --- framework/java/android/bluetooth/BluetoothAdapter.java | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 052a7733c2..0442514d9c 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -604,6 +604,7 @@ public final class BluetoothAdapter { * * @hide */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @SystemApi public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; @@ -618,6 +619,9 @@ public final class BluetoothAdapter { * * @hide */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED = "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED"; @@ -642,6 +646,9 @@ public final class BluetoothAdapter { * * @hide */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BLE_ACL_CONNECTED = "android.bluetooth.adapter.action.BLE_ACL_CONNECTED"; @@ -656,6 +663,9 @@ public final class BluetoothAdapter { * * @hide */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BLE_ACL_DISCONNECTED = "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED"; -- cgit v1.2.3 From 4e4c9c4796c2c16d32e87417e084a1f724e9f258 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 22 Apr 2021 12:21:46 -0600 Subject: Refinement of AttributionSource handling. Previous CLs had started passing AttributionSource values across Binder calls inside BluetoothDevice instances, but this can cause confuse the permission check logic in the future; we should instead always aim to use the AttributionSource closest to the app making the call, instead of parceling it. This change also improves logging to highlight when we're quietly treating a permission as denied, and when a UID is mismatched. Bug: 186106084 Test: atest BluetoothInstrumentationTests Change-Id: I5d3fdb3c573cb9e77474952d8680caa4c4c464eb --- .../java/android/bluetooth/BluetoothAdapter.java | 104 ++++++++++----------- 1 file changed, 49 insertions(+), 55 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 5704c6513e..2426ead810 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -53,7 +53,6 @@ import android.os.Binder; import android.os.Build; import android.os.IBinder; import android.os.ParcelUuid; -import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -75,6 +74,7 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.Executor; @@ -713,7 +713,6 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; @UnsupportedAppUsage private IBluetooth mService; - private Context mContext; private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); private final Object mLock = new Object(); @@ -723,6 +722,8 @@ public final class BluetoothAdapter { private final Map mBluetoothConnectionCallbackExecutorMap = new HashMap<>(); + private AttributionSource mAttributionSource; + /** * Bluetooth metadata listener. Overrides the default BluetoothMetadataListener * implementation. @@ -762,17 +763,22 @@ public final class BluetoothAdapter { @RequiresNoPermission public static synchronized BluetoothAdapter getDefaultAdapter() { if (sAdapter == null) { - IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE); - if (b != null) { - IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b); - sAdapter = new BluetoothAdapter(managerService); - } else { - Log.e(TAG, "Bluetooth binder is null"); - } + sAdapter = createAdapter(); } return sAdapter; } + /** {@hide} */ + public static BluetoothAdapter createAdapter() { + IBinder binder = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE); + if (binder != null) { + return new BluetoothAdapter(IBluetoothManager.Stub.asInterface(binder)); + } else { + Log.e(TAG, "Bluetooth binder is null"); + return null; + } + } + /** * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. */ @@ -793,6 +799,15 @@ public final class BluetoothAdapter { mToken = new Binder(); } + void setAttributionSource(AttributionSource attributionSource) { + mAttributionSource = attributionSource; + } + + private AttributionSource resolveAttributionSource() { + return (mAttributionSource != null) ? mAttributionSource + : ActivityThread.currentAttributionSource(); + } + /** * Get a {@link BluetoothDevice} object for the given Bluetooth hardware * address. @@ -807,7 +822,9 @@ public final class BluetoothAdapter { */ @RequiresNoPermission public BluetoothDevice getRemoteDevice(String address) { - return new BluetoothDevice(address, getAttributionSource()); + final BluetoothDevice res = new BluetoothDevice(address); + res.setAttributionSource(mAttributionSource); + return res; } /** @@ -826,9 +843,11 @@ public final class BluetoothAdapter { if (address == null || address.length != 6) { throw new IllegalArgumentException("Bluetooth address must have 6 bytes"); } - return new BluetoothDevice( + final BluetoothDevice res = new BluetoothDevice( String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1], - address[2], address[3], address[4], address[5]), getAttributionSource()); + address[2], address[3], address[4], address[5])); + res.setAttributionSource(mAttributionSource); + return res; } /** @@ -891,7 +910,7 @@ public final class BluetoothAdapter { synchronized (mLock) { if (sBluetoothLeScanner == null) { sBluetoothLeScanner = - new BluetoothLeScanner(mManagerService, getAttributionSource()); + new BluetoothLeScanner(mManagerService, resolveAttributionSource()); } } return sBluetoothLeScanner; @@ -1330,7 +1349,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getUuids(getAttributionSource()); + return mService.getUuids(resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1364,7 +1383,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.setName(name, getAttributionSource()); + return mService.setName(name, resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1392,7 +1411,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getBluetoothClass(getAttributionSource()); + return mService.getBluetoothClass(resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1448,7 +1467,7 @@ public final class BluetoothAdapter { if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getIoCapability(getAttributionSource()); + if (mService != null) return mService.getIoCapability(resolveAttributionSource()); } catch (RemoteException e) { Log.e(TAG, e.getMessage(), e); } finally { @@ -1501,7 +1520,7 @@ public final class BluetoothAdapter { if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getLeIoCapability(getAttributionSource()); + if (mService != null) return mService.getLeIoCapability(resolveAttributionSource()); } catch (RemoteException e) { Log.e(TAG, e.getMessage(), e); } finally { @@ -1563,7 +1582,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getScanMode(getAttributionSource()); + return mService.getScanMode(resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1612,7 +1631,7 @@ public final class BluetoothAdapter { mServiceLock.readLock().lock(); if (mService != null) { int durationSeconds = Math.toIntExact(durationMillis / 1000); - return mService.setScanMode(mode, durationSeconds, getAttributionSource()); + return mService.setScanMode(mode, durationSeconds, resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1662,7 +1681,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.setScanMode(mode, getDiscoverableTimeout(), getAttributionSource()); + return mService.setScanMode(mode, getDiscoverableTimeout(), resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1683,7 +1702,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getDiscoverableTimeout(getAttributionSource()); + return mService.getDiscoverableTimeout(resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1704,7 +1723,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - mService.setDiscoverableTimeout(timeout, getAttributionSource()); + mService.setDiscoverableTimeout(timeout, resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1737,31 +1756,6 @@ public final class BluetoothAdapter { return -1; } - /** - * Set the context for this BluetoothAdapter (only called from BluetoothManager) - * @hide - */ - @RequiresNoPermission - public void setContext(Context context) { - mContext = context; - } - - String getOpPackageName() { - // Workaround for legacy API for getting a BluetoothAdapter not - // passing a context - if (mContext != null) { - return mContext.getOpPackageName(); - } - return ActivityThread.currentOpPackageName(); - } - - AttributionSource getAttributionSource() { - if (mContext != null) { - return mContext.getAttributionSource(); - } - return new AttributionSource(Process.myUid(), ActivityThread.currentOpPackageName(), null); - } - /** * Start the remote device discovery process. *

The discovery process usually involves an inquiry scan of about 12 @@ -1802,7 +1796,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.startDiscovery(getAttributionSource()); + return mService.startDiscovery(resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1838,7 +1832,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.cancelDiscovery(getAttributionSource()); + return mService.cancelDiscovery(resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1876,7 +1870,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.isDiscovering(getAttributionSource()); + return mService.isDiscovering(resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2313,7 +2307,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getMaxConnectedAudioDevices(getAttributionSource()); + return mService.getMaxConnectedAudioDevices(resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "failed to get getMaxConnectedAudioDevices, error: ", e); @@ -2425,7 +2419,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getMostRecentlyConnectedDevices(getAttributionSource()); + return mService.getMostRecentlyConnectedDevices(resolveAttributionSource()); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2455,7 +2449,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return toDeviceSet(mService.getBondedDevices(getAttributionSource())); + return toDeviceSet(mService.getBondedDevices(resolveAttributionSource())); } return toDeviceSet(new BluetoothDevice[0]); } catch (RemoteException e) { @@ -3270,7 +3264,7 @@ public final class BluetoothAdapter { /** * Provides callback methods for receiving {@link OobData} from the host stack, as well as an - * error interface in order to allow the caller to determine next steps based on the {@link + * error interface in order to allow the caller to determine next steps based on the {@code * ErrorCode}. * * @hide -- cgit v1.2.3 From 4dabcb764f1948823dcd74eefb3440afcab07db2 Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Thu, 22 Apr 2021 19:05:17 +0100 Subject: Pass attribution source to BT APIs. This adds attribution source to BT method calls. This is now required to allow the app ops for the new BT permissions (BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE, and BLUETOOTH_SCAN) to be noted. Bug: 183626112 Test: atest BluetoothInstrumentationTests Change-Id: I81598553b762e491d6364064a2e1ef41dec89bf9 --- .../java/android/bluetooth/BluetoothAdapter.java | 100 ++++++++++----------- 1 file changed, 49 insertions(+), 51 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 2426ead810..4ef37379a5 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -706,11 +706,13 @@ public final class BluetoothAdapter { */ private static BluetoothAdapter sAdapter; - private static BluetoothLeScanner sBluetoothLeScanner; - private static BluetoothLeAdvertiser sBluetoothLeAdvertiser; - private static PeriodicAdvertisingManager sPeriodicAdvertisingManager; + private BluetoothLeScanner mBluetoothLeScanner; + private BluetoothLeAdvertiser mBluetoothLeAdvertiser; + private PeriodicAdvertisingManager mPeriodicAdvertisingManager; private final IBluetoothManager mManagerService; + private final AttributionSource mAttributionSource; + @UnsupportedAppUsage private IBluetooth mService; private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); @@ -722,8 +724,6 @@ public final class BluetoothAdapter { private final Map mBluetoothConnectionCallbackExecutorMap = new HashMap<>(); - private AttributionSource mAttributionSource; - /** * Bluetooth metadata listener. Overrides the default BluetoothMetadataListener * implementation. @@ -763,16 +763,17 @@ public final class BluetoothAdapter { @RequiresNoPermission public static synchronized BluetoothAdapter getDefaultAdapter() { if (sAdapter == null) { - sAdapter = createAdapter(); + sAdapter = createAdapter(ActivityThread.currentAttributionSource()); } return sAdapter; } /** {@hide} */ - public static BluetoothAdapter createAdapter() { + public static BluetoothAdapter createAdapter(AttributionSource attributionSource) { IBinder binder = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE); if (binder != null) { - return new BluetoothAdapter(IBluetoothManager.Stub.asInterface(binder)); + return new BluetoothAdapter(IBluetoothManager.Stub.asInterface(binder), + attributionSource); } else { Log.e(TAG, "Bluetooth binder is null"); return null; @@ -782,7 +783,7 @@ public final class BluetoothAdapter { /** * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. */ - BluetoothAdapter(IBluetoothManager managerService) { + BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) { if (managerService == null) { throw new IllegalArgumentException("bluetooth manager service is null"); } @@ -794,20 +795,12 @@ public final class BluetoothAdapter { } finally { mServiceLock.writeLock().unlock(); } - mManagerService = managerService; + mManagerService = Objects.requireNonNull(managerService); + mAttributionSource = Objects.requireNonNull(attributionSource); mLeScanClients = new HashMap(); mToken = new Binder(); } - void setAttributionSource(AttributionSource attributionSource) { - mAttributionSource = attributionSource; - } - - private AttributionSource resolveAttributionSource() { - return (mAttributionSource != null) ? mAttributionSource - : ActivityThread.currentAttributionSource(); - } - /** * Get a {@link BluetoothDevice} object for the given Bluetooth hardware * address. @@ -864,11 +857,11 @@ public final class BluetoothAdapter { return null; } synchronized (mLock) { - if (sBluetoothLeAdvertiser == null) { - sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); + if (mBluetoothLeAdvertiser == null) { + mBluetoothLeAdvertiser = new BluetoothLeAdvertiser(this); } + return mBluetoothLeAdvertiser; } - return sBluetoothLeAdvertiser; } /** @@ -892,11 +885,11 @@ public final class BluetoothAdapter { } synchronized (mLock) { - if (sPeriodicAdvertisingManager == null) { - sPeriodicAdvertisingManager = new PeriodicAdvertisingManager(mManagerService); + if (mPeriodicAdvertisingManager == null) { + mPeriodicAdvertisingManager = new PeriodicAdvertisingManager(this); } + return mPeriodicAdvertisingManager; } - return sPeriodicAdvertisingManager; } /** @@ -908,12 +901,11 @@ public final class BluetoothAdapter { return null; } synchronized (mLock) { - if (sBluetoothLeScanner == null) { - sBluetoothLeScanner = - new BluetoothLeScanner(mManagerService, resolveAttributionSource()); + if (mBluetoothLeScanner == null) { + mBluetoothLeScanner = new BluetoothLeScanner(this); } + return mBluetoothLeScanner; } - return sBluetoothLeScanner; } /** @@ -1349,7 +1341,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getUuids(resolveAttributionSource()); + return mService.getUuids(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1383,7 +1375,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.setName(name, resolveAttributionSource()); + return mService.setName(name, mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1411,7 +1403,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getBluetoothClass(resolveAttributionSource()); + return mService.getBluetoothClass(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1467,7 +1459,7 @@ public final class BluetoothAdapter { if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getIoCapability(resolveAttributionSource()); + if (mService != null) return mService.getIoCapability(mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.getMessage(), e); } finally { @@ -1520,7 +1512,7 @@ public final class BluetoothAdapter { if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; try { mServiceLock.readLock().lock(); - if (mService != null) return mService.getLeIoCapability(resolveAttributionSource()); + if (mService != null) return mService.getLeIoCapability(mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.getMessage(), e); } finally { @@ -1582,7 +1574,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getScanMode(resolveAttributionSource()); + return mService.getScanMode(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1631,7 +1623,7 @@ public final class BluetoothAdapter { mServiceLock.readLock().lock(); if (mService != null) { int durationSeconds = Math.toIntExact(durationMillis / 1000); - return mService.setScanMode(mode, durationSeconds, resolveAttributionSource()); + return mService.setScanMode(mode, durationSeconds, mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1681,7 +1673,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.setScanMode(mode, getDiscoverableTimeout(), resolveAttributionSource()); + return mService.setScanMode(mode, getDiscoverableTimeout(), mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1702,7 +1694,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getDiscoverableTimeout(resolveAttributionSource()); + return mService.getDiscoverableTimeout(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1723,7 +1715,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - mService.setDiscoverableTimeout(timeout, resolveAttributionSource()); + mService.setDiscoverableTimeout(timeout, mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1796,7 +1788,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.startDiscovery(resolveAttributionSource()); + return mService.startDiscovery(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1832,7 +1824,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.cancelDiscovery(resolveAttributionSource()); + return mService.cancelDiscovery(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1870,7 +1862,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.isDiscovering(resolveAttributionSource()); + return mService.isDiscovering(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2307,7 +2299,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getMaxConnectedAudioDevices(resolveAttributionSource()); + return mService.getMaxConnectedAudioDevices(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "failed to get getMaxConnectedAudioDevices, error: ", e); @@ -2335,7 +2327,7 @@ public final class BluetoothAdapter { // BLE is not supported return false; } - return (iGatt.numHwTrackFiltersAvailable() != 0); + return (iGatt.numHwTrackFiltersAvailable(mAttributionSource) != 0); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -2419,7 +2411,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getMostRecentlyConnectedDevices(resolveAttributionSource()); + return mService.getMostRecentlyConnectedDevices(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2449,7 +2441,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return toDeviceSet(mService.getBondedDevices(resolveAttributionSource())); + return toDeviceSet(mService.getBondedDevices(mAttributionSource)); } return toDeviceSet(new BluetoothDevice[0]); } catch (RemoteException e) { @@ -3171,11 +3163,11 @@ public final class BluetoothAdapter { if (mLeScanClients != null) { mLeScanClients.clear(); } - if (sBluetoothLeAdvertiser != null) { - sBluetoothLeAdvertiser.cleanup(); + if (mBluetoothLeAdvertiser != null) { + mBluetoothLeAdvertiser.cleanup(); } - if (sBluetoothLeScanner != null) { - sBluetoothLeScanner.cleanup(); + if (mBluetoothLeScanner != null) { + mBluetoothLeScanner.cleanup(); } } finally { mServiceLock.writeLock().unlock(); @@ -3514,11 +3506,17 @@ public final class BluetoothAdapter { && (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11; } + /** {@hide} */ @UnsupportedAppUsage - /*package*/ IBluetoothManager getBluetoothManager() { + public IBluetoothManager getBluetoothManager() { return mManagerService; } + /** {@hide} */ + public AttributionSource getAttributionSource() { + return mAttributionSource; + } + private final ArrayList mProxyServiceStateCallbacks = new ArrayList(); -- cgit v1.2.3 From f9e176c3dcafb82f251a123751578539e3484deb Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 22 Apr 2021 16:01:29 -0600 Subject: More AttributionSource plumbing. To prepare for future work which will plumb AttributionSource values through all remaining AIDLs, we need profiles to interact directly with the specific BluetoothAdapter they were created from. This is how we'll ensure that the relevant AttributionSource can be chained down from the original Context they're obtained from. This change also marks getDefaultAdapter() as deprecated to clearly communicate that BluetoothManager.getAdapter() is the best-practice path to obtaining a correctly scoped BluetoothAdapter instance. Bug: 183626112 Test: atest BluetoothInstrumentationTests Change-Id: I1e15170d7679019bbb6e396279d6e633e3dad4d6 --- .../java/android/bluetooth/BluetoothAdapter.java | 46 ++++++++++++---------- 1 file changed, 26 insertions(+), 20 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 4ef37379a5..18e6356d82 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -752,18 +752,23 @@ public final class BluetoothAdapter { /** * Get a handle to the default local Bluetooth adapter. - *

Currently Android only supports one Bluetooth adapter, but the API - * could be extended to support more. This will always return the default - * adapter. + *

+ * Currently Android only supports one Bluetooth adapter, but the API could + * be extended to support more. This will always return the default adapter. *

* - * @return the default local adapter, or null if Bluetooth is not supported on this hardware - * platform + * @return the default local adapter, or null if Bluetooth is not supported + * on this hardware platform + * @deprecated this method will continue to work, but developers are + * strongly encouraged to migrate to using + * {@link BluetoothManager#getAdapter()}, since that approach + * enables support for {@link Context#createAttributionContext}. */ + @Deprecated @RequiresNoPermission public static synchronized BluetoothAdapter getDefaultAdapter() { if (sAdapter == null) { - sAdapter = createAdapter(ActivityThread.currentAttributionSource()); + sAdapter = createAdapter(BluetoothManager.resolveAttributionSource(null)); } return sAdapter; } @@ -2966,50 +2971,51 @@ public final class BluetoothAdapter { } if (profile == BluetoothProfile.HEADSET) { - BluetoothHeadset headset = new BluetoothHeadset(context, listener); + BluetoothHeadset headset = new BluetoothHeadset(context, listener, this); return true; } else if (profile == BluetoothProfile.A2DP) { - BluetoothA2dp a2dp = new BluetoothA2dp(context, listener); + BluetoothA2dp a2dp = new BluetoothA2dp(context, listener, this); return true; } else if (profile == BluetoothProfile.A2DP_SINK) { - BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener); + BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener, this); return true; } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) { - BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener); + BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener, this); return true; } else if (profile == BluetoothProfile.HID_HOST) { - BluetoothHidHost iDev = new BluetoothHidHost(context, listener); + BluetoothHidHost iDev = new BluetoothHidHost(context, listener, this); return true; } else if (profile == BluetoothProfile.PAN) { - BluetoothPan pan = new BluetoothPan(context, listener); + BluetoothPan pan = new BluetoothPan(context, listener, this); return true; } else if (profile == BluetoothProfile.PBAP) { - BluetoothPbap pbap = new BluetoothPbap(context, listener); + BluetoothPbap pbap = new BluetoothPbap(context, listener, this); return true; } else if (profile == BluetoothProfile.HEALTH) { Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated"); return false; } else if (profile == BluetoothProfile.MAP) { - BluetoothMap map = new BluetoothMap(context, listener); + BluetoothMap map = new BluetoothMap(context, listener, this); return true; } else if (profile == BluetoothProfile.HEADSET_CLIENT) { - BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener); + BluetoothHeadsetClient headsetClient = + new BluetoothHeadsetClient(context, listener, this); return true; } else if (profile == BluetoothProfile.SAP) { - BluetoothSap sap = new BluetoothSap(context, listener); + BluetoothSap sap = new BluetoothSap(context, listener, this); return true; } else if (profile == BluetoothProfile.PBAP_CLIENT) { - BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener); + BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener, this); return true; } else if (profile == BluetoothProfile.MAP_CLIENT) { - BluetoothMapClient mapClient = new BluetoothMapClient(context, listener); + BluetoothMapClient mapClient = new BluetoothMapClient(context, listener, this); return true; } else if (profile == BluetoothProfile.HID_DEVICE) { - BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener); + BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener, this); return true; } else if (profile == BluetoothProfile.HEARING_AID) { if (isHearingAidProfileSupported()) { - BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener); + BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener, this); return true; } return false; -- cgit v1.2.3 From 43ee69eed974cd7ebc4784416a6e1e251464cc36 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 23 Apr 2021 14:13:57 -0600 Subject: Long-tail of AttributionSource plumbing. Wires up AttributionSource across the remaining long-tail of Bluetooth AIDL interfaces, ensuring that developers can accurately make calls chained back to a specific Context. Moves "for data delivery" permission checks to happen in a single location on each interface to ensure they're performed consistently with the new AttributionSource arguments. Note that "for data delivery" isn't the best name; it's designed to represent that the requested action was performed and should result in the relevant appop being noted for the caller. This change has the positive side effect of ensuring that all interfaces are consistently enforcing the BLUETOOTH_CONNECT permission, even in the case where BLUETOOTH_PRIVILEGED is also required; this is what ensures that revoking the "Nearby devices" permission takes effect for all callers. Additionally, standardizing on enforcing permissions closer to the AIDL entry point reduces the need for @RequiresPermission annotations to be carried around inside the Bluetooth stack. Bug: 183626112 Test: atest BluetoothInstrumentationTests Change-Id: I8023dda654e325b8bfa2f0cdb994ad63a2b429d4 --- .../java/android/bluetooth/BluetoothAdapter.java | 29 +++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 18e6356d82..8afc557ef8 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -981,7 +981,7 @@ public final class BluetoothAdapter { } String packageName = ActivityThread.currentPackageName(); try { - return mManagerService.disableBle(packageName, mToken); + return mManagerService.disableBle(mAttributionSource, mToken); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1028,7 +1028,7 @@ public final class BluetoothAdapter { } String packageName = ActivityThread.currentPackageName(); try { - return mManagerService.enableBle(packageName, mToken); + return mManagerService.enableBle(mAttributionSource, mToken); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1193,7 +1193,7 @@ public final class BluetoothAdapter { return true; } try { - return mManagerService.enable(ActivityThread.currentPackageName()); + return mManagerService.enable(mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1226,7 +1226,7 @@ public final class BluetoothAdapter { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disable() { try { - return mManagerService.disable(ActivityThread.currentPackageName(), true); + return mManagerService.disable(mAttributionSource, true); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1246,7 +1246,7 @@ public final class BluetoothAdapter { public boolean disable(boolean persist) { try { - return mManagerService.disable(ActivityThread.currentPackageName(), persist); + return mManagerService.disable(mAttributionSource, persist); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1267,7 +1267,7 @@ public final class BluetoothAdapter { }) public String getAddress() { try { - return mManagerService.getAddress(); + return mManagerService.getAddress(mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1285,7 +1285,7 @@ public final class BluetoothAdapter { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getName() { try { - return mManagerService.getName(); + return mManagerService.getName(mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1297,7 +1297,7 @@ public final class BluetoothAdapter { @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public int getNameLengthForAdvertise() { try { - return mService.getNameLengthForAdvertise(); + return mService.getNameLengthForAdvertise(mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1316,7 +1316,8 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null && mService.factoryReset() - && mManagerService != null && mManagerService.onFactoryReset()) { + && mManagerService != null + && mManagerService.onFactoryReset(mAttributionSource)) { return true; } Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later"); @@ -1910,7 +1911,7 @@ public final class BluetoothAdapter { mServiceLock.readLock().lock(); if (mService != null) { if (DBG) Log.d(TAG, "removeActiveDevice, profiles: " + profiles); - return mService.removeActiveDevice(profiles); + return mService.removeActiveDevice(profiles, mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1962,7 +1963,7 @@ public final class BluetoothAdapter { if (DBG) { Log.d(TAG, "setActiveDevice, device: " + device + ", profiles: " + profiles); } - return mService.setActiveDevice(device, profiles); + return mService.setActiveDevice(device, profiles, mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1995,7 +1996,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.connectAllEnabledProfiles(device); + return mService.connectAllEnabledProfiles(device, mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2027,7 +2028,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.disconnectAllEnabledProfiles(device); + return mService.disconnectAllEnabledProfiles(device, mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -3219,7 +3220,7 @@ public final class BluetoothAdapter { return true; } try { - return mManagerService.enableNoAutoConnect(ActivityThread.currentPackageName()); + return mManagerService.enableNoAutoConnect(mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } -- cgit v1.2.3 From 08fa792031a529c1558250845e3d811ebcc0f6d0 Mon Sep 17 00:00:00 2001 From: Martin Brabham Date: Mon, 26 Apr 2021 15:23:45 -0700 Subject: Convert onOobData parameter for OobData from @Nullable to @NonNull Bug: 185603183 Test: Compiles, test app works Tag: #feature Change-Id: I52636769f50f50b5ad2d135f54472bdeb1c25ee5 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3802289dd6..63221c5d89 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3063,7 +3063,7 @@ public final class BluetoothAdapter { * @param transport - whether the {@link OobData} is generated for LE or Classic. * @param oobData - data generated in the host stack(LE) or controller (Classic) */ - void onOobData(@Transport int transport, @Nullable OobData oobData); + void onOobData(@Transport int transport, @NonNull OobData oobData); /** * Provides feedback when things don't go as expected. @@ -3104,7 +3104,7 @@ public final class BluetoothAdapter { * * @hide */ - public void onOobData(@Transport int transport, OobData oobData) { + public void onOobData(@Transport int transport, @NonNull OobData oobData) { mExecutor.execute(new Runnable() { public void run() { mCallback.onOobData(transport, oobData); -- cgit v1.2.3 From a2d365484c43a19ab6f67152651d61f3b0667b47 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 29 Apr 2021 07:12:20 -0600 Subject: Ensure privileged APIs require runtime permission. When users revoke a runtime permission, they expect all interactions to be blocked, including those protected by the BLUETOOTH_PRIVILEGED permission. This change finishes applying that policy to any remaining Bluetooth APIs which didn't already implement it. To keep the implementation straightforward, this change does "data delivery" checks when registering for callbacks; the ideal behavior would be to wait until data is actually delivered through the callbacks, but RemoteCallbackList doesn't have support for AttributionSource yet. Bug: 186405452 Test: atest BluetoothInstrumentationTests Change-Id: Idd7be143eb8baff020a0718065293baae708041b --- .../java/android/bluetooth/BluetoothAdapter.java | 104 ++++++++++++++++----- 1 file changed, 79 insertions(+), 25 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8afc557ef8..67179c7d3e 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1311,11 +1311,15 @@ public final class BluetoothAdapter { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean factoryReset() { try { mServiceLock.readLock().lock(); - if (mService != null && mService.factoryReset() + if (mService != null && mService.factoryReset(mAttributionSource) && mManagerService != null && mManagerService.onFactoryReset(mAttributionSource)) { return true; @@ -1430,7 +1434,11 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setBluetoothClass(BluetoothClass bluetoothClass) { if (getState() != STATE_ON) { return false; @@ -1438,7 +1446,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.setBluetoothClass(bluetoothClass); + return mService.setBluetoothClass(bluetoothClass, mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -1487,12 +1495,16 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setIoCapability(@IoCapability int capability) { if (getState() != STATE_ON) return false; try { mServiceLock.readLock().lock(); - if (mService != null) return mService.setIoCapability(capability); + if (mService != null) return mService.setIoCapability(capability, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.getMessage(), e); } finally { @@ -1540,12 +1552,16 @@ public final class BluetoothAdapter { * * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setLeIoCapability(@IoCapability int capability) { if (getState() != STATE_ON) return false; try { mServiceLock.readLock().lock(); - if (mService != null) return mService.setLeIoCapability(capability); + if (mService != null) return mService.setLeIoCapability(capability, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, e.getMessage(), e); } finally { @@ -1739,12 +1755,16 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public long getDiscoveryEndMillis() { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getDiscoveryEndMillis(); + return mService.getDiscoveryEndMillis(mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2353,7 +2373,11 @@ public final class BluetoothAdapter { * instead. */ @Deprecated - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { SynchronousResultReceiver receiver = new SynchronousResultReceiver(); requestControllerActivityEnergyInfo(receiver); @@ -2379,12 +2403,16 @@ public final class BluetoothAdapter { * @param result The callback to which to send the activity info. * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public void requestControllerActivityEnergyInfo(ResultReceiver result) { try { mServiceLock.readLock().lock(); if (mService != null) { - mService.requestActivityInfo(result); + mService.requestActivityInfo(result, mAttributionSource); result = null; } } catch (RemoteException e) { @@ -3141,7 +3169,7 @@ public final class BluetoothAdapter { sMetadataListeners.forEach((device, pair) -> { try { mService.registerMetadataListener(sBluetoothMetadataListener, - device); + device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Failed to register metadata listener", e); } @@ -3150,7 +3178,8 @@ public final class BluetoothAdapter { synchronized (mBluetoothConnectionCallbackExecutorMap) { if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) { try { - mService.registerBluetoothConnectionCallback(mConnectionCallback); + mService.registerBluetoothConnectionCallback(mConnectionCallback, + mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "onBluetoothServiceUp: Failed to register bluetooth" + "connection callback", e); @@ -3364,7 +3393,11 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public void generateLocalOobData(@Transport int transport, @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback) { if (transport != BluetoothDevice.TRANSPORT_BREDR && transport @@ -3378,7 +3411,7 @@ public final class BluetoothAdapter { } else { try { mService.generateLocalOobData(transport, new WrappedOobDataCallback(callback, - executor)); + executor), mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -3515,11 +3548,13 @@ public final class BluetoothAdapter { /** {@hide} */ @UnsupportedAppUsage + @RequiresNoPermission public IBluetoothManager getBluetoothManager() { return mManagerService; } /** {@hide} */ + @RequiresNoPermission public AttributionSource getAttributionSource() { return mAttributionSource; } @@ -3892,7 +3927,11 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device, @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) { if (DBG) Log.d(TAG, "addOnMetadataChangedListener()"); @@ -3932,7 +3971,8 @@ public final class BluetoothAdapter { boolean ret = false; try { - ret = service.registerMetadataListener(sBluetoothMetadataListener, device); + ret = service.registerMetadataListener(sBluetoothMetadataListener, device, + mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "registerMetadataListener fail", e); } finally { @@ -3965,7 +4005,11 @@ public final class BluetoothAdapter { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device, @NonNull OnMetadataChangedListener listener) { if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()"); @@ -3993,7 +4037,7 @@ public final class BluetoothAdapter { return true; } try { - return service.unregisterMetadataListener(device); + return service.unregisterMetadataListener(device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "unregisterMetadataListener fail", e); return false; @@ -4055,7 +4099,11 @@ public final class BluetoothAdapter { * @throws IllegalArgumentException if the callback is already registered * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean registerBluetoothConnectionCallback(@NonNull @CallbackExecutor Executor executor, @NonNull BluetoothConnectionCallback callback) { if (DBG) Log.d(TAG, "registerBluetoothConnectionCallback()"); @@ -4069,7 +4117,8 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - if (!mService.registerBluetoothConnectionCallback(mConnectionCallback)) { + if (!mService.registerBluetoothConnectionCallback(mConnectionCallback, + mAttributionSource)) { return false; } } @@ -4098,7 +4147,11 @@ public final class BluetoothAdapter { * @return true if the callback was unregistered successfully, false otherwise * @hide */ - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean unregisterBluetoothConnectionCallback( @NonNull BluetoothConnectionCallback callback) { if (DBG) Log.d(TAG, "unregisterBluetoothConnectionCallback()"); @@ -4120,7 +4173,8 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.unregisterBluetoothConnectionCallback(mConnectionCallback); + return mService.unregisterBluetoothConnectionCallback(mConnectionCallback, + mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); -- cgit v1.2.3 From 4c2ce6e1885c73085bd2eece5cdc53e141348258 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Wed, 5 May 2021 14:04:04 -0700 Subject: Update BluetoothDevice#setAlias based on API council feedback: now accepts null input and returns an int (with error codes). Update CompanionDeviceManager#canPairWithoutPrompt to take a UserHandle instead of an int. Adds BluetoothStatusCodes class for all new Bluetooth error / success codes. Moved OOB and hci disconnect constants to the new BluetoothStatusCodes class. Tag: #feature Bug: 184714087 Test: atest BluetoothDeviceTest#test_setAlias_getAlias Change-Id: Ife03506f2cf68800f5824cb5fa94fec8aa34a39c --- .../java/android/bluetooth/BluetoothAdapter.java | 177 ++++----------------- 1 file changed, 28 insertions(+), 149 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 9fc1f88c01..54941724b2 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3258,38 +3258,13 @@ public final class BluetoothAdapter { /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "OOB_ERROR_" }, value = { - OOB_ERROR_UNKNOWN, - OOB_ERROR_ANOTHER_ACTIVE_REQUEST, - OOB_ERROR_ADAPTER_DISABLED + @IntDef(value = { + BluetoothStatusCodes.ERROR_UNKNOWN, + BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, + BluetoothStatusCodes.ERROR_ANOTHER_ACTIVE_OOB_REQUEST, }) public @interface OobError {} - /** - * An unknown error has occurred in the controller, stack, or callback pipeline. - * - * @hide - */ - @SystemApi - public static final int OOB_ERROR_UNKNOWN = 0; - - /** - * If another application has already requested {@link OobData} then another fetch will be - * disallowed until the callback is removed. - * - * @hide - */ - @SystemApi - public static final int OOB_ERROR_ANOTHER_ACTIVE_REQUEST = 1; - - /** - * The adapter is currently disabled, please enable it. - * - * @hide - */ - @SystemApi - public static final int OOB_ERROR_ADAPTER_DISABLED = 2; - /** * Provides callback methods for receiving {@link OobData} from the host stack, as well as an * error interface in order to allow the caller to determine next steps based on the {@code @@ -3310,7 +3285,7 @@ public final class BluetoothAdapter { /** * Provides feedback when things don't go as expected. * - * @param errorCode - the code descibing the type of error that occurred. + * @param errorCode - the code describing the type of error that occurred. */ void onError(@OobError int errorCode); } @@ -3407,7 +3382,7 @@ public final class BluetoothAdapter { Preconditions.checkNotNull(callback); if (!isEnabled()) { Log.w(TAG, "generateLocalOobData(): Adapter isn't enabled!"); - callback.onError(OOB_ERROR_ADAPTER_DISABLED); + callback.onError(BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED); } else { try { mService.generateLocalOobData(transport, new WrappedOobDataCallback(callback, @@ -4210,141 +4185,45 @@ public final class BluetoothAdapter { */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "REASON_" }, value = { - REASON_UNKNOWN, - REASON_LOCAL_REQUEST, - REASON_REMOTE_REQUEST, - REASON_LOCAL_ERROR, - REASON_REMOTE_ERROR, - REASON_TIMEOUT, - REASON_SECURITY, - REASON_SYSTEM_POLICY, - REASON_RESOURCE_LIMIT_REACHED, - REASON_CONNECTION_EXISTS, - REASON_BAD_PARAMETERS}) + BluetoothStatusCodes.ERROR_UNKNOWN, + BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST, + BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE_REQUEST, + BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL, + BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE, + BluetoothStatusCodes.ERROR_DISCONNECT_REASON_TIMEOUT, + BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SECURITY, + BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SYSTEM_POLICY, + BluetoothStatusCodes.ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED, + BluetoothStatusCodes.ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS, + BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS}) public @interface DisconnectReason {} - /** - * Indicates that the ACL disconnected due to an unknown reason. - */ - public static final int REASON_UNKNOWN = 0; - - /** - * Indicates that the ACL disconnected due to an explicit request from the local device. - *

- * Example cause: This is a normal disconnect reason, e.g., user/app initiates - * disconnection. - */ - public static final int REASON_LOCAL_REQUEST = 1; - - /** - * Indicates that the ACL disconnected due to an explicit request from the remote device. - *

- * Example cause: This is a normal disconnect reason, e.g., user/app initiates - * disconnection. - *

- * Example solution: The app can also prompt the user to check their remote device. - */ - public static final int REASON_REMOTE_REQUEST = 2; - - /** - * Generic disconnect reason indicating the ACL disconnected due to an error on the local - * device. - *

- * Example solution: Prompt the user to check their local device (e.g., phone, car - * headunit). - */ - public static final int REASON_LOCAL_ERROR = 3; - - /** - * Generic disconnect reason indicating the ACL disconnected due to an error on the remote - * device. - *

- * Example solution: Prompt the user to check their remote device (e.g., headset, car - * headunit, watch). - */ - public static final int REASON_REMOTE_ERROR = 4; - - /** - * Indicates that the ACL disconnected due to a timeout. - *

- * Example cause: remote device might be out of range. - *

- * Example solution: Prompt user to verify their remote device is on or in - * connection/pairing mode. - */ - public static final int REASON_TIMEOUT = 5; - - /** - * Indicates that the ACL disconnected due to link key issues. - *

- * Example cause: Devices are either unpaired or remote device is refusing our pairing - * request. - *

- * Example solution: Prompt user to unpair and pair again. - */ - public static final int REASON_SECURITY = 6; - - /** - * Indicates that the ACL disconnected due to the local device's system policy. - *

- * Example cause: privacy policy, power management policy, permissions, etc. - *

- * Example solution: Prompt the user to check settings, or check with their system - * administrator (e.g. some corp-managed devices do not allow OPP connection). - */ - public static final int REASON_SYSTEM_POLICY = 7; - - /** - * Indicates that the ACL disconnected due to resource constraints, either on the local - * device or the remote device. - *

- * Example cause: controller is busy, memory limit reached, maximum number of connections - * reached. - *

- * Example solution: The app should wait and try again. If still failing, prompt the user - * to disconnect some devices, or toggle Bluetooth on the local and/or the remote device. - */ - public static final int REASON_RESOURCE_LIMIT_REACHED = 8; - - /** - * Indicates that the ACL disconnected because another ACL connection already exists. - */ - public static final int REASON_CONNECTION_EXISTS = 9; - - /** - * Indicates that the ACL disconnected due to incorrect parameters passed in from the app. - *

- * Example solution: Change parameters and try again. If error persists, the app can report - * telemetry and/or log the error in a bugreport. - */ - public static final int REASON_BAD_PARAMETERS = 10; - /** * Returns human-readable strings corresponding to {@link DisconnectReason}. */ public static String disconnectReasonText(@DisconnectReason int reason) { switch (reason) { - case REASON_UNKNOWN: + case BluetoothStatusCodes.ERROR_UNKNOWN: return "Reason unknown"; - case REASON_LOCAL_REQUEST: + case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST: return "Local request"; - case REASON_REMOTE_REQUEST: + case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE_REQUEST: return "Remote request"; - case REASON_LOCAL_ERROR: + case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL: return "Local error"; - case REASON_REMOTE_ERROR: + case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE: return "Remote error"; - case REASON_TIMEOUT: + case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_TIMEOUT: return "Timeout"; - case REASON_SECURITY: + case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SECURITY: return "Security"; - case REASON_SYSTEM_POLICY: + case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SYSTEM_POLICY: return "System policy"; - case REASON_RESOURCE_LIMIT_REACHED: + case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED: return "Resource constrained"; - case REASON_CONNECTION_EXISTS: + case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS: return "Connection already exists"; - case REASON_BAD_PARAMETERS: + case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS: return "Bad parameters"; default: return "Unrecognized disconnect reason: " + reason; -- cgit v1.2.3 From 98f3044ce87c7ab9d2a0efbfb8ef6a16872262df Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 3 Jun 2021 09:26:53 -0600 Subject: More Binder call AttributionSource assignment. Since developers can use a BluetoothDevice object can make remote calls, it needs to have an accurate AttributionSource. Previous CLs had updated many places where these BluetoothDevice instances were passed across Binder interfaces, but this change updates several remaining locations which had been missed. Introduces new "Attributable" marker interface to offer consistent tooling when applying AttributionSource updates. Bug: 187097694 Test: atest BluetoothInstrumentationTests Change-Id: Icad3b9726591f0fbad58a493cefa5a0af7648280 --- .../java/android/bluetooth/BluetoothAdapter.java | 58 ++++++++++++---------- 1 file changed, 33 insertions(+), 25 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 54941724b2..054b63fbad 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -46,6 +46,7 @@ import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.compat.annotation.UnsupportedAppUsage; +import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.BatteryStats; @@ -719,8 +720,8 @@ public final class BluetoothAdapter { private final Object mLock = new Object(); private final Map mLeScanClients; - private static final Map>> - sMetadataListeners = new HashMap<>(); + private final Map>> + mMetadataListeners = new HashMap<>(); private final Map mBluetoothConnectionCallbackExecutorMap = new HashMap<>(); @@ -729,14 +730,15 @@ public final class BluetoothAdapter { * implementation. */ @SuppressLint("AndroidFrameworkBluetoothPermission") - private static final IBluetoothMetadataListener sBluetoothMetadataListener = + private final IBluetoothMetadataListener mBluetoothMetadataListener = new IBluetoothMetadataListener.Stub() { @Override public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) { - synchronized (sMetadataListeners) { - if (sMetadataListeners.containsKey(device)) { + Attributable.setAttributionSource(device, mAttributionSource); + synchronized (mMetadataListeners) { + if (mMetadataListeners.containsKey(device)) { List> list = - sMetadataListeners.get(device); + mMetadataListeners.get(device); for (Pair pair : list) { OnMetadataChangedListener listener = pair.first; Executor executor = pair.second; @@ -2445,7 +2447,9 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.getMostRecentlyConnectedDevices(mAttributionSource); + return Attributable.setAttributionSource( + mService.getMostRecentlyConnectedDevices(mAttributionSource), + mAttributionSource); } } catch (RemoteException e) { Log.e(TAG, "", e); @@ -2470,14 +2474,16 @@ public final class BluetoothAdapter { @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public Set getBondedDevices() { if (getState() != STATE_ON) { - return toDeviceSet(new BluetoothDevice[0]); + return toDeviceSet(Arrays.asList()); } try { mServiceLock.readLock().lock(); if (mService != null) { - return toDeviceSet(mService.getBondedDevices(mAttributionSource)); + return toDeviceSet(Attributable.setAttributionSource( + Arrays.asList(mService.getBondedDevices(mAttributionSource)), + mAttributionSource)); } - return toDeviceSet(new BluetoothDevice[0]); + return toDeviceSet(Arrays.asList()); } catch (RemoteException e) { Log.e(TAG, "", e); } finally { @@ -3165,10 +3171,10 @@ public final class BluetoothAdapter { } } } - synchronized (sMetadataListeners) { - sMetadataListeners.forEach((device, pair) -> { + synchronized (mMetadataListeners) { + mMetadataListeners.forEach((device, pair) -> { try { - mService.registerMetadataListener(sBluetoothMetadataListener, + mService.registerMetadataListener(mBluetoothMetadataListener, device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "Failed to register metadata listener", e); @@ -3455,8 +3461,8 @@ public final class BluetoothAdapter { } } - private Set toDeviceSet(BluetoothDevice[] devices) { - Set deviceSet = new HashSet(Arrays.asList(devices)); + private Set toDeviceSet(List devices) { + Set deviceSet = new HashSet(devices); return Collections.unmodifiableSet(deviceSet); } @@ -3926,13 +3932,13 @@ public final class BluetoothAdapter { throw new NullPointerException("executor is null"); } - synchronized (sMetadataListeners) { + synchronized (mMetadataListeners) { List> listenerList = - sMetadataListeners.get(device); + mMetadataListeners.get(device); if (listenerList == null) { // Create new listener/executor list for registeration listenerList = new ArrayList<>(); - sMetadataListeners.put(device, listenerList); + mMetadataListeners.put(device, listenerList); } else { // Check whether this device was already registed by the lisenter if (listenerList.stream().anyMatch((pair) -> (pair.first.equals(listener)))) { @@ -3946,7 +3952,7 @@ public final class BluetoothAdapter { boolean ret = false; try { - ret = service.registerMetadataListener(sBluetoothMetadataListener, device, + ret = service.registerMetadataListener(mBluetoothMetadataListener, device, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "registerMetadataListener fail", e); @@ -3956,7 +3962,7 @@ public final class BluetoothAdapter { listenerList.remove(listenerPair); if (listenerList.isEmpty()) { // Remove the device if its listener list is empty - sMetadataListeners.remove(device); + mMetadataListeners.remove(device); } } } @@ -3995,17 +4001,17 @@ public final class BluetoothAdapter { throw new NullPointerException("listener is null"); } - synchronized (sMetadataListeners) { - if (!sMetadataListeners.containsKey(device)) { + synchronized (mMetadataListeners) { + if (!mMetadataListeners.containsKey(device)) { throw new IllegalArgumentException("device was not registered"); } // Remove issued listener from the registered device - sMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener))); + mMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener))); - if (sMetadataListeners.get(device).isEmpty()) { + if (mMetadataListeners.get(device).isEmpty()) { // Unregister to Bluetooth service if all listeners are removed from // the registered device - sMetadataListeners.remove(device); + mMetadataListeners.remove(device); final IBluetooth service = mService; if (service == null) { // Bluetooth is OFF, do nothing to Bluetooth service. @@ -4045,6 +4051,7 @@ public final class BluetoothAdapter { new IBluetoothConnectionCallback.Stub() { @Override public void onDeviceConnected(BluetoothDevice device) { + Attributable.setAttributionSource(device, mAttributionSource); for (Map.Entry callbackExecutorEntry: mBluetoothConnectionCallbackExecutorMap.entrySet()) { BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); @@ -4055,6 +4062,7 @@ public final class BluetoothAdapter { @Override public void onDeviceDisconnected(BluetoothDevice device, int hciReason) { + Attributable.setAttributionSource(device, mAttributionSource); for (Map.Entry callbackExecutorEntry: mBluetoothConnectionCallbackExecutorMap.entrySet()) { BluetoothConnectionCallback callback = callbackExecutorEntry.getKey(); -- cgit v1.2.3 From 1b3ac7733b50556d440ec8a5453645c074301c7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Rymanowski?= Date: Tue, 26 Jan 2021 06:39:08 +0000 Subject: Bluetooth: add Volume Control Profile boilerpalate This is very simple API to allow Android to connect VCP profile. Bug: 150670922 Test: compilation Sponsor: jpawlowski@ CTS-Coverage-Bug: 190833351 Change-Id: Ib20d967fcf6797077abf83b40b0eda526e5ab89d Merged-In: Ib20d967fcf6797077abf83b40b0eda526e5ab89d --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 63221c5d89..0dd6b4f636 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2815,6 +2815,9 @@ public final class BluetoothAdapter { return true; } return false; + } else if (profile == BluetoothProfile.VOLUME_CONTROL) { + BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this); + return true; } else { return false; } @@ -2899,6 +2902,11 @@ public final class BluetoothAdapter { case BluetoothProfile.HEARING_AID: BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy; hearingAid.close(); + break; + case BluetoothProfile.VOLUME_CONTROL: + BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy; + vcs.close(); + break; } } -- cgit v1.2.3 From 3728cb64ab3dfbcb0edcf6ed52613ae348b8c814 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Thu, 10 Jun 2021 17:28:38 -0700 Subject: Update nullability checks to use Objects#requireNonNull instead of deprecated method in Preconditions class Tag: #feature Bug: 190767948 Test: Manual Change-Id: Ie7f7282b89c13f587fdfe1bf3288eb4a3c7dcc6e --- framework/java/android/bluetooth/BluetoothAdapter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 054b63fbad..ded5e6e27a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -17,6 +17,8 @@ package android.bluetooth; +import static java.util.Objects.requireNonNull; + import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; @@ -62,8 +64,6 @@ import android.os.SystemProperties; import android.util.Log; import android.util.Pair; -import com.android.internal.util.Preconditions; - import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -3314,8 +3314,8 @@ public final class BluetoothAdapter { */ WrappedOobDataCallback(@NonNull OobDataCallback callback, @NonNull @CallbackExecutor Executor executor) { - Preconditions.checkNotNull(callback); - Preconditions.checkNotNull(executor); + requireNonNull(callback); + requireNonNull(executor); mCallback = callback; mExecutor = executor; } @@ -3385,7 +3385,7 @@ public final class BluetoothAdapter { != BluetoothDevice.TRANSPORT_LE) { throw new IllegalArgumentException("Invalid transport '" + transport + "'!"); } - Preconditions.checkNotNull(callback); + requireNonNull(callback); if (!isEnabled()) { Log.w(TAG, "generateLocalOobData(): Adapter isn't enabled!"); callback.onError(BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED); @@ -3522,7 +3522,7 @@ public final class BluetoothAdapter { * @hide */ public static boolean isAddressRandomStatic(@NonNull String address) { - Preconditions.checkNotNull(address); + requireNonNull(address); return checkBluetoothAddress(address) && (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11; } -- cgit v1.2.3 From 508506d886e5bc53c0b39ffabaaa8d4aa9881551 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Thu, 10 Jun 2021 17:28:38 -0700 Subject: Update nullability checks to use Objects#requireNonNull instead of deprecated method in Preconditions class Tag: #feature Bug: 190767948 Test: Manual Merged-In: Ie7f7282b89c13f587fdfe1bf3288eb4a3c7dcc6e Change-Id: Ie7f7282b89c13f587fdfe1bf3288eb4a3c7dcc6e --- framework/java/android/bluetooth/BluetoothAdapter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 63221c5d89..331fd07a6a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -17,6 +17,8 @@ package android.bluetooth; +import static java.util.Objects.requireNonNull; + import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.IntDef; @@ -53,8 +55,6 @@ import android.os.SystemProperties; import android.util.Log; import android.util.Pair; -import com.android.internal.util.Preconditions; - import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -3091,8 +3091,8 @@ public final class BluetoothAdapter { */ WrappedOobDataCallback(@NonNull OobDataCallback callback, @NonNull @CallbackExecutor Executor executor) { - Preconditions.checkNotNull(callback); - Preconditions.checkNotNull(executor); + requireNonNull(callback); + requireNonNull(executor); mCallback = callback; mExecutor = executor; } @@ -3158,7 +3158,7 @@ public final class BluetoothAdapter { != BluetoothDevice.TRANSPORT_LE) { throw new IllegalArgumentException("Invalid transport '" + transport + "'!"); } - Preconditions.checkNotNull(callback); + requireNonNull(callback); if (!isEnabled()) { Log.w(TAG, "generateLocalOobData(): Adapter isn't enabled!"); callback.onError(OOB_ERROR_ADAPTER_DISABLED); @@ -3293,7 +3293,7 @@ public final class BluetoothAdapter { * @hide */ public static boolean isAddressRandomStatic(@NonNull String address) { - Preconditions.checkNotNull(address); + requireNonNull(address); return checkBluetoothAddress(address) && (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11; } -- cgit v1.2.3 From 2dd8f397af3e604736bdb7f8c1e9d16c6cf7e0ed Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Fri, 18 Jun 2021 09:01:42 +0200 Subject: DO NOT MERGE Revert "Bluetooth: add Volume Control Profile boilerpalate" This reverts commit 1b3ac7733b50556d440ec8a5453645c074301c7b. Merged-In: Ib20d967fcf6797077abf83b40b0eda526e5ab89d Change-Id: I164fcdeddab6579cf10174c1123984e856fa6f20 --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 -------- 1 file changed, 8 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b0b247868b..ded5e6e27a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3054,9 +3054,6 @@ public final class BluetoothAdapter { return true; } return false; - } else if (profile == BluetoothProfile.VOLUME_CONTROL) { - BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this); - return true; } else { return false; } @@ -3145,11 +3142,6 @@ public final class BluetoothAdapter { case BluetoothProfile.HEARING_AID: BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy; hearingAid.close(); - break; - case BluetoothProfile.VOLUME_CONTROL: - BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy; - vcs.close(); - break; } } -- cgit v1.2.3 From 40ef4d5c4d3f72a207b4beeb9a21568b28aa9496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Rymanowski?= Date: Tue, 26 Jan 2021 06:39:08 +0000 Subject: DO NOT MERGE Bluetooth: add Volume Control Profile boilerpalate This is very simple API to allow Android to connect VCP profile. Bug: 150670922 Test: compilation Sponsor: jpawlowski@ CTS-Coverage-Bug: 190833351 Merged-In: Ib20d967fcf6797077abf83b40b0eda526e5ab89d Change-Id: Ib20d967fcf6797077abf83b40b0eda526e5ab89d --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ded5e6e27a..b0b247868b 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3054,6 +3054,9 @@ public final class BluetoothAdapter { return true; } return false; + } else if (profile == BluetoothProfile.VOLUME_CONTROL) { + BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this); + return true; } else { return false; } @@ -3142,6 +3145,11 @@ public final class BluetoothAdapter { case BluetoothProfile.HEARING_AID: BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy; hearingAid.close(); + break; + case BluetoothProfile.VOLUME_CONTROL: + BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy; + vcs.close(); + break; } } -- cgit v1.2.3 From 5f9c97831b9e77b947e0fa1fdc0cd033b26e492b Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Fri, 18 Jun 2021 09:01:42 +0200 Subject: DO NOT MERGE Revert "Bluetooth: add Volume Control Profile boilerpalate" This reverts commit 1b3ac7733b50556d440ec8a5453645c074301c7b. Merged-In: Ib20d967fcf6797077abf83b40b0eda526e5ab89d Change-Id: I164fcdeddab6579cf10174c1123984e856fa6f20 --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 -------- 1 file changed, 8 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b0b247868b..ded5e6e27a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3054,9 +3054,6 @@ public final class BluetoothAdapter { return true; } return false; - } else if (profile == BluetoothProfile.VOLUME_CONTROL) { - BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this); - return true; } else { return false; } @@ -3145,11 +3142,6 @@ public final class BluetoothAdapter { case BluetoothProfile.HEARING_AID: BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy; hearingAid.close(); - break; - case BluetoothProfile.VOLUME_CONTROL: - BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy; - vcs.close(); - break; } } -- cgit v1.2.3 From 2549cf892ce15e32747008614c0a37c0fa88ebea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Rymanowski?= Date: Tue, 26 Jan 2021 06:39:08 +0000 Subject: DO NOT MERGE Bluetooth: add Volume Control Profile boilerpalate This is very simple API to allow Android to connect VCP profile. Bug: 150670922 Test: compilation Sponsor: jpawlowski@ CTS-Coverage-Bug: 190833351 Merged-In: Ib20d967fcf6797077abf83b40b0eda526e5ab89d Change-Id: Ib20d967fcf6797077abf83b40b0eda526e5ab89d --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ded5e6e27a..b0b247868b 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3054,6 +3054,9 @@ public final class BluetoothAdapter { return true; } return false; + } else if (profile == BluetoothProfile.VOLUME_CONTROL) { + BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this); + return true; } else { return false; } @@ -3142,6 +3145,11 @@ public final class BluetoothAdapter { case BluetoothProfile.HEARING_AID: BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy; hearingAid.close(); + break; + case BluetoothProfile.VOLUME_CONTROL: + BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy; + vcs.close(); + break; } } -- cgit v1.2.3 From fe3d6da465f03900006100efa8618502d16334ff Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Wed, 23 Jun 2021 15:09:45 -0700 Subject: Add BluetoothLeAudio to BluetoothAdapter#getProfileProxy and BluetoothAdapter#closeProfileProxy Tag: #feature Bug: 15083918 Test: Manual Merged-In: Ia46dc4e50d42dbd574588b531045cb680aa09d94 Change-Id: Ia46dc4e50d42dbd574588b531045cb680aa09d94 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ded5e6e27a..5b72b76c35 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3054,6 +3054,9 @@ public final class BluetoothAdapter { return true; } return false; + } else if (profile == BluetoothProfile.LE_AUDIO) { + BluetoothLeAudio leAudio = new BluetoothLeAudio(context, listener, this); + return true; } else { return false; } @@ -3142,6 +3145,10 @@ public final class BluetoothAdapter { case BluetoothProfile.HEARING_AID: BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy; hearingAid.close(); + break; + case BluetoothProfile.LE_AUDIO: + BluetoothLeAudio leAudio = (BluetoothLeAudio) proxy; + leAudio.close(); } } -- cgit v1.2.3 From 5708b05dd7c110aa2cbf99d0902ba93140f71498 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Wed, 19 May 2021 21:18:59 -0700 Subject: Update BluetoothAdapter and BluetoothDevice documentation Update BluetoothAdapter#startDiscovery and BluetoothDevice#fetchUuidsWithSdp documentation to indicate that it queues the request if a device is currently bonding Tag: #feature Bug: 187165224 Test: Manual Change-Id: I3dbcdacff062f6c33c2fdc8d64170bf60b2fbf6f --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e305aa8e33..ce384868d4 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1698,9 +1698,10 @@ public final class BluetoothAdapter { * discoverable (inquiry scan enabled). Many Bluetooth devices are * not discoverable by default, and need to be entered into a special mode. *

If Bluetooth state is not {@link #STATE_ON}, this API - * will return false. After turning on Bluetooth, - * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} - * to get the updated value. + * will return false. After turning on Bluetooth, wait for {@link #ACTION_STATE_CHANGED} + * with {@link #STATE_ON} to get the updated value. + *

If a device is currently bonding, this request will be queued and executed once that + * device has finished bonding. If a request is already queued, this request will be ignored. * * @return true on success, false on error */ -- cgit v1.2.3 From 2cae3b9cd95f617b366621a6a3c9123e2605002e Mon Sep 17 00:00:00 2001 From: Etienne Ruffieux Date: Thu, 1 Jul 2021 22:39:36 +0000 Subject: Update BluetoothAdapter and BluetoothDevice documentation Update BluetoothAdapter#startDiscovery and BluetoothDevice#fetchUuidsWithSdp documentation to indicate that it queues the request if a device is currently bonding Tag: #feature Bug: 187165224 Test: Manual Merged-In: I3dbcdacff062f6c33c2fdc8d64170bf60b2fbf6f Change-Id: I7e598417ba96a5acc9f13fb6d29a0612740f31b4 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 5b72b76c35..421b4de9d6 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1799,9 +1799,10 @@ public final class BluetoothAdapter { * discoverable (inquiry scan enabled). Many Bluetooth devices are * not discoverable by default, and need to be entered into a special mode. *

If Bluetooth state is not {@link #STATE_ON}, this API - * will return false. After turning on Bluetooth, - * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} - * to get the updated value. + * will return false. After turning on Bluetooth, wait for {@link #ACTION_STATE_CHANGED} + * with {@link #STATE_ON} to get the updated value. + *

If a device is currently bonding, this request will be queued and executed once that + * device has finished bonding. If a request is already queued, this request will be ignored. * * @return true on success, false on error */ -- cgit v1.2.3 From 6106c3602038e5cb2f6a283322a3be382425cd59 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 7 Jul 2021 17:17:04 -0600 Subject: Tag some "new Binder()" instances to detect leaks. We've seen evidence of a Binder leak, and our hunch is that it's caused by one of these anonymous "new Binder()" sites. Adding descriptors will help us identify the leak cause. Bug: 192415943 Test: atest BluetoothInstrumentationTests Change-Id: I30cd15f084cf50f67edd833b27b853c4b22e1db1 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 421b4de9d6..f5ab2ab744 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -120,6 +120,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; */ public final class BluetoothAdapter { private static final String TAG = "BluetoothAdapter"; + private static final String DESCRIPTOR = "android.bluetooth.BluetoothAdapter"; private static final boolean DBG = true; private static final boolean VDBG = false; @@ -805,7 +806,7 @@ public final class BluetoothAdapter { mManagerService = Objects.requireNonNull(managerService); mAttributionSource = Objects.requireNonNull(attributionSource); mLeScanClients = new HashMap(); - mToken = new Binder(); + mToken = new Binder(DESCRIPTOR); } /** -- cgit v1.2.3 From 1f29a9b36139b6ae6b6a6bf29fca5ee59201c8b9 Mon Sep 17 00:00:00 2001 From: Yunsik Bae Date: Tue, 20 Jul 2021 06:56:50 +0000 Subject: Unify the mismatch in the byte order of the address. Bluetooth address should check MSB for AddrType based on Spec. (BT Core Spec v 5.2 | Vol 6, Part B, 1.3 DEVICE ADDRESS) Bluetooth address meaning is not unified in the current Android framework layer. Because of this, cannot register scanfilter with the intended address format. Bug: 180466950 Test: manual Tag: #compatibility Change-Id: I59a1b5538e4f3fea77a98cba2aa46649fc32ac6b --- framework/java/android/bluetooth/BluetoothAdapter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index ce384868d4..d487025631 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3289,22 +3289,22 @@ public final class BluetoothAdapter { } /** - * Determines whether a String Bluetooth address, such as "00:43:A8:23:10:F0" + * Determines whether a String Bluetooth address, such as "F0:43:A8:23:10:00" * is a RANDOM STATIC address. * - * RANDOM STATIC: (addr & 0b11) == 0b11 - * RANDOM RESOLVABLE: (addr & 0b11) == 0b10 - * RANDOM non-RESOLVABLE: (addr & 0b11) == 0b00 + * RANDOM STATIC: (addr & 0xC0) == 0xC0 + * RANDOM RESOLVABLE: (addr & 0xC0) == 0x40 + * RANDOM non-RESOLVABLE: (addr & 0xC0) == 0x00 * * @param address Bluetooth address as string - * @return true if the 2 Least Significant Bits of the address equals 0b11. + * @return true if the 2 Most Significant Bits of the address equals 0xC0. * * @hide */ public static boolean isAddressRandomStatic(@NonNull String address) { requireNonNull(address); return checkBluetoothAddress(address) - && (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11; + && (Integer.parseInt(address.split(":")[0], 16) & 0xC0) == 0xC0; } @UnsupportedAppUsage -- cgit v1.2.3 From f90d578773ae80c01eb94f2a34b1c1718a9d4ed7 Mon Sep 17 00:00:00 2001 From: Yunsik Bae Date: Tue, 20 Jul 2021 06:56:50 +0000 Subject: Unify the mismatch in the byte order of the address. Bluetooth address should check MSB for AddrType based on Spec. (BT Core Spec v 5.2 | Vol 6, Part B, 1.3 DEVICE ADDRESS) Bluetooth address meaning is not unified in the current Android framework layer. Because of this, cannot register scanfilter with the intended address format. Bug: 180466950 Test: manual Tag: #compatibility Change-Id: I59a1b5538e4f3fea77a98cba2aa46649fc32ac6b Merged-In: I59a1b5538e4f3fea77a98cba2aa46649fc32ac6b --- framework/java/android/bluetooth/BluetoothAdapter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index f5ab2ab744..8398be1af4 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3518,22 +3518,22 @@ public final class BluetoothAdapter { } /** - * Determines whether a String Bluetooth address, such as "00:43:A8:23:10:F0" + * Determines whether a String Bluetooth address, such as "F0:43:A8:23:10:00" * is a RANDOM STATIC address. * - * RANDOM STATIC: (addr & 0b11) == 0b11 - * RANDOM RESOLVABLE: (addr & 0b11) == 0b10 - * RANDOM non-RESOLVABLE: (addr & 0b11) == 0b00 + * RANDOM STATIC: (addr & 0xC0) == 0xC0 + * RANDOM RESOLVABLE: (addr & 0xC0) == 0x40 + * RANDOM non-RESOLVABLE: (addr & 0xC0) == 0x00 * * @param address Bluetooth address as string - * @return true if the 2 Least Significant Bits of the address equals 0b11. + * @return true if the 2 Most Significant Bits of the address equals 0xC0. * * @hide */ public static boolean isAddressRandomStatic(@NonNull String address) { requireNonNull(address); return checkBluetoothAddress(address) - && (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11; + && (Integer.parseInt(address.split(":")[0], 16) & 0xC0) == 0xC0; } /** {@hide} */ -- cgit v1.2.3 From 56a86434a2277555bb8051443a38c9061a947d9b Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 10 Aug 2021 16:50:52 -0600 Subject: Register IBluetoothManagerCallback per-process. As part of introducing AttributionSource across the Bluetooth stack earlier this year, each BluetoothAdapter instance is now associated with a specific AttributionSource, and several instances of shared static code were made BluetoothAdapter-specific so they could be augmented with the relevant AttributionSource. However, processes that create many BluetoothAdapter instances can overload the system, since a IBluetoothManagerCallback was registered for each instance. This change mitigates this by only registering a single IBluetoothManagerCallback for the entire process, and it then reuses the existing sProxyServiceStateCallbacks list for dispatching events to all active adapters within the process. Since it's so late in the release, we keep both mService and sService intact to minimize the size of this CL; future work should refactor to a more robust design, such as Supplier. Bug: 195286998, 172022978 Test: atest BluetoothInstrumentationTests Change-Id: I012f3f65e61eaf55e40436486806e56506c928ee --- .../java/android/bluetooth/BluetoothAdapter.java | 184 ++++++++++++++------- 1 file changed, 124 insertions(+), 60 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8398be1af4..5094498dbe 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -64,6 +64,8 @@ import android.os.SystemProperties; import android.util.Log; import android.util.Pair; +import com.android.internal.annotations.GuardedBy; + import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -78,6 +80,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.WeakHashMap; import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -715,10 +718,21 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; private final AttributionSource mAttributionSource; + // Yeah, keeping both mService and sService isn't pretty, but it's too late + // in the current release for a major refactoring, so we leave them both + // intact until this can be cleaned up in a future release + @UnsupportedAppUsage + @GuardedBy("mServiceLock") private IBluetooth mService; private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); + @GuardedBy("sServiceLock") + private static boolean sServiceRegistered; + @GuardedBy("sServiceLock") + private static IBluetooth sService; + private static final Object sServiceLock = new Object(); + private final Object mLock = new Object(); private final Map mLeScanClients; private final Map>> @@ -792,19 +806,11 @@ public final class BluetoothAdapter { * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. */ BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) { - if (managerService == null) { - throw new IllegalArgumentException("bluetooth manager service is null"); - } - try { - mServiceLock.writeLock().lock(); - mService = managerService.registerAdapter(mManagerCallback); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.writeLock().unlock(); - } mManagerService = Objects.requireNonNull(managerService); mAttributionSource = Objects.requireNonNull(attributionSource); + synchronized (mServiceLock.writeLock()) { + mService = getBluetoothService(mManagerCallback); + } mLeScanClients = new HashMap(); mToken = new Binder(DESCRIPTOR); } @@ -3154,21 +3160,16 @@ public final class BluetoothAdapter { } } - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final IBluetoothManagerCallback mManagerCallback = + private static final IBluetoothManagerCallback sManagerCallback = new IBluetoothManagerCallback.Stub() { - @SuppressLint("AndroidFrameworkRequiresPermission") public void onBluetoothServiceUp(IBluetooth bluetoothService) { if (DBG) { Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); } - mServiceLock.writeLock().lock(); - mService = bluetoothService; - mServiceLock.writeLock().unlock(); - - synchronized (mProxyServiceStateCallbacks) { - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) { + synchronized (sServiceLock) { + sService = bluetoothService; + for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) { try { if (cb != null) { cb.onBluetoothServiceUp(bluetoothService); @@ -3180,6 +3181,56 @@ public final class BluetoothAdapter { } } } + } + + public void onBluetoothServiceDown() { + if (DBG) { + Log.d(TAG, "onBluetoothServiceDown"); + } + + synchronized (sServiceLock) { + sService = null; + for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) { + try { + if (cb != null) { + cb.onBluetoothServiceDown(); + } else { + Log.d(TAG, "onBluetoothServiceDown: cb is null!"); + } + } catch (Exception e) { + Log.e(TAG, "", e); + } + } + } + } + + public void onBrEdrDown() { + if (VDBG) { + Log.i(TAG, "onBrEdrDown"); + } + + synchronized (sServiceLock) { + for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) { + try { + if (cb != null) { + cb.onBrEdrDown(); + } else { + Log.d(TAG, "onBrEdrDown: cb is null!"); + } + } catch (Exception e) { + Log.e(TAG, "", e); + } + } + } + } + }; + + private final IBluetoothManagerCallback mManagerCallback = + new IBluetoothManagerCallback.Stub() { + public void onBluetoothServiceUp(IBluetooth bluetoothService) { + synchronized (mServiceLock.writeLock()) { + mService = bluetoothService; + } synchronized (mMetadataListeners) { mMetadataListeners.forEach((device, pair) -> { try { @@ -3204,12 +3255,7 @@ public final class BluetoothAdapter { } public void onBluetoothServiceDown() { - if (DBG) { - Log.d(TAG, "onBluetoothServiceDown: " + mService); - } - - try { - mServiceLock.writeLock().lock(); + synchronized (mServiceLock.writeLock()) { mService = null; if (mLeScanClients != null) { mLeScanClients.clear(); @@ -3220,29 +3266,10 @@ public final class BluetoothAdapter { if (mBluetoothLeScanner != null) { mBluetoothLeScanner.cleanup(); } - } finally { - mServiceLock.writeLock().unlock(); - } - - synchronized (mProxyServiceStateCallbacks) { - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) { - try { - if (cb != null) { - cb.onBluetoothServiceDown(); - } else { - Log.d(TAG, "onBluetoothServiceDown: cb is null!"); - } - } catch (Exception e) { - Log.e(TAG, "", e); - } - } } } public void onBrEdrDown() { - if (VDBG) { - Log.i(TAG, "onBrEdrDown: " + mService); - } } }; @@ -3477,15 +3504,12 @@ public final class BluetoothAdapter { protected void finalize() throws Throwable { try { - mManagerService.unregisterAdapter(mManagerCallback); - } catch (RemoteException e) { - Log.e(TAG, "", e); + removeServiceStateCallback(mManagerCallback); } finally { super.finalize(); } } - /** * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0" *

Alphabetic characters must be uppercase to be valid. @@ -3549,24 +3573,64 @@ public final class BluetoothAdapter { return mAttributionSource; } - private final ArrayList mProxyServiceStateCallbacks = - new ArrayList(); + @GuardedBy("sServiceLock") + private static final WeakHashMap sProxyServiceStateCallbacks = + new WeakHashMap<>(); + + /*package*/ IBluetooth getBluetoothService() { + synchronized (sServiceLock) { + if (sProxyServiceStateCallbacks.isEmpty()) { + throw new IllegalStateException( + "Anonymous service access requires at least one lifecycle in process"); + } + return sService; + } + } @UnsupportedAppUsage /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { - synchronized (mProxyServiceStateCallbacks) { - if (cb == null) { - Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback"); - } else if (!mProxyServiceStateCallbacks.contains(cb)) { - mProxyServiceStateCallbacks.add(cb); - } + Objects.requireNonNull(cb); + synchronized (sServiceLock) { + sProxyServiceStateCallbacks.put(cb, null); + registerOrUnregisterAdapterLocked(); + return sService; } - return mService; } /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) { - synchronized (mProxyServiceStateCallbacks) { - mProxyServiceStateCallbacks.remove(cb); + Objects.requireNonNull(cb); + synchronized (sServiceLock) { + sProxyServiceStateCallbacks.remove(cb); + registerOrUnregisterAdapterLocked(); + } + } + + /** + * Handle registering (or unregistering) a single process-wide + * {@link IBluetoothManagerCallback} based on the presence of local + * {@link #sProxyServiceStateCallbacks} clients. + */ + @GuardedBy("sServiceLock") + private void registerOrUnregisterAdapterLocked() { + final boolean isRegistered = sServiceRegistered; + final boolean wantRegistered = !sProxyServiceStateCallbacks.isEmpty(); + + if (isRegistered != wantRegistered) { + if (wantRegistered) { + try { + sService = mManagerService.registerAdapter(sManagerCallback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } else { + try { + mManagerService.unregisterAdapter(sManagerCallback); + sService = null; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + sServiceRegistered = wantRegistered; } } -- cgit v1.2.3 From a1157dbeedfecfdb039802cee22a5f5e1abf0cf8 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 10 Aug 2021 16:50:52 -0600 Subject: Register IBluetoothManagerCallback per-process. As part of introducing AttributionSource across the Bluetooth stack earlier this year, each BluetoothAdapter instance is now associated with a specific AttributionSource, and several instances of shared static code were made BluetoothAdapter-specific so they could be augmented with the relevant AttributionSource. However, processes that create many BluetoothAdapter instances can overload the system, since a IBluetoothManagerCallback was registered for each instance. This change mitigates this by only registering a single IBluetoothManagerCallback for the entire process, and it then reuses the existing sProxyServiceStateCallbacks list for dispatching events to all active adapters within the process. Since it's so late in the release, we keep both mService and sService intact to minimize the size of this CL; future work should refactor to a more robust design, such as Supplier. Bug: 195286998, 172022978 Test: atest BluetoothInstrumentationTests Change-Id: I012f3f65e61eaf55e40436486806e56506c928ee (cherry picked from commit f0fa7f9b4aaee876053486d988909df9dc64e990) --- .../java/android/bluetooth/BluetoothAdapter.java | 184 ++++++++++++++------- 1 file changed, 124 insertions(+), 60 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 8398be1af4..5094498dbe 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -64,6 +64,8 @@ import android.os.SystemProperties; import android.util.Log; import android.util.Pair; +import com.android.internal.annotations.GuardedBy; + import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -78,6 +80,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.WeakHashMap; import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -715,10 +718,21 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; private final AttributionSource mAttributionSource; + // Yeah, keeping both mService and sService isn't pretty, but it's too late + // in the current release for a major refactoring, so we leave them both + // intact until this can be cleaned up in a future release + @UnsupportedAppUsage + @GuardedBy("mServiceLock") private IBluetooth mService; private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); + @GuardedBy("sServiceLock") + private static boolean sServiceRegistered; + @GuardedBy("sServiceLock") + private static IBluetooth sService; + private static final Object sServiceLock = new Object(); + private final Object mLock = new Object(); private final Map mLeScanClients; private final Map>> @@ -792,19 +806,11 @@ public final class BluetoothAdapter { * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. */ BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) { - if (managerService == null) { - throw new IllegalArgumentException("bluetooth manager service is null"); - } - try { - mServiceLock.writeLock().lock(); - mService = managerService.registerAdapter(mManagerCallback); - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.writeLock().unlock(); - } mManagerService = Objects.requireNonNull(managerService); mAttributionSource = Objects.requireNonNull(attributionSource); + synchronized (mServiceLock.writeLock()) { + mService = getBluetoothService(mManagerCallback); + } mLeScanClients = new HashMap(); mToken = new Binder(DESCRIPTOR); } @@ -3154,21 +3160,16 @@ public final class BluetoothAdapter { } } - @SuppressLint("AndroidFrameworkBluetoothPermission") - private final IBluetoothManagerCallback mManagerCallback = + private static final IBluetoothManagerCallback sManagerCallback = new IBluetoothManagerCallback.Stub() { - @SuppressLint("AndroidFrameworkRequiresPermission") public void onBluetoothServiceUp(IBluetooth bluetoothService) { if (DBG) { Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); } - mServiceLock.writeLock().lock(); - mService = bluetoothService; - mServiceLock.writeLock().unlock(); - - synchronized (mProxyServiceStateCallbacks) { - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) { + synchronized (sServiceLock) { + sService = bluetoothService; + for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) { try { if (cb != null) { cb.onBluetoothServiceUp(bluetoothService); @@ -3180,6 +3181,56 @@ public final class BluetoothAdapter { } } } + } + + public void onBluetoothServiceDown() { + if (DBG) { + Log.d(TAG, "onBluetoothServiceDown"); + } + + synchronized (sServiceLock) { + sService = null; + for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) { + try { + if (cb != null) { + cb.onBluetoothServiceDown(); + } else { + Log.d(TAG, "onBluetoothServiceDown: cb is null!"); + } + } catch (Exception e) { + Log.e(TAG, "", e); + } + } + } + } + + public void onBrEdrDown() { + if (VDBG) { + Log.i(TAG, "onBrEdrDown"); + } + + synchronized (sServiceLock) { + for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) { + try { + if (cb != null) { + cb.onBrEdrDown(); + } else { + Log.d(TAG, "onBrEdrDown: cb is null!"); + } + } catch (Exception e) { + Log.e(TAG, "", e); + } + } + } + } + }; + + private final IBluetoothManagerCallback mManagerCallback = + new IBluetoothManagerCallback.Stub() { + public void onBluetoothServiceUp(IBluetooth bluetoothService) { + synchronized (mServiceLock.writeLock()) { + mService = bluetoothService; + } synchronized (mMetadataListeners) { mMetadataListeners.forEach((device, pair) -> { try { @@ -3204,12 +3255,7 @@ public final class BluetoothAdapter { } public void onBluetoothServiceDown() { - if (DBG) { - Log.d(TAG, "onBluetoothServiceDown: " + mService); - } - - try { - mServiceLock.writeLock().lock(); + synchronized (mServiceLock.writeLock()) { mService = null; if (mLeScanClients != null) { mLeScanClients.clear(); @@ -3220,29 +3266,10 @@ public final class BluetoothAdapter { if (mBluetoothLeScanner != null) { mBluetoothLeScanner.cleanup(); } - } finally { - mServiceLock.writeLock().unlock(); - } - - synchronized (mProxyServiceStateCallbacks) { - for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) { - try { - if (cb != null) { - cb.onBluetoothServiceDown(); - } else { - Log.d(TAG, "onBluetoothServiceDown: cb is null!"); - } - } catch (Exception e) { - Log.e(TAG, "", e); - } - } } } public void onBrEdrDown() { - if (VDBG) { - Log.i(TAG, "onBrEdrDown: " + mService); - } } }; @@ -3477,15 +3504,12 @@ public final class BluetoothAdapter { protected void finalize() throws Throwable { try { - mManagerService.unregisterAdapter(mManagerCallback); - } catch (RemoteException e) { - Log.e(TAG, "", e); + removeServiceStateCallback(mManagerCallback); } finally { super.finalize(); } } - /** * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0" *

Alphabetic characters must be uppercase to be valid. @@ -3549,24 +3573,64 @@ public final class BluetoothAdapter { return mAttributionSource; } - private final ArrayList mProxyServiceStateCallbacks = - new ArrayList(); + @GuardedBy("sServiceLock") + private static final WeakHashMap sProxyServiceStateCallbacks = + new WeakHashMap<>(); + + /*package*/ IBluetooth getBluetoothService() { + synchronized (sServiceLock) { + if (sProxyServiceStateCallbacks.isEmpty()) { + throw new IllegalStateException( + "Anonymous service access requires at least one lifecycle in process"); + } + return sService; + } + } @UnsupportedAppUsage /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { - synchronized (mProxyServiceStateCallbacks) { - if (cb == null) { - Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback"); - } else if (!mProxyServiceStateCallbacks.contains(cb)) { - mProxyServiceStateCallbacks.add(cb); - } + Objects.requireNonNull(cb); + synchronized (sServiceLock) { + sProxyServiceStateCallbacks.put(cb, null); + registerOrUnregisterAdapterLocked(); + return sService; } - return mService; } /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) { - synchronized (mProxyServiceStateCallbacks) { - mProxyServiceStateCallbacks.remove(cb); + Objects.requireNonNull(cb); + synchronized (sServiceLock) { + sProxyServiceStateCallbacks.remove(cb); + registerOrUnregisterAdapterLocked(); + } + } + + /** + * Handle registering (or unregistering) a single process-wide + * {@link IBluetoothManagerCallback} based on the presence of local + * {@link #sProxyServiceStateCallbacks} clients. + */ + @GuardedBy("sServiceLock") + private void registerOrUnregisterAdapterLocked() { + final boolean isRegistered = sServiceRegistered; + final boolean wantRegistered = !sProxyServiceStateCallbacks.isEmpty(); + + if (isRegistered != wantRegistered) { + if (wantRegistered) { + try { + sService = mManagerService.registerAdapter(sManagerCallback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } else { + try { + mManagerService.unregisterAdapter(sManagerCallback); + sService = null; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + sServiceRegistered = wantRegistered; } } -- cgit v1.2.3 From a43e3aeb15a2af130d5e436a20cb5194b3ce9a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Rymanowski?= Date: Mon, 24 May 2021 06:36:13 +0000 Subject: csip: Add Coordinated Set Identification Profile Tag: #feature Test: atest CsipSetCoordinatorStateMachineTest CsipSetCoordinatorServiceTest Bug: 150670922 Sponsor: jpawlowski@ Change-Id: I67536ddcc32ace82d63e19426dce19f2bc69cdea --- framework/java/android/bluetooth/BluetoothAdapter.java | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 2ed26a9f4d..1c96b8bec2 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3062,6 +3062,10 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.VOLUME_CONTROL) { BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this); return true; + } else if (profile == BluetoothProfile.CSIP_SET_COORDINATOR) { + BluetoothCsipSetCoordinator csipSetCoordinator = + new BluetoothCsipSetCoordinator(context, listener, this); + return true; } else { return false; } @@ -3159,6 +3163,11 @@ public final class BluetoothAdapter { BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy; vcs.close(); break; + case BluetoothProfile.CSIP_SET_COORDINATOR: + BluetoothCsipSetCoordinator csipSetCoordinator = + (BluetoothCsipSetCoordinator) proxy; + csipSetCoordinator.close(); + break; } } -- cgit v1.2.3 From d00916c7fe16c0ae0c107b7b343e85085836e27d Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Tue, 28 Sep 2021 16:16:07 -0700 Subject: Add BluetoothDevice#connect and BluetoothDevice#disconnect as System APIs Tag: #feature Bug: 201462141 Test: Manual Change-Id: I79332c63e99efd9e90036ba2c693835151cc1240 --- .../java/android/bluetooth/BluetoothAdapter.java | 65 ---------------------- 1 file changed, 65 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 77abbe96db..e9be0ecd20 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2004,71 +2004,6 @@ public final class BluetoothAdapter { return false; } - /** - * Connects all enabled and supported bluetooth profiles between the local and remote device. - * Connection is asynchronous and you should listen to each profile's broadcast intent - * ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful. For example, - * to verify a2dp is connected, you would listen for - * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} - * - * @param device is the remote device with which to connect these profiles - * @return true if message sent to try to connect all profiles, false if an error occurred - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.connectAllEnabledProfiles(device, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - - return false; - } - - /** - * Disconnects all enabled and supported bluetooth profiles between the local and remote device. - * Disconnection is asynchronous and you should listen to each profile's broadcast intent - * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example, - * to verify a2dp is disconnected, you would listen for - * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} - * - * @param device is the remote device with which to disconnect these profiles - * @return true if message sent to try to disconnect all profiles, false if an error occurred - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.disconnectAllEnabledProfiles(device, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - - return false; - } - /** * Return true if the multi advertisement is supported by the chipset * -- cgit v1.2.3 From fd3e858be2c3686d0b5a5b4ea2e80257fa204c92 Mon Sep 17 00:00:00 2001 From: wescande Date: Wed, 11 Aug 2021 14:56:06 +0200 Subject: Add getActiveDevices api Bug: 195149213 Test: Manual Tag: #feature Change-Id: I0836f7bd0009a49b4db7f08e9f347fe3e1a76f84 --- .../java/android/bluetooth/BluetoothAdapter.java | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e9be0ecd20..1eadf954ba 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -511,6 +511,12 @@ public final class BluetoothAdapter { @SystemApi public static final int ACTIVE_DEVICE_ALL = 2; + /** @hide */ + @IntDef({BluetoothProfile.HEADSET, BluetoothProfile.A2DP, + BluetoothProfile.HEARING_AID}) + @Retention(RetentionPolicy.SOURCE) + public @interface ActiveDeviceProfile {} + /** * Broadcast Action: The local Bluetooth adapter has started the remote * device discovery process. @@ -2004,6 +2010,51 @@ public final class BluetoothAdapter { return false; } + /** + * Get the active devices for the BluetoothProfile specified + * + * @param profile is the profile from which we want the active devices. + * Possible values are: + * {@link BluetoothProfile#HEADSET}, + * {@link BluetoothProfile#A2DP}, + * {@link BluetoothProfile#HEARING_AID} + * @return A list of active bluetooth devices + * @throws IllegalArgumentException If profile is not one of {@link ActiveDeviceProfile} + * @hide + */ + @SystemApi + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public @NonNull List getActiveDevices(@ActiveDeviceProfile int profile) { + if (profile != BluetoothProfile.HEADSET + && profile != BluetoothProfile.A2DP + && profile != BluetoothProfile.HEARING_AID) { + Log.e(TAG, "Invalid profile param value in getActiveDevices"); + throw new IllegalArgumentException("Profiles must be one of " + + "BluetoothProfile.A2DP, " + + "BluetoothProfile.HEARING_AID, or" + + "BluetoothProfile.HEARING_AID"); + } + try { + mServiceLock.readLock().lock(); + if (mService != null) { + if (DBG) { + Log.d(TAG, "getActiveDevices(profile= " + + BluetoothProfile.getProfileName(profile) + ")"); + } + return mService.getActiveDevices(profile, mAttributionSource); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + mServiceLock.readLock().unlock(); + } + + return new ArrayList<>(); + } + /** * Return true if the multi advertisement is supported by the chipset * -- cgit v1.2.3 From f599dc49a2b0e598cfaacefebb4c24cbabf06299 Mon Sep 17 00:00:00 2001 From: Sal Savage Date: Thu, 2 Sep 2021 11:52:23 -0700 Subject: Make BluetoothAdapter#disable(boolean persist) a @SystemApi Bug: 196235708 Test: build, flash car hardware, test basic functionality Change-Id: I952c3d2ce3b7ec70a384e9a96e172d6ab90c23e8 --- framework/java/android/bluetooth/BluetoothAdapter.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index e9be0ecd20..9c69903d59 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -1245,13 +1245,17 @@ public final class BluetoothAdapter { /** * Turn off the local Bluetooth adapter and don't persist the setting. * + * @param persist Indicate whether the off state should be persisted following the next reboot * @return true to indicate adapter shutdown has begun, or false on immediate error * @hide */ - @UnsupportedAppUsage(trackingBug = 171933273) + @SystemApi @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothConnectPermission - @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean disable(boolean persist) { try { -- cgit v1.2.3 From 7e33f238b2fd191a74183b11bf6abf35e7668665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Rymanowski?= Date: Mon, 11 Oct 2021 11:58:12 +0000 Subject: bluetooth: Fix common typo sponsor: jpawlowski@ test: NA Change-Id: I0e93b87371f434c229f211c480727cc26434a5e0 --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 3b744a73e7..06ce0530d4 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2099,7 +2099,7 @@ public final class BluetoothAdapter { try { return mManagerService.isBleScanAlwaysAvailable(); } catch (RemoteException e) { - Log.e(TAG, "remote expection when calling isBleScanAlwaysAvailable", e); + Log.e(TAG, "remote exception when calling isBleScanAlwaysAvailable", e); return false; } } @@ -2307,7 +2307,7 @@ public final class BluetoothAdapter { try { return mManagerService.isHearingAidProfileSupported(); } catch (RemoteException e) { - Log.e(TAG, "remote expection when calling isHearingAidProfileSupported", e); + Log.e(TAG, "remote exception when calling isHearingAidProfileSupported", e); return false; } } -- cgit v1.2.3 From f3fc3166c04cbe693abdef14ef3088550f7c4d37 Mon Sep 17 00:00:00 2001 From: Patty Date: Mon, 18 Oct 2021 19:44:36 +0800 Subject: Expose isCISCentralSupported() and isLePeriodicAdvertisingSyncTransferSenderSupported() API Tag: #feature Bug: 200749925 Bug: 150670922 Test: Compile Change-Id: I45c674dcc8719d209f0e790aa9716bbbf0052fce --- .../java/android/bluetooth/BluetoothAdapter.java | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 06ce0530d4..dac8ffe5e0 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2272,6 +2272,66 @@ public final class BluetoothAdapter { return false; } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + BluetoothStatusCodes.SUCCESS, + BluetoothStatusCodes.ERROR_UNKNOWN, + BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, + BluetoothStatusCodes.ERROR_FEATURE_NOT_SUPPORTED, + }) + public @interface LeFeatureReturnValues {} + + /** + * Returns {@link BluetoothStatusCodes#SUCCESS} if LE Connected Isochronous Stream Central + * feature is supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if + * the feature is not supported or an error code. + * + * @return whether the chipset supports the LE Connected Isochronous Stream Central feature + */ + @RequiresNoPermission + public @LeFeatureReturnValues int isCisCentralSupported() { + if (!getLeAccess()) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.isCisCentralSupported(); + } + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } finally { + mServiceLock.readLock().unlock(); + } + return BluetoothStatusCodes.ERROR_UNKNOWN; + } + + /** + * Returns {@link BluetoothStatusCodes#SUCCESS} if LE Periodic Advertising Sync Transfer Sender + * feature is supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if the + * feature is not supported or an error code + * + * @return whether the chipset supports the LE Periodic Advertising Sync Transfer Sender feature + */ + @RequiresNoPermission + public @LeFeatureReturnValues int isLePeriodicAdvertisingSyncTransferSenderSupported() { + if (!getLeAccess()) { + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.isLePeriodicAdvertisingSyncTransferSenderSupported(); + } + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } finally { + mServiceLock.readLock().unlock(); + } + return BluetoothStatusCodes.ERROR_UNKNOWN; + } + /** * Return the maximum LE advertising data length in bytes, * if LE Extended Advertising feature is supported, 0 otherwise. -- cgit v1.2.3 From 99d1a066c74f1f782948612ff42d6e6dfbf1239c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Rymanowski?= Date: Fri, 12 Nov 2021 11:55:00 +0000 Subject: BluetoothAdapter: Extend getActiveDevice with LeAudio Bug: 150670922 Sponsor: jpawlowski@ Test: NA Change-Id: I82662de5fe7f86b28dee1edff38761cf48343c5a --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index dac8ffe5e0..cf00cbd584 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2022,6 +2022,7 @@ public final class BluetoothAdapter { * {@link BluetoothProfile#HEADSET}, * {@link BluetoothProfile#A2DP}, * {@link BluetoothProfile#HEARING_AID} + * {@link BluetoothProfile#LE_AUDIO} * @return A list of active bluetooth devices * @throws IllegalArgumentException If profile is not one of {@link ActiveDeviceProfile} * @hide @@ -2034,12 +2035,14 @@ public final class BluetoothAdapter { public @NonNull List getActiveDevices(@ActiveDeviceProfile int profile) { if (profile != BluetoothProfile.HEADSET && profile != BluetoothProfile.A2DP - && profile != BluetoothProfile.HEARING_AID) { + && profile != BluetoothProfile.HEARING_AID + && profile != BluetoothProfile.LE_AUDIO) { Log.e(TAG, "Invalid profile param value in getActiveDevices"); throw new IllegalArgumentException("Profiles must be one of " + "BluetoothProfile.A2DP, " + "BluetoothProfile.HEARING_AID, or" - + "BluetoothProfile.HEARING_AID"); + + "BluetoothProfile.HEARING_AID" + + "BluetoothProfile.LE_AUDIO"); } try { mServiceLock.readLock().lock(); -- cgit v1.2.3 From 647179ea4ea64a1401a9304b4afa3c07659a2daf Mon Sep 17 00:00:00 2001 From: William Escande Date: Thu, 18 Nov 2021 15:56:58 +0100 Subject: BT_MAINLINE Delete getControllerActivityEnergyInfo This hidden api is deprecated since 2016. Removing it because it's not used and it's calling 3 hidden apis Bug: 200200870 Tag: #refactor Test: Build Change-Id: Ib84e069dc663def3d6a2d6f64717d76d39b59fb9 --- .../java/android/bluetooth/BluetoothAdapter.java | 35 ---------------------- 1 file changed, 35 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index cf00cbd584..2c875fee10 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -51,7 +51,6 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; -import android.os.BatteryStats; import android.os.Binder; import android.os.Build; import android.os.IBinder; @@ -59,7 +58,6 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; -import android.os.SynchronousResultReceiver; import android.os.SystemProperties; import android.util.Log; import android.util.Pair; @@ -82,7 +80,6 @@ import java.util.Set; import java.util.UUID; import java.util.WeakHashMap; import java.util.concurrent.Executor; -import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.ReentrantReadWriteLock; /** @@ -2423,38 +2420,6 @@ public final class BluetoothAdapter { return false; } - /** - * Return the record of {@link BluetoothActivityEnergyInfo} object that - * has the activity and energy info. This can be used to ascertain what - * the controller has been up to, since the last sample. - * - * @param updateType Type of info, cached vs refreshed. - * @return a record with {@link BluetoothActivityEnergyInfo} or null if report is unavailable or - * unsupported - * @hide - * @deprecated use the asynchronous {@link #requestControllerActivityEnergyInfo(ResultReceiver)} - * instead. - */ - @Deprecated - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { - SynchronousResultReceiver receiver = new SynchronousResultReceiver(); - requestControllerActivityEnergyInfo(receiver); - try { - SynchronousResultReceiver.Result result = receiver.awaitResult(1000); - if (result.bundle != null) { - return result.bundle.getParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY); - } - } catch (TimeoutException e) { - Log.e(TAG, "getControllerActivityEnergyInfo timed out"); - } - return null; - } - /** * Request the record of {@link BluetoothActivityEnergyInfo} object that * has the activity and energy info. This can be used to ascertain what -- cgit v1.2.3 From 59ffe8a6a7e37a29a7020f743fac97ad85b026e2 Mon Sep 17 00:00:00 2001 From: Patty Date: Tue, 30 Nov 2021 19:56:07 +0800 Subject: Change isCISCentralSupported() to isLeAudioSupported() API Tag: #feature Bug: 200749925 Bug: 150670922 Test: atest BasicAdapterTest Change-Id: Ie606f45e148f6d9026495279d718a3cc1523c36f --- framework/java/android/bluetooth/BluetoothAdapter.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index cf00cbd584..6154b7149a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -2286,21 +2286,21 @@ public final class BluetoothAdapter { public @interface LeFeatureReturnValues {} /** - * Returns {@link BluetoothStatusCodes#SUCCESS} if LE Connected Isochronous Stream Central - * feature is supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if + * Returns {@link BluetoothStatusCodes#SUCCESS} if the LE audio feature is + * supported, returns {@link BluetoothStatusCodes#ERROR_FEATURE_NOT_SUPPORTED} if * the feature is not supported or an error code. * - * @return whether the chipset supports the LE Connected Isochronous Stream Central feature + * @return whether the LE audio is supported */ @RequiresNoPermission - public @LeFeatureReturnValues int isCisCentralSupported() { + public @LeFeatureReturnValues int isLeAudioSupported() { if (!getLeAccess()) { return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.isCisCentralSupported(); + return mService.isLeAudioSupported(); } } catch (RemoteException e) { e.rethrowFromSystemServer(); -- cgit v1.2.3 From 375c93f52c0230fba3594c2427874566b0c4c7ed Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Mon, 13 Dec 2021 14:32:46 -0800 Subject: Remove unused references to android.app.ActivityThread in BluetoothAdapter Tag: #feature Bug: 210468546 Test: Manual Change-Id: Ia473afe6bcf4d0824e2fd2c6ca2ce562d0ecbde3 --- framework/java/android/bluetooth/BluetoothAdapter.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 14be9215c7..6a81c4043a 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -29,7 +29,6 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.app.ActivityThread; import android.app.PropertyInvalidatedCache; import android.bluetooth.BluetoothDevice.Transport; import android.bluetooth.BluetoothProfile.ConnectionPolicy; @@ -991,7 +990,6 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) { return false; } - String packageName = ActivityThread.currentPackageName(); try { return mManagerService.disableBle(mAttributionSource, mToken); } catch (RemoteException e) { @@ -1038,7 +1036,6 @@ public final class BluetoothAdapter { if (!isBleScanAlwaysAvailable()) { return false; } - String packageName = ActivityThread.currentPackageName(); try { return mManagerService.enableBle(mAttributionSource, mToken); } catch (RemoteException e) { -- cgit v1.2.3 From d517127a57b499305f82ec6eea6da8e0bd485e87 Mon Sep 17 00:00:00 2001 From: William Escande Date: Tue, 14 Dec 2021 16:16:11 +0100 Subject: Copy attributable to Bluetooth Attributable is called by bluetooth and it's hidden. By copying into bluetooth we are now allowed to call it Bug: 210467788 Test: build Tag: #refactor Change-Id: I73ea07c9439988ab5477c82799f718c6d81513be --- framework/java/android/bluetooth/BluetoothAdapter.java | 1 - 1 file changed, 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 14be9215c7..362a89d869 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -48,7 +48,6 @@ import android.bluetooth.le.ScanRecord; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.compat.annotation.UnsupportedAppUsage; -import android.content.Attributable; import android.content.AttributionSource; import android.content.Context; import android.os.Binder; -- cgit v1.2.3 From cc2d01f2367b0cf54fc2d9686b065156797ce8d9 Mon Sep 17 00:00:00 2001 From: Etienne Ruffieux Date: Wed, 15 Dec 2021 13:04:11 +0000 Subject: Replaced Bluetooth SystemProperties.set by sysprop Tag: #feature Bug: 197210455 Test: set/get sysprop with SystemProperties Merged-In: I613808dbc930c90e391df9857a173a86aedc4acf Change-Id: I613808dbc930c90e391df9857a173a86aedc4acf --- framework/java/android/bluetooth/BluetoothAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 14be9215c7..cc3f747fa8 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -58,7 +58,7 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; -import android.os.SystemProperties; +import android.sysprop.BluetoothProperties; import android.util.Log; import android.util.Pair; @@ -1341,7 +1341,7 @@ public final class BluetoothAdapter { return true; } Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later"); - SystemProperties.set("persist.bluetooth.factoryreset", "true"); + BluetoothProperties.factory_reset(true); } catch (RemoteException e) { Log.e(TAG, "", e); } finally { -- cgit v1.2.3 From 9cc5b0f8b0f0acd4a55b48378fa77c0f1fea5798 Mon Sep 17 00:00:00 2001 From: Etienne Ruffieux Date: Tue, 14 Dec 2021 18:39:55 +0000 Subject: Moved AttributionSource related APIs in AttributionSource Modified myAttributionSource() to check for global AS for process in ActivityThread and fallback to building new AS with PackageManager#getPackageForUid(myUid()) if null. Tag: #feature Bug: 210467846 Bug: 210468546 Test: build Change-Id: I7aa75395469bf0bb806100420faaf98c52057355 CTS-Coverage-Bug: 210906055 --- framework/java/android/bluetooth/BluetoothAdapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 14be9215c7..9160edea87 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -788,7 +788,7 @@ public final class BluetoothAdapter { @RequiresNoPermission public static synchronized BluetoothAdapter getDefaultAdapter() { if (sAdapter == null) { - sAdapter = createAdapter(BluetoothManager.resolveAttributionSource(null)); + sAdapter = createAdapter(AttributionSource.myAttributionSource()); } return sAdapter; } -- cgit v1.2.3 From fbbb005a03fa7fb0fda87afd7d6015d44cae7a3c Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 17 Nov 2020 09:11:17 +0000 Subject: gtbs: Add Generic Telephone Bearer Service support Tag: #feature Bug: 159786353 Sponsor: jpawlowski@ Test: build Change-Id: I8264ade4b07df17fc0207437dfdcae7028cc20ff --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index b23c3eb0ce..991da1da1d 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3086,6 +3086,9 @@ public final class BluetoothAdapter { BluetoothCsipSetCoordinator csipSetCoordinator = new BluetoothCsipSetCoordinator(context, listener, this); return true; + } else if (profile == BluetoothProfile.LE_CALL_CONTROL) { + BluetoothLeCallControl tbs = new BluetoothLeCallControl(context, listener); + return true; } else { return false; } @@ -3188,6 +3191,10 @@ public final class BluetoothAdapter { (BluetoothCsipSetCoordinator) proxy; csipSetCoordinator.close(); break; + case BluetoothProfile.LE_CALL_CONTROL: + BluetoothLeCallControl tbs = (BluetoothLeCallControl) proxy; + tbs.close(); + break; } } -- cgit v1.2.3 From 6bf87965a2b4220de686a0526f83ff010f1e252f Mon Sep 17 00:00:00 2001 From: Jack He Date: Fri, 7 Jan 2022 00:09:07 +0000 Subject: Revert "gtbs: Add Generic Telephone Bearer Service support" Revert "gtbs: Add Generic Telephone Bearer Service implementation" Revert submission 1873900-gtbs Reason for revert: broke cellular call over BT, see b/213412267 Reverted Changes: I284ddacfc:gtbs: Add Generic Telephone Bearer Service impleme... I8264ade4b:gtbs: Add Generic Telephone Bearer Service support... I996cd5ff9:Add support for Generic Telephone Bearer service (... Bug: 213412267 Tag: #feature Test: answer cellular call by pressing button on HFP headset Change-Id: I9c6b12b794b7378fd852238ad06890f46922c095 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 ------- 1 file changed, 7 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 991da1da1d..b23c3eb0ce 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3086,9 +3086,6 @@ public final class BluetoothAdapter { BluetoothCsipSetCoordinator csipSetCoordinator = new BluetoothCsipSetCoordinator(context, listener, this); return true; - } else if (profile == BluetoothProfile.LE_CALL_CONTROL) { - BluetoothLeCallControl tbs = new BluetoothLeCallControl(context, listener); - return true; } else { return false; } @@ -3191,10 +3188,6 @@ public final class BluetoothAdapter { (BluetoothCsipSetCoordinator) proxy; csipSetCoordinator.close(); break; - case BluetoothProfile.LE_CALL_CONTROL: - BluetoothLeCallControl tbs = (BluetoothLeCallControl) proxy; - tbs.close(); - break; } } -- cgit v1.2.3 From 90bd65132b36a8d9225b5645e14d1f54083fa108 Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Tue, 17 Nov 2020 09:11:17 +0000 Subject: gtbs: Add Generic Telephone Bearer Service support Tag: #feature Bug: 159786353 Bug: 213412267 Sponsor: jpawlowski@ Test: build Change-Id: Iecd56b91ce59f6b014878691fe4c6fae826b73f9 --- framework/java/android/bluetooth/BluetoothAdapter.java | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index 9b37457c99..c6c64b034b 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -3086,6 +3086,9 @@ public final class BluetoothAdapter { BluetoothCsipSetCoordinator csipSetCoordinator = new BluetoothCsipSetCoordinator(context, listener, this); return true; + } else if (profile == BluetoothProfile.LE_CALL_CONTROL) { + BluetoothLeCallControl tbs = new BluetoothLeCallControl(context, listener); + return true; } else { return false; } @@ -3188,6 +3191,10 @@ public final class BluetoothAdapter { (BluetoothCsipSetCoordinator) proxy; csipSetCoordinator.close(); break; + case BluetoothProfile.LE_CALL_CONTROL: + BluetoothLeCallControl tbs = (BluetoothLeCallControl) proxy; + tbs.close(); + break; } } -- cgit v1.2.3 From 56e00da8e76a12e0a6c99fdc92d7621513ec9ee4 Mon Sep 17 00:00:00 2001 From: Rahul Sabnis Date: Wed, 12 Jan 2022 14:06:51 -0800 Subject: Temporarily comment out usages of PropertyInvalidatedCache in Bluetooth code while it is pending migration to module-utils Tag: #feature Bug: 210468958 Test: Manual Change-Id: Iab59d235ca59fe2b5863fb4714eaccbc64fa915c --- .../java/android/bluetooth/BluetoothAdapter.java | 88 ++++++++++++++++------ 1 file changed, 63 insertions(+), 25 deletions(-) (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java') diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java index c6c64b034b..f94ee8579e 100644 --- a/framework/java/android/bluetooth/BluetoothAdapter.java +++ b/framework/java/android/bluetooth/BluetoothAdapter.java @@ -28,8 +28,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.app.PropertyInvalidatedCache; +import android.annotation.SystemApi; //import android.app.PropertyInvalidatedCache; import android.bluetooth.BluetoothDevice.Transport; import android.bluetooth.BluetoothProfile.ConnectionPolicy; import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission; @@ -676,14 +675,15 @@ public final class BluetoothAdapter { "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED"; /** The profile is in disconnected state */ - public static final int STATE_DISCONNECTED = BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED; + public static final int STATE_DISCONNECTED = + 0; //BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED; /** The profile is in connecting state */ - public static final int STATE_CONNECTING = BluetoothProtoEnums.CONNECTION_STATE_CONNECTING; + public static final int STATE_CONNECTING = 1; //BluetoothProtoEnums.CONNECTION_STATE_CONNECTING; /** The profile is in connected state */ - public static final int STATE_CONNECTED = BluetoothProtoEnums.CONNECTION_STATE_CONNECTED; + public static final int STATE_CONNECTED = 2; //BluetoothProtoEnums.CONNECTION_STATE_CONNECTED; /** The profile is in disconnecting state */ public static final int STATE_DISCONNECTING = - BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING; + 3; //BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING; /** @hide */ public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; @@ -1044,6 +1044,7 @@ public final class BluetoothAdapter { return false; } + /* private static final String BLUETOOTH_GET_STATE_CACHE_PROPERTY = "cache_key.bluetooth.get_state"; private final PropertyInvalidatedCache mBluetoothGetStateCache = @@ -1059,17 +1060,22 @@ public final class BluetoothAdapter { } } }; + */ /** @hide */ + /* @RequiresNoPermission public void disableBluetoothGetStateCache() { mBluetoothGetStateCache.disableLocal(); } + */ /** @hide */ + /* public static void invalidateBluetoothGetStateCache() { PropertyInvalidatedCache.invalidateCache(BLUETOOTH_GET_STATE_CACHE_PROPERTY); } + */ /** * Fetch the current bluetooth state. If the service is down, return @@ -1081,14 +1087,12 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - state = mBluetoothGetStateCache.query(null); - } - } catch (RuntimeException e) { - if (e.getCause() instanceof RemoteException) { - Log.e(TAG, "", e.getCause()); - } else { - throw e; + //state = mBluetoothGetStateCache.query(null); + state = mService.getState(); } + } catch (RemoteException e) { + Log.e(TAG, "", e); + e.rethrowFromSystemServer(); } finally { mServiceLock.readLock().unlock(); } @@ -2100,6 +2104,7 @@ public final class BluetoothAdapter { } } + /* private static final String BLUETOOTH_FILTERING_CACHE_PROPERTY = "cache_key.bluetooth.is_offloaded_filtering_supported"; private final PropertyInvalidatedCache mBluetoothFilteringCache = @@ -2122,17 +2127,22 @@ public final class BluetoothAdapter { } }; + */ /** @hide */ + /* @RequiresNoPermission public void disableIsOffloadedFilteringSupportedCache() { mBluetoothFilteringCache.disableLocal(); } + */ /** @hide */ + /* public static void invalidateIsOffloadedFilteringSupportedCache() { PropertyInvalidatedCache.invalidateCache(BLUETOOTH_FILTERING_CACHE_PROPERTY); } + */ /** * Return true if offloaded filters are supported @@ -2145,7 +2155,18 @@ public final class BluetoothAdapter { if (!getLeAccess()) { return false; } - return mBluetoothFilteringCache.query(null); + //return mBluetoothFilteringCache.query(null); + try { + mServiceLock.readLock().lock(); + if (mService != null) { + return mService.isOffloadedFilteringSupported(); + } + } catch (RemoteException e) { + Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); + } finally { + mServiceLock.readLock().unlock(); + } + return false; } /** @@ -2551,15 +2572,13 @@ public final class BluetoothAdapter { return supportedProfiles; } + /* private static final String BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY = "cache_key.bluetooth.get_adapter_connection_state"; private final PropertyInvalidatedCache mBluetoothGetAdapterConnectionStateCache = new PropertyInvalidatedCache ( 8, BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY) { - /** - * This method must not be called when mService is null. - */ @Override @SuppressLint("AndroidFrameworkRequiresPermission") protected Integer recompute(Void query) { @@ -2570,18 +2589,23 @@ public final class BluetoothAdapter { } } }; + */ /** @hide */ + /* @RequiresNoPermission public void disableGetAdapterConnectionStateCache() { mBluetoothGetAdapterConnectionStateCache.disableLocal(); } + */ /** @hide */ + /* public static void invalidateGetAdapterConnectionStateCache() { PropertyInvalidatedCache.invalidateCache( BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY); } + */ /** * Get the current connection state of the local Bluetooth adapter. @@ -2605,20 +2629,18 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mBluetoothGetAdapterConnectionStateCache.query(null); - } - } catch (RuntimeException e) { - if (e.getCause() instanceof RemoteException) { - Log.e(TAG, "getConnectionState:", e.getCause()); - } else { - throw e; + return mService.getAdapterConnectionState(); } + //return mBluetoothGetAdapterConnectionStateCache.query(null); + } catch (RemoteException e) { + Log.e(TAG, "failed to getConnectionState, error: ", e); } finally { mServiceLock.readLock().unlock(); } return BluetoothAdapter.STATE_DISCONNECTED; } + /* private static final String BLUETOOTH_PROFILE_CACHE_PROPERTY = "cache_key.bluetooth.get_profile_connection_state"; private final PropertyInvalidatedCache @@ -2646,17 +2668,22 @@ public final class BluetoothAdapter { query); } }; + */ /** @hide */ + /* @RequiresNoPermission public void disableGetProfileConnectionStateCache() { mGetProfileConnectionStateCache.disableLocal(); } + */ /** @hide */ + /* public static void invalidateGetProfileConnectionStateCache() { PropertyInvalidatedCache.invalidateCache(BLUETOOTH_PROFILE_CACHE_PROPERTY); } + */ /** * Get the current connection state of a profile. @@ -2678,7 +2705,18 @@ public final class BluetoothAdapter { if (getState() != STATE_ON) { return BluetoothProfile.STATE_DISCONNECTED; } - return mGetProfileConnectionStateCache.query(new Integer(profile)); + try { + mServiceLock.readLock().lock(); + if (mService != null) { + mService.getProfileConnectionState(profile); + } + //return mGetProfileConnectionStateCache.query(new Integer(profile)); + } catch (RemoteException e) { + Log.e(TAG, "failed to getProfileConnectionState, error: ", e); + } finally { + mServiceLock.readLock().unlock(); + } + return BluetoothProfile.STATE_DISCONNECTED; } /** -- cgit v1.2.3