aboutsummaryrefslogtreecommitdiff
path: root/framework/java/android/bluetooth/BluetoothAdapter.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothAdapter.java')
-rw-r--r--framework/java/android/bluetooth/BluetoothAdapter.java969
1 files changed, 605 insertions, 364 deletions
diff --git a/framework/java/android/bluetooth/BluetoothAdapter.java b/framework/java/android/bluetooth/BluetoothAdapter.java
index d487025631..2ed26a9f4d 100644
--- a/framework/java/android/bluetooth/BluetoothAdapter.java
+++ b/framework/java/android/bluetooth/BluetoothAdapter.java
@@ -19,19 +19,26 @@ package android.bluetooth;
import static java.util.Objects.requireNonNull;
-import android.Manifest;
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;
+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.RequiresBluetoothAdvertisePermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
+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;
@@ -41,6 +48,8 @@ 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;
import android.os.Binder;
@@ -66,6 +75,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;
@@ -96,11 +106,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
* Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
* </p>
* <p>This class is thread safe.</p>
- * <p class="note"><strong>Note:</strong>
- * Most methods require the {@link android.Manifest.permission#BLUETOOTH}
- * permission and some also require the
- * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- * </p>
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>
@@ -115,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;
@@ -142,8 +148,8 @@ public final class BluetoothAdapter {
* <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link
* #EXTRA_PREVIOUS_STATE} containing the new and old states
* respectively.
- * <p>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";
@@ -276,8 +282,10 @@ public final class BluetoothAdapter {
* <p>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.
- * <p>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";
@@ -303,8 +311,10 @@ public final class BluetoothAdapter {
* has rejected the request or an error has occurred.
* <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
* for global notification whenever Bluetooth is turned on or off.
- * <p>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";
@@ -323,10 +333,12 @@ public final class BluetoothAdapter {
* has rejected the request or an error has occurred.
* <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
* for global notification whenever Bluetooth is turned on or off.
- * <p>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";
@@ -353,8 +365,10 @@ public final class BluetoothAdapter {
* <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
* #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
* respectively.
- * <p>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";
@@ -506,15 +520,19 @@ public final class BluetoothAdapter {
* progress, and existing connections will experience limited bandwidth
* and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
* discovery.
- * <p>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.
- * <p>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";
@@ -524,8 +542,10 @@ public final class BluetoothAdapter {
* <p>This name is visible to remote Bluetooth devices.
* <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing
* the name.
- * <p>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";
/**
@@ -557,9 +577,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}.
- *
- * <p>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";
@@ -585,6 +606,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";
@@ -599,6 +621,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";
@@ -623,6 +648,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";
@@ -637,6 +665,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";
@@ -677,20 +708,21 @@ 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 Context mContext;
private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
private final Object mLock = new Object();
private final Map<LeScanCallback, ScanCallback> mLeScanClients;
- private static final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
- sMetadataListeners = new HashMap<>();
+ private final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
+ mMetadataListeners = new HashMap<>();
private final Map<BluetoothConnectionCallback, Executor>
mBluetoothConnectionCallbackExecutorMap = new HashMap<>();
@@ -698,14 +730,16 @@ public final class BluetoothAdapter {
* Bluetooth metadata listener. Overrides the default BluetoothMetadataListener
* implementation.
*/
- private static final IBluetoothMetadataListener sBluetoothMetadataListener =
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
+ 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<Pair<OnMetadataChangedListener, Executor>> list =
- sMetadataListeners.get(device);
+ mMetadataListeners.get(device);
for (Pair<OnMetadataChangedListener, Executor> pair : list) {
OnMetadataChangedListener listener = pair.first;
Executor executor = pair.second;
@@ -721,32 +755,43 @@ public final class BluetoothAdapter {
/**
* Get a handle to the default local Bluetooth adapter.
- * <p>Currently Android only supports one Bluetooth adapter, but the API
- * could be extended to support more. This will always return the default
- * adapter.
+ * <p>
+ * Currently Android only supports one Bluetooth adapter, but the API could
+ * be extended to support more. This will always return the default adapter.
* </p>
*
- * @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) {
- 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(BluetoothManager.resolveAttributionSource(null));
}
return sAdapter;
}
+ /** {@hide} */
+ public static BluetoothAdapter createAdapter(AttributionSource attributionSource) {
+ IBinder binder = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
+ if (binder != null) {
+ return new BluetoothAdapter(IBluetoothManager.Stub.asInterface(binder),
+ attributionSource);
+ } else {
+ Log.e(TAG, "Bluetooth binder is null");
+ return null;
+ }
+ }
+
/**
* 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");
}
@@ -758,9 +803,10 @@ public final class BluetoothAdapter {
} finally {
mServiceLock.writeLock().unlock();
}
- mManagerService = managerService;
+ mManagerService = Objects.requireNonNull(managerService);
+ mAttributionSource = Objects.requireNonNull(attributionSource);
mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
- mToken = new Binder();
+ mToken = new Binder(DESCRIPTOR);
}
/**
@@ -775,8 +821,11 @@ 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);
+ final BluetoothDevice res = new BluetoothDevice(address);
+ res.setAttributionSource(mAttributionSource);
+ return res;
}
/**
@@ -790,13 +839,16 @@ 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");
}
- 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]));
+ res.setAttributionSource(mAttributionSource);
+ return res;
}
/**
@@ -807,16 +859,17 @@ 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;
}
synchronized (mLock) {
- if (sBluetoothLeAdvertiser == null) {
- sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService);
+ if (mBluetoothLeAdvertiser == null) {
+ mBluetoothLeAdvertiser = new BluetoothLeAdvertiser(this);
}
+ return mBluetoothLeAdvertiser;
}
- return sBluetoothLeAdvertiser;
}
/**
@@ -829,6 +882,7 @@ public final class BluetoothAdapter {
*
* @hide
*/
+ @RequiresNoPermission
public PeriodicAdvertisingManager getPeriodicAdvertisingManager() {
if (!getLeAccess()) {
return null;
@@ -839,27 +893,27 @@ public final class BluetoothAdapter {
}
synchronized (mLock) {
- if (sPeriodicAdvertisingManager == null) {
- sPeriodicAdvertisingManager = new PeriodicAdvertisingManager(mManagerService);
+ if (mPeriodicAdvertisingManager == null) {
+ mPeriodicAdvertisingManager = new PeriodicAdvertisingManager(this);
}
+ return mPeriodicAdvertisingManager;
}
- return sPeriodicAdvertisingManager;
}
/**
* Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
*/
+ @RequiresNoPermission
public BluetoothLeScanner getBluetoothLeScanner() {
if (!getLeAccess()) {
return null;
}
synchronized (mLock) {
- if (sBluetoothLeScanner == null) {
- sBluetoothLeScanner = new BluetoothLeScanner(mManagerService, getOpPackageName(),
- getAttributionTag());
+ if (mBluetoothLeScanner == null) {
+ mBluetoothLeScanner = new BluetoothLeScanner(this);
}
+ return mBluetoothLeScanner;
}
- return sBluetoothLeScanner;
}
/**
@@ -869,7 +923,8 @@ public final class BluetoothAdapter {
*
* @return true if the local adapter is turned on
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isEnabled() {
return getState() == BluetoothAdapter.STATE_ON;
}
@@ -883,6 +938,7 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
+ @RequiresNoPermission
public boolean isLeEnabled() {
final int state = getLeState();
if (DBG) {
@@ -920,13 +976,15 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disableBLE() {
if (!isBleScanAlwaysAvailable()) {
return false;
}
String packageName = ActivityThread.currentPackageName();
try {
- return mManagerService.disableBle(packageName, mToken);
+ return mManagerService.disableBle(mAttributionSource, mToken);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -965,13 +1023,15 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean enableBLE() {
if (!isBleScanAlwaysAvailable()) {
return false;
}
String packageName = ActivityThread.currentPackageName();
try {
- return mManagerService.enableBle(packageName, mToken);
+ return mManagerService.enableBle(mAttributionSource, mToken);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -985,6 +1045,7 @@ public final class BluetoothAdapter {
new PropertyInvalidatedCache<Void, Integer>(
8, BLUETOOTH_GET_STATE_CACHE_PROPERTY) {
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
protected Integer recompute(Void query) {
try {
return mService.getState();
@@ -995,6 +1056,7 @@ public final class BluetoothAdapter {
};
/** @hide */
+ @RequiresNoPermission
public void disableBluetoothGetStateCache() {
mBluetoothGetStateCache.disableLocal();
}
@@ -1038,7 +1100,8 @@ public final class BluetoothAdapter {
*
* @return current state of Bluetooth adapter
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
@AdapterState
public int getState() {
int state = getStateInternal();
@@ -1074,7 +1137,8 @@ public final class BluetoothAdapter {
* @return current state of Bluetooth adapter
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
@AdapterState
@UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine "
+ "whether you can use BLE & BT classic.")
@@ -1121,7 +1185,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) {
@@ -1130,7 +1196,7 @@ public final class BluetoothAdapter {
return true;
}
try {
- return mManagerService.enable(ActivityThread.currentPackageName());
+ return mManagerService.enable(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1158,10 +1224,12 @@ 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);
+ return mManagerService.disable(mAttributionSource, true);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1171,17 +1239,17 @@ public final class BluetoothAdapter {
/**
* Turn off the local Bluetooth adapter and don't persist the setting.
*
- * <p>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 {
- return mManagerService.disable(ActivityThread.currentPackageName(), persist);
+ return mManagerService.disable(mAttributionSource, persist);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1194,10 +1262,15 @@ 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();
+ return mManagerService.getAddress(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1207,19 +1280,33 @@ public final class BluetoothAdapter {
/**
* Get the friendly Bluetooth name of the local Bluetooth adapter.
* <p>This name is visible to remote Bluetooth devices.
- * <p>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();
+ return mManagerService.getName(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
return null;
}
+ /** {@hide} */
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
+ public int getNameLengthForAdvertise() {
+ try {
+ return mService.getNameLengthForAdvertise(mAttributionSource);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ return -1;
+ }
+
/**
* Factory reset bluetooth settings.
*
@@ -1227,12 +1314,17 @@ public final class BluetoothAdapter {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(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()
- && mManagerService != null && mManagerService.onFactoryReset()) {
+ if (mService != null && mService.factoryReset(mAttributionSource)
+ && mManagerService != null
+ && mManagerService.onFactoryReset(mAttributionSource)) {
return true;
}
Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later");
@@ -1252,7 +1344,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;
@@ -1260,7 +1354,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.getUuids();
+ return mService.getUuids(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1284,7 +1378,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;
@@ -1292,7 +1388,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.setName(name);
+ return mService.setName(name, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1310,7 +1406,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;
@@ -1318,7 +1416,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.getBluetoothClass();
+ return mService.getBluetoothClass(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1339,7 +1437,11 @@ public final class BluetoothAdapter {
*
* @hide
*/
- @RequiresPermission(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;
@@ -1347,7 +1449,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);
@@ -1366,13 +1468,15 @@ 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;
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getIoCapability();
+ if (mService != null) return mService.getIoCapability(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.getMessage(), e);
} finally {
@@ -1394,12 +1498,16 @@ public final class BluetoothAdapter {
*
* @hide
*/
- @RequiresPermission(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 {
@@ -1417,13 +1525,15 @@ 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;
try {
mServiceLock.readLock().lock();
- if (mService != null) return mService.getLeIoCapability();
+ if (mService != null) return mService.getLeIoCapability(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, e.getMessage(), e);
} finally {
@@ -1445,12 +1555,16 @@ public final class BluetoothAdapter {
*
* @hide
*/
- @RequiresPermission(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 {
@@ -1474,7 +1588,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) {
@@ -1483,7 +1599,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.getScanMode();
+ return mService.getScanMode(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1521,7 +1637,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;
@@ -1530,7 +1648,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, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1570,7 +1688,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;
@@ -1578,7 +1698,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.setScanMode(mode, getDiscoverableTimeout());
+ return mService.setScanMode(mode, getDiscoverableTimeout(), mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1590,6 +1710,8 @@ public final class BluetoothAdapter {
/** @hide */
@UnsupportedAppUsage
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public int getDiscoverableTimeout() {
if (getState() != STATE_ON) {
return -1;
@@ -1597,7 +1719,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.getDiscoverableTimeout();
+ return mService.getDiscoverableTimeout(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1609,6 +1731,8 @@ public final class BluetoothAdapter {
/** @hide */
@UnsupportedAppUsage
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void setDiscoverableTimeout(int timeout) {
if (getState() != STATE_ON) {
return;
@@ -1616,7 +1740,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
- mService.setDiscoverableTimeout(timeout);
+ mService.setDiscoverableTimeout(timeout, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1634,12 +1758,16 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
- @RequiresPermission(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);
@@ -1650,32 +1778,6 @@ public final class BluetoothAdapter {
}
/**
- * 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();
- }
-
- private String getAttributionTag() {
- // Workaround for legacy API for getting a BluetoothAdapter not
- // passing a context
- if (mContext != null) {
- return mContext.getAttributionTag();
- }
- return null;
- }
-
- /**
* Start the remote device discovery process.
* <p>The discovery process usually involves an inquiry scan of about 12
* seconds, followed by a page scan of each new device to retrieve its
@@ -1705,7 +1807,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;
@@ -1713,7 +1818,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.startDiscovery(getOpPackageName(), getAttributionTag());
+ return mService.startDiscovery(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1739,7 +1844,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;
@@ -1747,7 +1854,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.cancelDiscovery();
+ return mService.cancelDiscovery(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1775,7 +1882,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;
@@ -1783,7 +1892,7 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.isDiscovering();
+ return mService.isDiscovering(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1807,7 +1916,12 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @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) {
@@ -1821,7 +1935,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);
@@ -1847,7 +1961,12 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresBluetoothConnectPermission
+ @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) {
@@ -1868,7 +1987,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);
@@ -1891,12 +2010,17 @@ public final class BluetoothAdapter {
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @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);
+ return mService.connectAllEnabledProfiles(device, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1919,12 +2043,16 @@ public final class BluetoothAdapter {
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @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);
+ return mService.disconnectAllEnabledProfiles(device, mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1940,6 +2068,8 @@ public final class BluetoothAdapter {
*
* @return true if Multiple Advertisement feature is supported
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isMultipleAdvertisementSupported() {
if (getState() != STATE_ON) {
return false;
@@ -1968,6 +2098,7 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
+ @RequiresNoPermission
public boolean isBleScanAlwaysAvailable() {
try {
return mManagerService.isBleScanAlwaysAvailable();
@@ -1983,6 +2114,7 @@ public final class BluetoothAdapter {
new PropertyInvalidatedCache<Void, Boolean>(
8, BLUETOOTH_FILTERING_CACHE_PROPERTY) {
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
protected Boolean recompute(Void query) {
try {
mServiceLock.readLock().lock();
@@ -2000,6 +2132,7 @@ public final class BluetoothAdapter {
};
/** @hide */
+ @RequiresNoPermission
public void disableIsOffloadedFilteringSupportedCache() {
mBluetoothFilteringCache.disableLocal();
}
@@ -2014,6 +2147,8 @@ public final class BluetoothAdapter {
*
* @return true if chipset supports on-chip filtering
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isOffloadedFilteringSupported() {
if (!getLeAccess()) {
return false;
@@ -2026,6 +2161,8 @@ public final class BluetoothAdapter {
*
* @return true if chipset supports on-chip scan batching
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isOffloadedScanBatchingSupported() {
if (!getLeAccess()) {
return false;
@@ -2048,6 +2185,8 @@ public final class BluetoothAdapter {
*
* @return true if chipset supports LE 2M PHY feature
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isLe2MPhySupported() {
if (!getLeAccess()) {
return false;
@@ -2070,6 +2209,8 @@ public final class BluetoothAdapter {
*
* @return true if chipset supports LE Coded PHY feature
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isLeCodedPhySupported() {
if (!getLeAccess()) {
return false;
@@ -2092,6 +2233,8 @@ public final class BluetoothAdapter {
*
* @return true if chipset supports LE Extended Advertising feature
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isLeExtendedAdvertisingSupported() {
if (!getLeAccess()) {
return false;
@@ -2114,6 +2257,8 @@ public final class BluetoothAdapter {
*
* @return true if chipset supports LE Periodic Advertising feature
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public boolean isLePeriodicAdvertisingSupported() {
if (!getLeAccess()) {
return false;
@@ -2137,6 +2282,8 @@ public final class BluetoothAdapter {
*
* @return the maximum LE advertising data length.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public int getLeMaximumAdvertisingDataLength() {
if (!getLeAccess()) {
return 0;
@@ -2159,6 +2306,7 @@ public final class BluetoothAdapter {
*
* @return true if phone supports Hearing Aid Profile
*/
+ @RequiresNoPermission
private boolean isHearingAidProfileSupported() {
try {
return mManagerService.isHearingAidProfileSupported();
@@ -2174,12 +2322,14 @@ 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();
if (mService != null) {
- return mService.getMaxConnectedAudioDevices();
+ return mService.getMaxConnectedAudioDevices(mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "failed to get getMaxConnectedAudioDevices, error: ", e);
@@ -2195,6 +2345,8 @@ 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()) {
return false;
@@ -2205,7 +2357,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);
}
@@ -2225,6 +2377,11 @@ public final class BluetoothAdapter {
* 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);
@@ -2250,11 +2407,16 @@ public final class BluetoothAdapter {
* @param result The callback to which to send the activity info.
* @hide
*/
+ @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) {
@@ -2277,7 +2439,9 @@ public final class BluetoothAdapter {
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getMostRecentlyConnectedDevices() {
if (getState() != STATE_ON) {
return new ArrayList<>();
@@ -2285,7 +2449,9 @@ public final class BluetoothAdapter {
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.getMostRecentlyConnectedDevices();
+ return Attributable.setAttributionSource(
+ mService.getMostRecentlyConnectedDevices(mAttributionSource),
+ mAttributionSource);
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -2305,17 +2471,21 @@ 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<BluetoothDevice> 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());
+ 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 {
@@ -2334,6 +2504,7 @@ public final class BluetoothAdapter {
* BluetoothProfile}.
* @hide
*/
+ @RequiresNoPermission
public @NonNull List<Integer> getSupportedProfiles() {
final ArrayList<Integer> supportedProfiles = new ArrayList<Integer>();
@@ -2360,6 +2531,38 @@ 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<Void, Integer>
+ mBluetoothGetAdapterConnectionStateCache =
+ new PropertyInvalidatedCache<Void, Integer> (
+ 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) {
+ try {
+ return mService.getAdapterConnectionState();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+ };
+
+ /** @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.
* This can be used to check whether the local Bluetooth adapter is connected
@@ -2373,6 +2576,8 @@ public final class BluetoothAdapter {
* @hide
*/
@UnsupportedAppUsage
+ @RequiresLegacyBluetoothPermission
+ @RequiresNoPermission
public int getConnectionState() {
if (getState() != STATE_ON) {
return BluetoothAdapter.STATE_DISCONNECTED;
@@ -2380,10 +2585,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();
}
@@ -2397,6 +2606,7 @@ public final class BluetoothAdapter {
new PropertyInvalidatedCache<Integer, Integer>(
8, BLUETOOTH_PROFILE_CACHE_PROPERTY) {
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
protected Integer recompute(Integer query) {
try {
mServiceLock.readLock().lock();
@@ -2418,6 +2628,7 @@ public final class BluetoothAdapter {
};
/** @hide */
+ @RequiresNoPermission
public void disableGetProfileConnectionStateCache() {
mGetProfileConnectionStateCache.disableLocal();
}
@@ -2439,7 +2650,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;
@@ -2454,7 +2668,6 @@ public final class BluetoothAdapter {
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
* connections from a listening {@link BluetoothServerSocket}.
* <p>Valid RFCOMM channels are in range 1 to 30.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
*
* @param channel RFCOMM channel to listen on
* @return a listening RFCOMM BluetoothServerSocket
@@ -2462,6 +2675,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);
}
@@ -2473,7 +2689,6 @@ public final class BluetoothAdapter {
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
* connections from a listening {@link BluetoothServerSocket}.
* <p>Valid RFCOMM channels are in range 1 to 30.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
* <p>To auto assign a channel without creating a SDP record use
* {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number.
*
@@ -2487,6 +2702,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 =
@@ -2527,7 +2745,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);
@@ -2559,7 +2779,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);
@@ -2590,7 +2812,6 @@ public final class BluetoothAdapter {
* closed, or if this application closes unexpectedly.
* <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
* connect to this socket from another device using the same {@link UUID}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param name service name for SDP record
* @param uuid uuid for SDP record
@@ -2600,12 +2821,16 @@ 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);
}
-
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
boolean auth, boolean encrypt) throws IOException {
BluetoothServerSocket socket;
@@ -2631,6 +2856,8 @@ public final class BluetoothAdapter {
* permissions.
* @hide
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
BluetoothServerSocket socket =
new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, false, port);
@@ -2662,6 +2889,8 @@ public final class BluetoothAdapter {
* permissions.
* @hide
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)
throws IOException {
BluetoothServerSocket socket =
@@ -2694,11 +2923,12 @@ 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);
}
-
/**
* Construct an insecure L2CAP server socket.
* Call #accept to retrieve connections to this socket.
@@ -2711,6 +2941,8 @@ 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);
BluetoothServerSocket socket =
@@ -2737,11 +2969,14 @@ public final class BluetoothAdapter {
/**
* Read the local Out of Band Pairing Data
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @return Pair<byte[], byte[]> of Hash and Randomizer
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public Pair<byte[], byte[]> readOutOfBandData() {
return null;
}
@@ -2762,6 +2997,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) {
@@ -2769,53 +3008,57 @@ 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;
+ } else if (profile == BluetoothProfile.LE_AUDIO) {
+ BluetoothLeAudio leAudio = new BluetoothLeAudio(context, listener, this);
+ return true;
} else if (profile == BluetoothProfile.VOLUME_CONTROL) {
BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this);
return true;
@@ -2834,6 +3077,10 @@ public final class BluetoothAdapter {
* @param profile
* @param proxy Profile proxy object
*/
+ @SuppressLint({
+ "AndroidFrameworkRequiresPermission",
+ "AndroidFrameworkBluetoothPermission"
+ })
public void closeProfileProxy(int profile, BluetoothProfile proxy) {
if (proxy == null) {
return;
@@ -2904,6 +3151,10 @@ public final class BluetoothAdapter {
BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy;
hearingAid.close();
break;
+ case BluetoothProfile.LE_AUDIO:
+ BluetoothLeAudio leAudio = (BluetoothLeAudio) proxy;
+ leAudio.close();
+ break;
case BluetoothProfile.VOLUME_CONTROL:
BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy;
vcs.close();
@@ -2911,8 +3162,10 @@ public final class BluetoothAdapter {
}
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private final IBluetoothManagerCallback mManagerCallback =
new IBluetoothManagerCallback.Stub() {
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onBluetoothServiceUp(IBluetooth bluetoothService) {
if (DBG) {
Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
@@ -2935,11 +3188,11 @@ public final class BluetoothAdapter {
}
}
}
- synchronized (sMetadataListeners) {
- sMetadataListeners.forEach((device, pair) -> {
+ synchronized (mMetadataListeners) {
+ mMetadataListeners.forEach((device, pair) -> {
try {
- mService.registerMetadataListener(sBluetoothMetadataListener,
- device);
+ mService.registerMetadataListener(mBluetoothMetadataListener,
+ device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register metadata listener", e);
}
@@ -2948,7 +3201,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);
@@ -2968,11 +3222,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();
@@ -3007,7 +3261,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) {
@@ -3016,7 +3272,7 @@ public final class BluetoothAdapter {
return true;
}
try {
- return mManagerService.enableNoAutoConnect(ActivityThread.currentPackageName());
+ return mManagerService.enableNoAutoConnect(mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -3025,41 +3281,16 @@ 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 {@link
+ * error interface in order to allow the caller to determine next steps based on the {@code
* ErrorCode}.
*
* @hide
@@ -3077,7 +3308,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);
}
@@ -3160,7 +3391,11 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
- @RequiresPermission(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
@@ -3170,11 +3405,11 @@ public final class BluetoothAdapter {
requireNonNull(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,
- executor));
+ executor), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -3204,12 +3439,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.
*
- * <p>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;
@@ -3241,8 +3478,8 @@ public final class BluetoothAdapter {
}
}
- private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) {
- Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(Arrays.asList(devices));
+ private Set<BluetoothDevice> toDeviceSet(List<BluetoothDevice> devices) {
+ Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(devices);
return Collections.unmodifiableSet(deviceSet);
}
@@ -3307,11 +3544,19 @@ public final class BluetoothAdapter {
&& (Integer.parseInt(address.split(":")[0], 16) & 0xC0) == 0xC0;
}
+ /** {@hide} */
@UnsupportedAppUsage
- /*package*/ IBluetoothManager getBluetoothManager() {
+ @RequiresNoPermission
+ public IBluetoothManager getBluetoothManager() {
return mManagerService;
}
+ /** {@hide} */
+ @RequiresNoPermission
+ public AttributionSource getAttributionSource() {
+ return mAttributionSource;
+ }
+
private final ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks =
new ArrayList<IBluetoothManagerCallback>();
@@ -3353,6 +3598,61 @@ public final class BluetoothAdapter {
}
/**
+ * 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.
*
* <p>Results of the scan are reported using the
@@ -3364,7 +3664,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);
}
@@ -3383,7 +3686,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));
@@ -3417,6 +3723,7 @@ public final class BluetoothAdapter {
return false;
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
@@ -3480,7 +3787,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()");
@@ -3521,7 +3830,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 =
@@ -3567,7 +3878,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 =
@@ -3612,7 +3925,11 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
- @RequiresPermission(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()");
@@ -3632,13 +3949,13 @@ public final class BluetoothAdapter {
throw new NullPointerException("executor is null");
}
- synchronized (sMetadataListeners) {
+ synchronized (mMetadataListeners) {
List<Pair<OnMetadataChangedListener, Executor>> 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)))) {
@@ -3652,7 +3969,8 @@ 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);
} finally {
@@ -3661,7 +3979,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);
}
}
}
@@ -3685,7 +4003,11 @@ public final class BluetoothAdapter {
* @hide
*/
@SystemApi
- @RequiresPermission(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()");
@@ -3696,24 +4018,24 @@ 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.
return true;
}
try {
- return service.unregisterMetadataListener(device);
+ return service.unregisterMetadataListener(device, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "unregisterMetadataListener fail", e);
return false;
@@ -3741,10 +4063,12 @@ public final class BluetoothAdapter {
@Nullable byte[] value);
}
+ @SuppressLint("AndroidFrameworkBluetoothPermission")
private final IBluetoothConnectionCallback mConnectionCallback =
new IBluetoothConnectionCallback.Stub() {
@Override
public void onDeviceConnected(BluetoothDevice device) {
+ Attributable.setAttributionSource(device, mAttributionSource);
for (Map.Entry<BluetoothConnectionCallback, Executor> callbackExecutorEntry:
mBluetoothConnectionCallbackExecutorMap.entrySet()) {
BluetoothConnectionCallback callback = callbackExecutorEntry.getKey();
@@ -3755,6 +4079,7 @@ public final class BluetoothAdapter {
@Override
public void onDeviceDisconnected(BluetoothDevice device, int hciReason) {
+ Attributable.setAttributionSource(device, mAttributionSource);
for (Map.Entry<BluetoothConnectionCallback, Executor> callbackExecutorEntry:
mBluetoothConnectionCallbackExecutorMap.entrySet()) {
BluetoothConnectionCallback callback = callbackExecutorEntry.getKey();
@@ -3774,6 +4099,11 @@ public final class BluetoothAdapter {
* @throws IllegalArgumentException if the callback is already registered
* @hide
*/
+ @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()");
@@ -3787,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;
}
}
@@ -3816,6 +4147,11 @@ public final class BluetoothAdapter {
* @return true if the callback was unregistered successfully, false otherwise
* @hide
*/
+ @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()");
@@ -3837,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);
@@ -3873,141 +4210,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.
- * <p>
- * 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.
- * <p>
- * Example cause: This is a normal disconnect reason, e.g., user/app initiates
- * disconnection.
- * <p>
- * 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.
- * <p>
- * 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.
- * <p>
- * 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.
- * <p>
- * Example cause: remote device might be out of range.
- * <p>
- * 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.
- * <p>
- * Example cause: Devices are either unpaired or remote device is refusing our pairing
- * request.
- * <p>
- * 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.
- * <p>
- * Example cause: privacy policy, power management policy, permissions, etc.
- * <p>
- * 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.
- * <p>
- * Example cause: controller is busy, memory limit reached, maximum number of connections
- * reached.
- * <p>
- * 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.
- * <p>
- * 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;