summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt322
-rw-r--r--core/api/system-current.txt74
-rw-r--r--core/api/system-removed.txt2
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java100
-rwxr-xr-xcore/java/android/bluetooth/BluetoothA2dpSink.java20
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java269
-rw-r--r--core/java/android/bluetooth/BluetoothAvrcpController.java10
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java226
-rw-r--r--core/java/android/bluetooth/BluetoothGatt.java113
-rw-r--r--core/java/android/bluetooth/BluetoothGattCharacteristic.java2
-rw-r--r--core/java/android/bluetooth/BluetoothGattDescriptor.java4
-rw-r--r--core/java/android/bluetooth/BluetoothGattServer.java57
-rw-r--r--core/java/android/bluetooth/BluetoothGattService.java8
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java149
-rw-r--r--core/java/android/bluetooth/BluetoothHeadsetClient.java35
-rw-r--r--core/java/android/bluetooth/BluetoothHealth.java53
-rw-r--r--core/java/android/bluetooth/BluetoothHearingAid.java47
-rw-r--r--core/java/android/bluetooth/BluetoothHidDevice.java23
-rw-r--r--core/java/android/bluetooth/BluetoothHidHost.java54
-rw-r--r--core/java/android/bluetooth/BluetoothLeAudio.java40
-rw-r--r--core/java/android/bluetooth/BluetoothManager.java18
-rw-r--r--core/java/android/bluetooth/BluetoothMap.java33
-rw-r--r--core/java/android/bluetooth/BluetoothMapClient.java53
-rw-r--r--core/java/android/bluetooth/BluetoothPan.java42
-rw-r--r--core/java/android/bluetooth/BluetoothPbap.java13
-rw-r--r--core/java/android/bluetooth/BluetoothPbapClient.java4
-rw-r--r--core/java/android/bluetooth/BluetoothProfile.java6
-rw-r--r--core/java/android/bluetooth/BluetoothProfileConnector.java3
-rw-r--r--core/java/android/bluetooth/BluetoothSap.java36
-rw-r--r--core/java/android/bluetooth/BluetoothServerSocket.java3
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java9
-rw-r--r--core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java39
-rw-r--r--core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java39
-rw-r--r--core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java41
-rw-r--r--core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java39
-rw-r--r--core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java39
-rw-r--r--core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java39
-rw-r--r--core/java/android/bluetooth/le/AdvertisingSet.java32
-rw-r--r--core/java/android/bluetooth/le/BluetoothLeAdvertiser.java59
-rw-r--r--core/java/android/bluetooth/le/BluetoothLeScanner.java58
-rw-r--r--core/java/android/bluetooth/le/PeriodicAdvertisingManager.java18
-rw-r--r--core/java/com/android/internal/util/State.java2
-rw-r--r--errorprone/java/android/annotation/SuppressLint.java38
-rw-r--r--errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java328
-rw-r--r--errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java325
-rw-r--r--errorprone/tests/res/android/annotation/RequiresPermission.java35
-rw-r--r--errorprone/tests/res/android/annotation/SuppressLint.java34
-rw-r--r--errorprone/tests/res/android/content/BroadcastReceiver.java23
-rw-r--r--errorprone/tests/res/android/content/Context.java3
-rw-r--r--errorprone/tests/res/android/database/ContentObserver.java23
-rw-r--r--errorprone/tests/res/android/foo/IColorService.java32
-rw-r--r--errorprone/tests/res/android/os/Handler.java23
-rw-r--r--errorprone/tests/res/android/os/IBinder.java23
-rw-r--r--errorprone/tests/res/android/os/Message.java20
-rw-r--r--services/core/java/com/android/server/BluetoothAirplaneModeListener.java2
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java46
-rw-r--r--services/core/java/com/android/server/BluetoothModeChangeHelper.java2
57 files changed, 2554 insertions, 636 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 325521f3889c..3cd249423d11 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -8604,37 +8604,37 @@ package android.bluetooth {
public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
method public void finalize();
- method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method public int getConnectionState(android.bluetooth.BluetoothDevice);
- method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
- method public boolean isA2dpPlaying(android.bluetooth.BluetoothDevice);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
- field public static final String ACTION_PLAYING_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isA2dpPlaying(android.bluetooth.BluetoothDevice);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_PLAYING_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
field public static final int STATE_NOT_PLAYING = 11; // 0xb
field public static final int STATE_PLAYING = 10; // 0xa
}
public final class BluetoothAdapter {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelDiscovery();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean cancelDiscovery();
method public static boolean checkBluetoothAddress(String);
method public void closeProfileProxy(int, android.bluetooth.BluetoothProfile);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disable();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enable();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public String getAddress();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disable();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enable();
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, "android.permission.LOCAL_MAC_ADDRESS"}) public String getAddress();
method public android.bluetooth.le.BluetoothLeAdvertiser getBluetoothLeAdvertiser();
method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.Set<android.bluetooth.BluetoothDevice> getBondedDevices();
method public static android.bluetooth.BluetoothAdapter getDefaultAdapter();
method public int getLeMaximumAdvertisingDataLength();
- method public String getName();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getProfileConnectionState(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getName();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getProfileConnectionState(int);
method public boolean getProfileProxy(android.content.Context, android.bluetooth.BluetoothProfile.ServiceListener, int);
method public android.bluetooth.BluetoothDevice getRemoteDevice(String);
method public android.bluetooth.BluetoothDevice getRemoteDevice(byte[]);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getScanMode();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getState();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isDiscovering();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEnabled();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public int getScanMode();
+ method public int getState();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean isDiscovering();
+ method public boolean isEnabled();
method public boolean isLe2MPhySupported();
method public boolean isLeCodedPhySupported();
method public boolean isLeExtendedAdvertisingSupported();
@@ -8642,22 +8642,22 @@ package android.bluetooth {
method public boolean isMultipleAdvertisementSupported();
method public boolean isOffloadedFilteringSupported();
method public boolean isOffloadedScanBatchingSupported();
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startDiscovery();
- method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startLeScan(java.util.UUID[], android.bluetooth.BluetoothAdapter.LeScanCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void stopLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
- field public static final String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
- field public static final String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
- field public static final String ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
- field public static final String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
- field public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
- field public static final String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setName(String);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startDiscovery();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean startLeScan(java.util.UUID[], android.bluetooth.BluetoothAdapter.LeScanCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void stopLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public static final String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
field public static final String ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED";
field public static final int ERROR = -2147483648; // 0x80000000
field public static final String EXTRA_CONNECTION_STATE = "android.bluetooth.adapter.extra.CONNECTION_STATE";
@@ -9007,38 +9007,38 @@ package android.bluetooth {
}
public final class BluetoothDevice implements android.os.Parcelable {
- method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
- method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
- method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
- method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond();
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
- method public int describeContents();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean fetchUuidsWithSdp();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBond();
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
+ method public int describeContents();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean fetchUuidsWithSdp();
method public String getAddress();
- method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH) public String getAlias();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothClass getBluetoothClass();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getBondState();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public String getName();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getType();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.os.ParcelUuid[] getUuids();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setAlias(@NonNull String);
+ method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getAlias();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothClass getBluetoothClass();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getBondState();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public String getName();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getType();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.os.ParcelUuid[] getUuids();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setAlias(@NonNull String);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPairingConfirmation(boolean);
- method public boolean setPin(byte[]);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
- field public static final String ACTION_ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED";
- field public static final String ACTION_ACL_DISCONNECT_REQUESTED = "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
- field public static final String ACTION_ALIAS_CHANGED = "android.bluetooth.device.action.ALIAS_CHANGED";
- field public static final String ACTION_BOND_STATE_CHANGED = "android.bluetooth.device.action.BOND_STATE_CHANGED";
- field public static final String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
- field public static final String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
- field public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
- field public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
- field public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setPin(byte[]);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACL_DISCONNECT_REQUESTED = "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ALIAS_CHANGED = "android.bluetooth.device.action.ALIAS_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_BOND_STATE_CHANGED = "android.bluetooth.device.action.BOND_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
field public static final int ADDRESS_TYPE_PUBLIC = 0; // 0x0
field public static final int ADDRESS_TYPE_RANDOM = 1; // 0x1
field public static final int BOND_BONDED = 12; // 0xc
@@ -9076,30 +9076,30 @@ package android.bluetooth {
}
public final class BluetoothGatt implements android.bluetooth.BluetoothProfile {
- method public void abortReliableWrite();
- method @Deprecated public void abortReliableWrite(android.bluetooth.BluetoothDevice);
- method public boolean beginReliableWrite();
- method public void close();
- method public boolean connect();
- method public void disconnect();
- method public boolean discoverServices();
- method public boolean executeReliableWrite();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void abortReliableWrite();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void abortReliableWrite(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean beginReliableWrite();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void close();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void disconnect();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean discoverServices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean executeReliableWrite();
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public int getConnectionState(android.bluetooth.BluetoothDevice);
method public android.bluetooth.BluetoothDevice getDevice();
method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
- method public boolean readCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
- method public boolean readDescriptor(android.bluetooth.BluetoothGattDescriptor);
- method public void readPhy();
- method public boolean readRemoteRssi();
- method public boolean requestConnectionPriority(int);
- method public boolean requestMtu(int);
- method public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean);
- method public void setPreferredPhy(int, int, int);
- method public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
- method public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean readCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean readDescriptor(android.bluetooth.BluetoothGattDescriptor);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void readPhy();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean readRemoteRssi();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean requestConnectionPriority(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean requestMtu(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setPreferredPhy(int, int, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
field public static final int CONNECTION_PRIORITY_BALANCED = 0; // 0x0
field public static final int CONNECTION_PRIORITY_HIGH = 1; // 0x1
field public static final int CONNECTION_PRIORITY_LOW_POWER = 2; // 0x2
@@ -9209,21 +9209,21 @@ package android.bluetooth {
}
public final class BluetoothGattServer implements android.bluetooth.BluetoothProfile {
- method public boolean addService(android.bluetooth.BluetoothGattService);
- method public void cancelConnection(android.bluetooth.BluetoothDevice);
- method public void clearServices();
- method public void close();
- method public boolean connect(android.bluetooth.BluetoothDevice, boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean addService(android.bluetooth.BluetoothGattService);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void cancelConnection(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void clearServices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void close();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect(android.bluetooth.BluetoothDevice, boolean);
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public int getConnectionState(android.bluetooth.BluetoothDevice);
method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
- method public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
- method public void readPhy(android.bluetooth.BluetoothDevice);
- method public boolean removeService(android.bluetooth.BluetoothGattService);
- method public boolean sendResponse(android.bluetooth.BluetoothDevice, int, int, int, byte[]);
- method public void setPreferredPhy(android.bluetooth.BluetoothDevice, int, int, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void readPhy(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeService(android.bluetooth.BluetoothGattService);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendResponse(android.bluetooth.BluetoothDevice, int, int, int, byte[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setPreferredPhy(android.bluetooth.BluetoothDevice, int, int, int);
}
public abstract class BluetoothGattServerCallback {
@@ -9261,18 +9261,18 @@ package android.bluetooth {
}
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
- method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method public int getConnectionState(android.bluetooth.BluetoothDevice);
- method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
- method public boolean isAudioConnected(android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isNoiseReductionSupported(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isVoiceRecognitionSupported(@NonNull android.bluetooth.BluetoothDevice);
- method public boolean sendVendorSpecificResultCode(android.bluetooth.BluetoothDevice, String, String);
- method public boolean startVoiceRecognition(android.bluetooth.BluetoothDevice);
- method public boolean stopVoiceRecognition(android.bluetooth.BluetoothDevice);
- field public static final String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED";
- field public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT = "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isAudioConnected(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isNoiseReductionSupported(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isVoiceRecognitionSupported(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendVendorSpecificResultCode(android.bluetooth.BluetoothDevice, String, String);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean startVoiceRecognition(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean stopVoiceRecognition(android.bluetooth.BluetoothDevice);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT = "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
field public static final int AT_CMD_TYPE_ACTION = 4; // 0x4
field public static final int AT_CMD_TYPE_BASIC = 3; // 0x3
field public static final int AT_CMD_TYPE_READ = 0; // 0x0
@@ -9289,14 +9289,14 @@ package android.bluetooth {
}
@Deprecated public final class BluetoothHealth implements android.bluetooth.BluetoothProfile {
- method @Deprecated public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
- method @Deprecated public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
- method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @Deprecated public int getConnectionState(android.bluetooth.BluetoothDevice);
- method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
- method @Deprecated public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
- method @Deprecated public boolean registerSinkAppConfiguration(String, int, android.bluetooth.BluetoothHealthCallback);
- method @Deprecated public boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean registerSinkAppConfiguration(String, int, android.bluetooth.BluetoothHealthCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration);
field @Deprecated public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; // 0x1
field @Deprecated public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; // 0x0
field @Deprecated public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; // 0x3
@@ -9327,24 +9327,24 @@ package android.bluetooth {
}
public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
- method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
}
public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
- method public boolean connect(android.bluetooth.BluetoothDevice);
- method public boolean disconnect(android.bluetooth.BluetoothDevice);
- method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method public int getConnectionState(android.bluetooth.BluetoothDevice);
- method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
- method public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, java.util.concurrent.Executor, android.bluetooth.BluetoothHidDevice.Callback);
- method public boolean replyReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]);
- method public boolean reportError(android.bluetooth.BluetoothDevice, byte);
- method public boolean sendReport(android.bluetooth.BluetoothDevice, int, byte[]);
- method public boolean unregisterApp();
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean connect(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, java.util.concurrent.Executor, android.bluetooth.BluetoothHidDevice.Callback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean replyReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean reportError(android.bluetooth.BluetoothDevice, byte);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean sendReport(android.bluetooth.BluetoothDevice, int, byte[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean unregisterApp();
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
field public static final byte ERROR_RSP_INVALID_PARAM = 4; // 0x4
field public static final byte ERROR_RSP_INVALID_RPT_ID = 2; // 0x2
field public static final byte ERROR_RSP_NOT_READY = 1; // 0x1
@@ -9410,26 +9410,26 @@ package android.bluetooth {
}
public final class BluetoothLeAudio implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void close();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) protected void finalize();
- method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
- field public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
+ method public void close();
+ method protected void finalize();
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
}
public final class BluetoothManager {
method public android.bluetooth.BluetoothAdapter getAdapter();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(android.bluetooth.BluetoothDevice, int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int, int[]);
- method public android.bluetooth.BluetoothGattServer openGattServer(android.content.Context, android.bluetooth.BluetoothGattServerCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int, int[]);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothGattServer openGattServer(android.content.Context, android.bluetooth.BluetoothGattServerCallback);
}
public interface BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
field public static final int A2DP = 2; // 0x2
field public static final String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE";
field public static final String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
@@ -9460,7 +9460,7 @@ package android.bluetooth {
public final class BluetoothSocket implements java.io.Closeable {
method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void connect() throws java.io.IOException;
method public int getConnectionType();
method public java.io.InputStream getInputStream() throws java.io.IOException;
method public int getMaxReceivePacketSize();
@@ -9538,13 +9538,13 @@ package android.bluetooth.le {
}
public final class AdvertisingSet {
- method public void enableAdvertising(boolean, int, int);
- method public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
- method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
- method public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
- method public void setPeriodicAdvertisingEnabled(boolean);
- method public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
- method public void setScanResponseData(android.bluetooth.le.AdvertiseData);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void enableAdvertising(boolean, int, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void setScanResponseData(android.bluetooth.le.AdvertiseData);
}
public abstract class AdvertisingSetCallback {
@@ -9607,23 +9607,23 @@ package android.bluetooth.le {
}
public final class BluetoothLeAdvertiser {
- method public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
- method public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
- method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback);
- method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
- method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, int, android.bluetooth.le.AdvertisingSetCallback);
- method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, int, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
- method public void stopAdvertising(android.bluetooth.le.AdvertiseCallback);
- method public void stopAdvertisingSet(android.bluetooth.le.AdvertisingSetCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, int, android.bluetooth.le.AdvertisingSetCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT}) public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, int, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void stopAdvertising(android.bluetooth.le.AdvertiseCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE) public void stopAdvertisingSet(android.bluetooth.le.AdvertisingSetCallback);
}
public final class BluetoothLeScanner {
- method public void flushPendingScanResults(android.bluetooth.le.ScanCallback);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void startScan(android.bluetooth.le.ScanCallback);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public int startScan(@Nullable java.util.List<android.bluetooth.le.ScanFilter>, @Nullable android.bluetooth.le.ScanSettings, @NonNull android.app.PendingIntent);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void stopScan(android.bluetooth.le.ScanCallback);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void stopScan(android.app.PendingIntent);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void flushPendingScanResults(android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startScan(android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startScan(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public int startScan(@Nullable java.util.List<android.bluetooth.le.ScanFilter>, @Nullable android.bluetooth.le.ScanSettings, @NonNull android.app.PendingIntent);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void stopScan(android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void stopScan(android.app.PendingIntent);
field public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE";
field public static final String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE";
field public static final String EXTRA_LIST_SCAN_RESULT = "android.bluetooth.le.extra.LIST_SCAN_RESULT";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 199d77a232e9..e956dee11526 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1901,7 +1901,7 @@ package android.bluetooth {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getDynamicBufferSupport();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferLengthMillis(int, int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1
field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2
field public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0; // 0x0
@@ -1917,22 +1917,22 @@ package android.bluetooth {
method public void finalize();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isAudioPlaying(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
}
public final class BluetoothAdapter {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
- method public boolean disableBLE();
- method public boolean enableBLE();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disableBLE();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableBLE();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enableNoAutoConnect();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void generateLocalOobData(int, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OobDataCallback);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public long getDiscoveryEndMillis();
method public boolean isBleScanAlwaysAvailable();
method public boolean isLeEnabled();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeActiveDevice(int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean removeActiveDevice(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setActiveDevice(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setActiveDevice(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
field public static final int ACTIVE_DEVICE_ALL = 2; // 0x2
@@ -1954,14 +1954,14 @@ package android.bluetooth {
public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean canBondWithoutDialog();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean cancelBondProcess();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean cancelBondProcess();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData);
method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getSimAccessPermission();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getSimAccessPermission();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isConnected();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isEncrypted();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeBond();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean removeBond();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMessageAccessPermission(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
@@ -2002,51 +2002,51 @@ package android.bluetooth {
}
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connect(android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnect(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean connect(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disconnect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
}
public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public long getHiSyncId(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
}
public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
}
public final class BluetoothHidHost implements android.bluetooth.BluetoothProfile {
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
}
public final class BluetoothMap implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void close();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) protected void finalize();
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method public void close();
+ method protected void finalize();
+ method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
}
public final class BluetoothMapClient implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.SEND_SMS) public boolean sendMessage(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.net.Uri>, @NonNull String, @Nullable android.app.PendingIntent, @Nullable android.app.PendingIntent);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.SEND_SMS}) public boolean sendMessage(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.net.Uri>, @NonNull String, @Nullable android.app.PendingIntent, @Nullable android.app.PendingIntent);
}
public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @NonNull @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isTetheringOn();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setBluetoothTethering(boolean);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
- field public static final String ACTION_TETHERING_STATE_CHANGED = "android.bluetooth.action.TETHERING_STATE_CHANGED";
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isTetheringOn();
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.TETHER_PRIVILEGED}) public void setBluetoothTethering(boolean);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_TETHERING_STATE_CHANGED = "android.bluetooth.action.TETHERING_STATE_CHANGED";
field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
field public static final String EXTRA_TETHERING_STATE = "android.bluetooth.extra.TETHERING_STATE";
field public static final int LOCAL_NAP_ROLE = 1; // 0x1
@@ -2060,7 +2060,7 @@ package android.bluetooth {
public class BluetoothPbap implements android.bluetooth.BluetoothProfile {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
}
@@ -2185,9 +2185,9 @@ package android.bluetooth {
package android.bluetooth.le {
public final class BluetoothLeScanner {
- method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADMIN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
- method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADMIN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
- method public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
}
public final class ResultStorageDescriptor implements android.os.Parcelable {
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index b50b8dd3fdb4..bf9f4f1ad37e 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -51,7 +51,7 @@ package android.app.prediction {
package android.bluetooth {
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
- method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
+ method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
}
}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 16413e1a1db6..a268e168ae74 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -23,6 +23,9 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -69,10 +72,10 @@ public final class BluetoothA2dp implements BluetoothProfile {
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission 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.a2dp.profile.action.CONNECTION_STATE_CHANGED";
@@ -90,10 +93,10 @@ public final class BluetoothA2dp implements BluetoothProfile {
*
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PLAYING_STATE_CHANGED =
"android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
@@ -112,11 +115,11 @@ public final class BluetoothA2dp implements BluetoothProfile {
* be null if no device is active. </li>
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@UnsupportedAppUsage(trackingBug = 171933273)
public static final String ACTION_ACTIVE_DEVICE_CHANGED =
@@ -133,11 +136,11 @@ public final class BluetoothA2dp implements BluetoothProfile {
* connected, otherwise it is not included.</li>
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@UnsupportedAppUsage(trackingBug = 181103983)
public static final String ACTION_CODEC_CONFIG_CHANGED =
@@ -307,7 +310,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
@@ -347,7 +352,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
@@ -368,6 +375,8 @@ public final class BluetoothA2dp implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
try {
@@ -387,6 +396,8 @@ public final class BluetoothA2dp implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
try {
@@ -406,6 +417,8 @@ public final class BluetoothA2dp implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @BtProfileState int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
try {
@@ -441,7 +454,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage(trackingBug = 171933273)
public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) log("setActiveDevice(" + device + ")");
@@ -468,7 +483,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
@UnsupportedAppUsage(trackingBug = 171933273)
@Nullable
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothDevice getActiveDevice() {
if (VDBG) log("getActiveDevice()");
try {
@@ -495,7 +512,10 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -514,7 +534,10 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -546,7 +569,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
@@ -620,6 +645,8 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @param volume Absolute volume to be set on AVRCP side
* @hide
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setAvrcpAbsoluteVolume(int volume) {
if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
try {
@@ -636,10 +663,11 @@ public final class BluetoothA2dp implements BluetoothProfile {
/**
* Check if A2DP profile is streaming music.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device BluetoothDevice device
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isA2dpPlaying(BluetoothDevice device) {
try {
final IBluetoothA2dp service = getService();
@@ -662,6 +690,7 @@ public final class BluetoothA2dp implements BluetoothProfile {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean shouldSendVolumeKeys(BluetoothDevice device) {
if (isEnabled() && isValidDevice(device)) {
ParcelUuid[] uuids = device.getUuids();
@@ -686,7 +715,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
@UnsupportedAppUsage(trackingBug = 181103983)
@Nullable
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) {
if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
verifyDeviceNotNull(device, "getCodecStatus");
@@ -714,7 +745,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(trackingBug = 181103983)
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setCodecConfigPreference(@NonNull BluetoothDevice device,
@NonNull BluetoothCodecConfig codecConfig) {
if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
@@ -744,7 +777,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void enableOptionalCodecs(@NonNull BluetoothDevice device) {
if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")");
verifyDeviceNotNull(device, "enableOptionalCodecs");
@@ -759,7 +794,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void disableOptionalCodecs(@NonNull BluetoothDevice device) {
if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")");
verifyDeviceNotNull(device, "disableOptionalCodecs");
@@ -773,6 +810,7 @@ public final class BluetoothA2dp implements BluetoothProfile {
* active A2DP Bluetooth device.
* @param enable if true, enable the optional codecs, other disable them
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void enableDisableOptionalCodecs(BluetoothDevice device, boolean enable) {
try {
final IBluetoothA2dp service = getService();
@@ -800,7 +838,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@OptionalCodecsSupportStatus
public int isOptionalCodecsSupported(@NonNull BluetoothDevice device) {
verifyDeviceNotNull(device, "isOptionalCodecsSupported");
@@ -826,7 +866,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@OptionalCodecsPreferenceStatus
public int isOptionalCodecsEnabled(@NonNull BluetoothDevice device) {
verifyDeviceNotNull(device, "isOptionalCodecsEnabled");
@@ -853,7 +895,9 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setOptionalCodecsEnabled(@NonNull BluetoothDevice device,
@OptionalCodecsPreferenceStatus int value) {
verifyDeviceNotNull(device, "setOptionalCodecsEnabled");
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index 67f3d7b5d717..d81316e357d3 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -21,6 +21,9 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Binder;
@@ -160,7 +163,9 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothA2dpSink service = getService();
@@ -243,8 +248,6 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
* Get the current audio configuration for the A2DP source device,
* or null if the device has no audio configuration
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Remote bluetooth device.
* @return audio configuration for the device, or null
*
@@ -252,6 +255,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
*
* @hide
*/
+ @RequiresLegacyBluetoothPermission
public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
if (VDBG) log("getAudioConfig(" + device + ")");
final IBluetoothA2dpSink service = getService();
@@ -278,7 +282,10 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -297,7 +304,10 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 236185e2a28d..972e9e6d73b0 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/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)}.
* </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>
@@ -144,8 +145,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";
@@ -278,8 +279,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";
@@ -305,8 +308,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";
@@ -325,10 +330,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";
@@ -355,8 +362,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";
@@ -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.
- * <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";
@@ -526,8 +539,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";
/**
@@ -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}.
- *
- * <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";
@@ -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<Void, Integer>(
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.
*
- * <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 {
@@ -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.
* <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();
@@ -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<Void, Boolean>(
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<BluetoothDevice> 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<BluetoothDevice> 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<Integer, Integer>(
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 {
* <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
@@ -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 {
* <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.
*
@@ -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.
* <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
@@ -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
- * <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;
}
@@ -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.
*
- * <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;
@@ -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()");
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
index 4e7e4415c54d..887cf3f08b9d 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -16,6 +16,10 @@
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -54,10 +58,10 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 0c208fd71aed..1201663d1d10 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -16,7 +16,6 @@
package android.bluetooth;
-import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,6 +25,11 @@ import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.app.PropertyInvalidatedCache;
+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.companion.AssociationRequest;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -66,9 +70,6 @@ import java.util.UUID;
* {@link #createRfcommSocketToServiceRecord(UUID)} over Bluetooth BR/EDR or using
* {@link #createL2capChannel(int)} over Bluetooth LE.
*
- * <p class="note"><strong>Note:</strong>
- * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>
@@ -108,10 +109,12 @@ public final class BluetoothDevice implements Parcelable {
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
* {@link #EXTRA_RSSI} if they are available.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} and
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive.
*/
// TODO: Change API to not broadcast RSSI if not available (incoming connection)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_FOUND =
"android.bluetooth.device.action.FOUND";
@@ -120,9 +123,11 @@ public final class BluetoothDevice implements Parcelable {
* Broadcast Action: Bluetooth class of a remote device has changed.
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_CLASS}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
* {@see BluetoothClass}
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CLASS_CHANGED =
"android.bluetooth.device.action.CLASS_CHANGED";
@@ -133,8 +138,10 @@ public final class BluetoothDevice implements Parcelable {
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
* <p>ACL connections are managed automatically by the Android Bluetooth
* stack.
- * <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_ACL_CONNECTED =
"android.bluetooth.device.action.ACL_CONNECTED";
@@ -146,8 +153,10 @@ public final class BluetoothDevice implements Parcelable {
* this intent as a hint to immediately terminate higher level connections
* (RFCOMM, L2CAP, or profile connections) to the remote device.
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <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_ACL_DISCONNECT_REQUESTED =
"android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
@@ -158,8 +167,10 @@ public final class BluetoothDevice implements Parcelable {
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
* <p>ACL connections are managed automatically by the Android Bluetooth
* stack.
- * <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_ACL_DISCONNECTED =
"android.bluetooth.device.action.ACL_DISCONNECTED";
@@ -169,8 +180,10 @@ public final class BluetoothDevice implements Parcelable {
* been retrieved for the first time, or changed since the last retrieval.
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_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_NAME_CHANGED =
"android.bluetooth.device.action.NAME_CHANGED";
@@ -179,9 +192,11 @@ public final class BluetoothDevice implements Parcelable {
* Broadcast Action: Indicates the alias of a remote device has been
* changed.
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
@SuppressLint("ActionValue")
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_ALIAS_CHANGED =
"android.bluetooth.device.action.ALIAS_CHANGED";
@@ -191,10 +206,12 @@ public final class BluetoothDevice implements Parcelable {
* device. For example, if a device is bonded (paired).
* <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
* #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
// Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
// contain a hidden extra field EXTRA_REASON with the result code.
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_BOND_STATE_CHANGED =
"android.bluetooth.device.action.BOND_STATE_CHANGED";
@@ -204,10 +221,12 @@ public final class BluetoothDevice implements Parcelable {
* been retrieved for the first time, or changed since the last retrieval
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_BATTERY_LEVEL}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_BATTERY_LEVEL_CHANGED =
"android.bluetooth.device.action.BATTERY_LEVEL_CHANGED";
@@ -642,8 +661,10 @@ public final class BluetoothDevice implements Parcelable {
* device are requested to be fetched using Service Discovery Protocol
* <p> Always contains the extra field {@link #EXTRA_DEVICE}
* <p> Always contains the extra field {@link #EXTRA_UUID}
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to receive.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_UUID =
"android.bluetooth.device.action.UUID";
@@ -657,20 +678,23 @@ public final class BluetoothDevice implements Parcelable {
* Broadcast Action: Indicates a failure to retrieve the name of a remote
* device.
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*
* @hide
*/
//TODO: is this actually useful?
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_NAME_FAILED =
"android.bluetooth.device.action.NAME_FAILED";
/**
* Broadcast Action: This intent is used to broadcast PAIRING REQUEST
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to
- * receive.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PAIRING_REQUEST =
"android.bluetooth.device.action.PAIRING_REQUEST";
@@ -1206,7 +1230,9 @@ public final class BluetoothDevice implements Parcelable {
*
* @return the Bluetooth name, or null if there was a problem.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public String getName() {
final IBluetooth service = sService;
if (service == null) {
@@ -1235,7 +1261,9 @@ public final class BluetoothDevice implements Parcelable {
* @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} {@link
* #DEVICE_TYPE_DUAL}. {@link #DEVICE_TYPE_UNKNOWN} if it's not available
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getType() {
final IBluetooth service = sService;
if (service == null) {
@@ -1257,7 +1285,9 @@ public final class BluetoothDevice implements Parcelable {
* null if there was a problem
*/
@Nullable
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public String getAlias() {
final IBluetooth service = sService;
if (service == null) {
@@ -1293,7 +1323,9 @@ public final class BluetoothDevice implements Parcelable {
* @return {@code true} if the alias is successfully set, {@code false} on error
* @throws IllegalArgumentException if the alias is {@code null} or the empty string
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setAlias(@NonNull String alias) {
if (alias == null || alias.isEmpty()) {
throw new IllegalArgumentException("Cannot set the alias to null or the empty string");
@@ -1321,7 +1353,9 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getBatteryLevel() {
final IBluetooth service = sService;
if (service == null) {
@@ -1346,7 +1380,9 @@ public final class BluetoothDevice implements Parcelable {
*
* @return false on immediate error, true if bonding will begin
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean createBond() {
return createBond(TRANSPORT_AUTO);
}
@@ -1367,7 +1403,9 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean createBond(int transport) {
return createBondInternal(transport, null, null);
}
@@ -1395,7 +1433,7 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean createBondOutOfBand(int transport, @Nullable OobData remoteP192Data,
@Nullable OobData remoteP256Data) {
if (remoteP192Data == null && remoteP256Data == null) {
@@ -1406,6 +1444,7 @@ public final class BluetoothDevice implements Parcelable {
return createBondInternal(transport, remoteP192Data, remoteP256Data);
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data,
@Nullable OobData remoteP256Data) {
final IBluetooth service = sService;
@@ -1430,7 +1469,9 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isBondingInitiatedLocally() {
final IBluetooth service = sService;
if (service == null) {
@@ -1452,7 +1493,7 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean cancelBondProcess() {
final IBluetooth service = sService;
if (service == null) {
@@ -1480,7 +1521,7 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean removeBond() {
final IBluetooth service = sService;
if (service == null) {
@@ -1504,6 +1545,7 @@ public final class BluetoothDevice implements Parcelable {
new PropertyInvalidatedCache<BluetoothDevice, Integer>(
8, BLUETOOTH_BONDING_CACHE_PROPERTY) {
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
protected Integer recompute(BluetoothDevice query) {
try {
return sService.getBondState(query);
@@ -1532,7 +1574,10 @@ public final class BluetoothDevice implements Parcelable {
*
* @return the bond state
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public int getBondState() {
final IBluetooth service = sService;
if (service == null) {
@@ -1560,7 +1605,7 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean canBondWithoutDialog() {
final IBluetooth service = sService;
if (service == null) {
@@ -1583,7 +1628,9 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isConnected() {
final IBluetooth service = sService;
if (service == null) {
@@ -1606,7 +1653,9 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isEncrypted() {
final IBluetooth service = sService;
if (service == null) {
@@ -1626,7 +1675,9 @@ public final class BluetoothDevice implements Parcelable {
*
* @return Bluetooth class object, or null on error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothClass getBluetoothClass() {
final IBluetooth service = sService;
if (service == null) {
@@ -1653,7 +1704,9 @@ public final class BluetoothDevice implements Parcelable {
*
* @return the supported features (UUIDs) of the remote device, or null on error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public ParcelUuid[] getUuids() {
final IBluetooth service = sService;
if (service == null || !isBluetoothEnabled()) {
@@ -1681,7 +1734,9 @@ public final class BluetoothDevice implements Parcelable {
* @return False if the check fails, True if the process of initiating an ACL connection
* to the remote device was started.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean fetchUuidsWithSdp() {
final IBluetooth service = sService;
if (service == null || !isBluetoothEnabled()) {
@@ -1707,8 +1762,7 @@ public final class BluetoothDevice implements Parcelable {
* {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
* Detailed status error codes can be found by members of the Bluetooth package in
* the AbstractionLayer class.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
- * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
+ * <p>The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
* The object type will match one of the SdpXxxRecord types, depending on the UUID searched
* for.
*
@@ -1717,6 +1771,9 @@ public final class BluetoothDevice implements Parcelable {
* was started.
*/
/** @hide */
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sdpSearch(ParcelUuid uuid) {
final IBluetooth service = sService;
if (service == null) {
@@ -1733,10 +1790,12 @@ public final class BluetoothDevice implements Parcelable {
/**
* Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
* @return true pin has been set false for error
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setPin(byte[] pin) {
final IBluetooth service = sService;
if (service == null) {
@@ -1758,7 +1817,9 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setPin(@NonNull String pin) {
byte[] pinBytes = convertPinToBytes(pin);
if (pinBytes == null) {
@@ -1772,7 +1833,7 @@ public final class BluetoothDevice implements Parcelable {
*
* @return true confirmation has been sent out false for error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setPairingConfirmation(boolean confirm) {
final IBluetooth service = sService;
if (service == null) {
@@ -1795,7 +1856,9 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean cancelPairing() {
final IBluetooth service = sService;
if (service == null) {
@@ -1827,7 +1890,9 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @AccessPermission int getPhonebookAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
@@ -1859,8 +1924,6 @@ public final class BluetoothDevice implements Parcelable {
* If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot
* enter silence mode.
*
- * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
- *
* @param silence true to enter silence mode, false to exit
* @return true on success, false on error.
* @throws IllegalStateException if Bluetooth is not turned ON.
@@ -1884,8 +1947,6 @@ public final class BluetoothDevice implements Parcelable {
/**
* Check whether the {@link BluetoothDevice} is in silence mode
*
- * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
- *
* @return true on device in silence mode, otherwise false.
* @throws IllegalStateException if Bluetooth is not turned ON.
* @hide
@@ -1935,7 +1996,9 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @AccessPermission int getMessageAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
@@ -1959,7 +2022,7 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setMessageAccessPermission(@AccessPermission int value) {
// Validates param value is one of the accepted constants
if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) {
@@ -1984,7 +2047,9 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @AccessPermission int getSimAccessPermission() {
final IBluetooth service = sService;
if (service == null) {
@@ -2008,7 +2073,7 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setSimAccessPermission(int value) {
final IBluetooth service = sService;
if (service == null) {
@@ -2039,7 +2104,6 @@ public final class BluetoothDevice implements Parcelable {
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
* connection.
* <p>Valid RFCOMM channels are in range 1 to 30.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param channel RFCOMM channel to connect to
* @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
@@ -2048,6 +2112,10 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createRfcommSocket(int channel) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "Bluetooth is not enabled");
@@ -2074,7 +2142,6 @@ public final class BluetoothDevice implements Parcelable {
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
* connection.
* <p>Valid L2CAP PSM channels are in range 1 to 2^16.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param channel L2cap PSM/channel to connect to
* @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
@@ -2082,6 +2149,10 @@ public final class BluetoothDevice implements Parcelable {
* permissions
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createL2capSocket(int channel) throws IOException {
return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
null);
@@ -2095,7 +2166,6 @@ public final class BluetoothDevice implements Parcelable {
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
* connection.
* <p>Valid L2CAP PSM channels are in range 1 to 2^16.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param channel L2cap PSM/channel to connect to
* @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
@@ -2103,6 +2173,10 @@ public final class BluetoothDevice implements Parcelable {
* permissions
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException {
return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel,
null);
@@ -2138,7 +2212,10 @@ public final class BluetoothDevice implements Parcelable {
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "Bluetooth is not enabled");
@@ -2176,7 +2253,10 @@ public final class BluetoothDevice implements Parcelable {
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "Bluetooth is not enabled");
@@ -2192,7 +2272,6 @@ public final class BluetoothDevice implements Parcelable {
* Call #connect on the returned #BluetoothSocket to begin the connection.
* The remote device will not be authenticated and communication on this
* socket will not be encrypted.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
*
* @param port remote port
* @return An RFCOMM BluetoothSocket
@@ -2202,6 +2281,10 @@ public final class BluetoothDevice implements Parcelable {
*/
@UnsupportedAppUsage(publicAlternatives = "Use "
+ "{@link #createInsecureRfcommSocketToServiceRecord} instead.")
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "Bluetooth is not enabled");
@@ -2214,7 +2297,6 @@ public final class BluetoothDevice implements Parcelable {
/**
* Construct a SCO socket ready to start an outgoing connection.
* Call #connect on the returned #BluetoothSocket to begin the connection.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
*
* @return a SCO BluetoothSocket
* @throws IOException on error, for example Bluetooth not available, or insufficient
@@ -2222,6 +2304,10 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public BluetoothSocket createScoSocket() throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "Bluetooth is not enabled");
@@ -2269,6 +2355,8 @@ public final class BluetoothDevice implements Parcelable {
* automatically connect as soon as the remote device becomes available (true).
* @throws IllegalArgumentException if callback is null
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback) {
return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO));
@@ -2289,6 +2377,8 @@ public final class BluetoothDevice implements Parcelable {
* BluetoothDevice#TRANSPORT_LE}
* @throws IllegalArgumentException if callback is null
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback, int transport) {
return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK));
@@ -2313,6 +2403,8 @@ public final class BluetoothDevice implements Parcelable {
* is set to true.
* @throws NullPointerException if callback is null
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback, int transport, int phy) {
return connectGatt(context, autoConnect, callback, transport, phy, null);
@@ -2339,6 +2431,8 @@ public final class BluetoothDevice implements Parcelable {
* an un-specified background thread.
* @throws NullPointerException if callback is null
*/
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback, int transport, int phy,
Handler handler) {
@@ -2372,6 +2466,8 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback, int transport,
boolean opportunistic, int phy, Handler handler) {
@@ -2416,7 +2512,10 @@ public final class BluetoothDevice implements Parcelable {
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
@@ -2444,7 +2543,10 @@ public final class BluetoothDevice implements Parcelable {
* @throws IOException on error, for example Bluetooth not available, or insufficient
* permissions
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
if (!isBluetoothEnabled()) {
Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
@@ -2472,7 +2574,7 @@ public final class BluetoothDevice implements Parcelable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) {
final IBluetooth service = sService;
if (service == null) {
@@ -2500,7 +2602,7 @@ public final class BluetoothDevice implements Parcelable {
*/
@SystemApi
@Nullable
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public byte[] getMetadata(@MetadataKey int key) {
final IBluetooth service = sService;
if (service == null) {
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 381318b26dad..942f8432639c 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -17,6 +17,14 @@
package android.bluetooth;
import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.annotation.RequiresPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
+import android.bluetooth.annotations.RequiresBluetoothScanPermission;
import android.os.Build;
import android.os.Handler;
import android.os.ParcelUuid;
@@ -157,6 +165,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @hide
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onClientRegistered(int status, int clientIf) {
if (DBG) {
Log.d(TAG, "onClientRegistered() - status=" + status
@@ -347,6 +356,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @hide
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onCharacteristicRead(String address, int status, int handle,
byte[] value) {
if (VDBG) {
@@ -404,6 +414,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @hide
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onCharacteristicWrite(String address, int status, int handle) {
if (VDBG) {
Log.d(TAG, "onCharacteristicWrite() - Device=" + address
@@ -487,6 +498,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @hide
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onDescriptorRead(String address, int status, int handle, byte[] value) {
if (VDBG) {
Log.d(TAG,
@@ -538,6 +550,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @hide
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onDescriptorWrite(String address, int status, int handle) {
if (VDBG) {
Log.d(TAG,
@@ -734,6 +747,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* Application should call this method as early as possible after it is done with
* this GATT client.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void close() {
if (DBG) Log.d(TAG, "close()");
@@ -817,12 +831,13 @@ public final class BluetoothGatt implements BluetoothProfile {
* <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
* is used to notify success or failure if the function returns true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @return If true, the callback will be called to notify success or failure, false on immediate
* error
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private boolean registerApp(BluetoothGattCallback callback, Handler handler) {
return registerApp(callback, handler, false);
}
@@ -833,14 +848,15 @@ public final class BluetoothGatt implements BluetoothProfile {
* <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
* is used to notify success or failure if the function returns true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @param eatt_support indicate to allow for eatt support
* @return If true, the callback will be called to notify success or failure, false on immediate
* error
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private boolean registerApp(BluetoothGattCallback callback, Handler handler,
boolean eatt_support) {
if (DBG) Log.d(TAG, "registerApp()");
@@ -865,6 +881,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* Unregister the current application and callbacks.
*/
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void unregisterApp() {
if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf);
if (mService == null || mClientIf == 0) return;
@@ -893,14 +910,15 @@ public final class BluetoothGatt implements BluetoothProfile {
* subsequent connections to known devices should be invoked with the
* autoConnect parameter set to true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Remote device to connect to
* @param autoConnect Whether to directly connect to the remote device (false) or to
* automatically connect as soon as the remote device becomes available (true).
* @return true, if the connection attempt was initiated successfully
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
/*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback,
Handler handler) {
if (DBG) {
@@ -931,9 +949,10 @@ public final class BluetoothGatt implements BluetoothProfile {
/**
* Disconnects an established connection, or cancels a connection attempt
* currently in progress.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void disconnect() {
if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return;
@@ -954,6 +973,7 @@ public final class BluetoothGatt implements BluetoothProfile {
*
* @return true, if the connection attempt was initiated successfully
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect() {
try {
mService.clientConnect(mClientIf, mDevice.getAddress(), false, mTransport,
@@ -983,6 +1003,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* of {@link BluetoothDevice#PHY_OPTION_NO_PREFERRED}, {@link BluetoothDevice#PHY_OPTION_S2} or
* {@link BluetoothDevice#PHY_OPTION_S8}
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setPreferredPhy(int txPhy, int rxPhy, int phyOptions) {
try {
mService.clientSetPreferredPhy(mClientIf, mDevice.getAddress(), txPhy, rxPhy,
@@ -996,6 +1017,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* Read the current transmitter PHY and receiver PHY of the connection. The values are returned
* in {@link BluetoothGattCallback#onPhyRead}
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void readPhy() {
try {
mService.clientReadPhy(mClientIf, mDevice.getAddress());
@@ -1022,10 +1044,11 @@ public final class BluetoothGatt implements BluetoothProfile {
* triggered. If the discovery was successful, the remote services can be
* retrieved using the {@link #getServices} function.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the remote service discovery has been started
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean discoverServices() {
if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1047,11 +1070,12 @@ public final class BluetoothGatt implements BluetoothProfile {
* It should never be used by real applications. The service is not searched
* for characteristics and descriptors, or returned in any callback.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the remote service discovery has been started
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean discoverServiceByUuid(UUID uuid) {
if (DBG) Log.d(TAG, "discoverServiceByUuid() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1073,11 +1097,10 @@ public final class BluetoothGatt implements BluetoothProfile {
* <p>This function requires that service discovery has been completed
* for the given device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return List of services on the remote device. Returns an empty list if service discovery has
* not yet been performed.
*/
+ @RequiresLegacyBluetoothPermission
public List<BluetoothGattService> getServices() {
List<BluetoothGattService> result =
new ArrayList<BluetoothGattService>();
@@ -1101,12 +1124,11 @@ public final class BluetoothGatt implements BluetoothProfile {
* <p>If multiple instances of the same service (as identified by UUID)
* exist, the first instance of the service is returned.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param uuid UUID of the requested service
* @return BluetoothGattService if supported, or null if the requested service is not offered by
* the remote device.
*/
+ @RequiresLegacyBluetoothPermission
public BluetoothGattService getService(UUID uuid) {
for (BluetoothGattService service : mServices) {
if (service.getDevice().equals(mDevice) && service.getUuid().equals(uuid)) {
@@ -1124,11 +1146,12 @@ public final class BluetoothGatt implements BluetoothProfile {
* is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
* callback.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param characteristic Characteristic to read from the remote device
* @return true, if the read operation was initiated successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean readCharacteristic(BluetoothGattCharacteristic characteristic) {
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) == 0) {
return false;
@@ -1167,12 +1190,13 @@ public final class BluetoothGatt implements BluetoothProfile {
* is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
* callback.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param uuid UUID of characteristic to read from the remote device
* @return true, if the read operation was initiated successfully
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) {
if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid);
if (mService == null || mClientIf == 0) return false;
@@ -1202,11 +1226,12 @@ public final class BluetoothGatt implements BluetoothProfile {
* {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
* reporting the result of the operation.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param characteristic Characteristic to write on the remote device
* @return true, if the write operation was initiated successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
&& (characteristic.getProperties()
@@ -1248,11 +1273,12 @@ public final class BluetoothGatt implements BluetoothProfile {
* {@link BluetoothGattCallback#onDescriptorRead} callback is
* triggered, signaling the result of the operation.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param descriptor Descriptor value to read from the remote device
* @return true, if the read operation was initiated successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean readDescriptor(BluetoothGattDescriptor descriptor) {
if (VDBG) Log.d(TAG, "readDescriptor() - uuid: " + descriptor.getUuid());
if (mService == null || mClientIf == 0) return false;
@@ -1289,11 +1315,12 @@ public final class BluetoothGatt implements BluetoothProfile {
* <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is
* triggered to report the result of the write operation.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param descriptor Descriptor to write to the associated remote device
* @return true, if the write operation was initiated successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean writeDescriptor(BluetoothGattDescriptor descriptor) {
if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid());
if (mService == null || mClientIf == 0 || descriptor.getValue() == null) return false;
@@ -1340,10 +1367,11 @@ public final class BluetoothGatt implements BluetoothProfile {
* cancel the current transaction without committing any values on the
* remote device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the reliable write transaction has been initiated
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean beginReliableWrite() {
if (VDBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1367,10 +1395,11 @@ public final class BluetoothGatt implements BluetoothProfile {
* <p>A {@link BluetoothGattCallback#onReliableWriteCompleted} callback is
* invoked to indicate whether the transaction has been executed correctly.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the request to execute the transaction has been sent
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean executeReliableWrite() {
if (VDBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1396,9 +1425,10 @@ public final class BluetoothGatt implements BluetoothProfile {
*
* <p>Calling this function will discard all queued characteristic write
* operations for a given remote device.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void abortReliableWrite() {
if (VDBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return;
@@ -1414,6 +1444,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @deprecated Use {@link #abortReliableWrite()}
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void abortReliableWrite(BluetoothDevice mDevice) {
abortReliableWrite();
}
@@ -1426,12 +1457,13 @@ public final class BluetoothGatt implements BluetoothProfile {
* triggered if the remote device indicates that the given characteristic
* has changed.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param characteristic The characteristic for which to enable notifications
* @param enable Set to true to enable notifications/indications
* @return true, if the requested notification status was set successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enable) {
if (DBG) {
@@ -1464,6 +1496,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean refresh() {
if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1484,10 +1517,11 @@ public final class BluetoothGatt implements BluetoothProfile {
* <p>The {@link BluetoothGattCallback#onReadRemoteRssi} callback will be
* invoked when the RSSI value has been read.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the RSSI value has been requested successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean readRemoteRssi() {
if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
@@ -1512,10 +1546,11 @@ public final class BluetoothGatt implements BluetoothProfile {
* <p>A {@link BluetoothGattCallback#onMtuChanged} callback will indicate
* whether this operation was successful.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true, if the new MTU value has been requested successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean requestMtu(int mtu) {
if (DBG) {
Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
@@ -1544,6 +1579,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* or {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}.
* @throws IllegalArgumentException If the parameters are outside of their specified range.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean requestConnectionPriority(int connectionPriority) {
if (connectionPriority < CONNECTION_PRIORITY_BALANCED
|| connectionPriority > CONNECTION_PRIORITY_LOW_POWER) {
@@ -1571,6 +1607,7 @@ public final class BluetoothGatt implements BluetoothProfile {
* @return true, if the request is send to the Bluetooth stack.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean requestLeConnectionUpdate(int minConnectionInterval, int maxConnectionInterval,
int slaveLatency, int supervisionTimeout,
int minConnectionEventLen, int maxConnectionEventLen) {
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index 8f1b59cf69e6..8a7d4baf5add 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -237,7 +237,6 @@ public class BluetoothGattCharacteristic implements Parcelable {
/**
* Create a new BluetoothGattCharacteristic.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this characteristic
* @param properties Properties of this characteristic
@@ -344,7 +343,6 @@ public class BluetoothGattCharacteristic implements Parcelable {
/**
* Adds a descriptor to this characteristic.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param descriptor Descriptor to be added to this characteristic.
* @return true, if the descriptor was added to the characteristic
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java
index 49ba281e2eb7..ed5ea0873020 100644
--- a/core/java/android/bluetooth/BluetoothGattDescriptor.java
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java
@@ -128,7 +128,6 @@ public class BluetoothGattDescriptor implements Parcelable {
/**
* Create a new BluetoothGattDescriptor.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this descriptor
* @param permissions Permissions for this descriptor
@@ -139,7 +138,6 @@ public class BluetoothGattDescriptor implements Parcelable {
/**
* Create a new BluetoothGattDescriptor.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param characteristic The characteristic this descriptor belongs to
* @param uuid The UUID for this descriptor
@@ -228,8 +226,6 @@ public class BluetoothGattDescriptor implements Parcelable {
* <p>If a remote device offers multiple descriptors with the same UUID,
* the instance ID is used to distuinguish between descriptors.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return Instance ID of this descriptor
* @hide
*/
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 088b0169b631..fdb801850e8e 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -16,6 +16,9 @@
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;
@@ -425,6 +428,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
* Application should call this method as early as possible after it is done with
* this GATT server.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void close() {
if (DBG) Log.d(TAG, "close()");
unregisterCallback();
@@ -436,12 +440,13 @@ public final class BluetoothGattServer implements BluetoothProfile {
* <p>This is an asynchronous call. The callback is used to notify
* success or failure if the function returns true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @return true, the callback will be called to notify success or failure, false on immediate
* error
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
/*package*/ boolean registerCallback(BluetoothGattServerCallback callback) {
return registerCallback(callback, false);
}
@@ -452,14 +457,15 @@ public final class BluetoothGattServer implements BluetoothProfile {
* <p>This is an asynchronous call. The callback is used to notify
* success or failure if the function returns true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @param eatt_support indicates if server can use eatt
* @return true, the callback will be called to notify success or failure, false on immediate
* error
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
/*package*/ boolean registerCallback(BluetoothGattServerCallback callback,
boolean eatt_support) {
if (DBG) Log.d(TAG, "registerCallback()");
@@ -504,6 +510,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
/**
* Unregister the current application and callbacks.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void unregisterCallback() {
if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf);
if (mService == null || mServerIf == 0) return;
@@ -548,12 +555,13 @@ public final class BluetoothGattServer implements BluetoothProfile {
* subsequent connections to known devices should be invoked with the
* autoConnect parameter set to true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param autoConnect Whether to directly connect to the remote device (false) or to
* automatically connect as soon as the remote device becomes available (true).
* @return true, if the connection attempt was initiated successfully
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect(BluetoothDevice device, boolean autoConnect) {
if (DBG) {
Log.d(TAG,
@@ -576,10 +584,11 @@ public final class BluetoothGattServer implements BluetoothProfile {
* Disconnects an established connection, or cancels a connection attempt
* currently in progress.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Remote device
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void cancelConnection(BluetoothDevice device) {
if (DBG) Log.d(TAG, "cancelConnection() - device: " + device.getAddress());
if (mService == null || mServerIf == 0) return;
@@ -609,6 +618,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
* of {@link BluetoothDevice#PHY_OPTION_NO_PREFERRED}, {@link BluetoothDevice#PHY_OPTION_S2} or
* {@link BluetoothDevice#PHY_OPTION_S8}
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setPreferredPhy(BluetoothDevice device, int txPhy, int rxPhy, int phyOptions) {
try {
mService.serverSetPreferredPhy(mServerIf, device.getAddress(), txPhy, rxPhy,
@@ -624,6 +634,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
*
* @param device The remote device to send this response to
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void readPhy(BluetoothDevice device) {
try {
mService.serverReadPhy(mServerIf, device.getAddress());
@@ -645,14 +656,15 @@ public final class BluetoothGattServer implements BluetoothProfile {
* <li>{@link BluetoothGattServerCallback#onDescriptorWriteRequest}
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device The remote device to send this response to
* @param requestId The ID of the request that was received with the callback
* @param status The status of the request to be sent to the remote devices
* @param offset Value offset for partial read/write response
* @param value The value of the attribute that was read/written (optional)
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendResponse(BluetoothDevice device, int requestId,
int status, int offset, byte[] value) {
if (VDBG) Log.d(TAG, "sendResponse() - device: " + device.getAddress());
@@ -677,8 +689,6 @@ public final class BluetoothGattServer implements BluetoothProfile {
* for every client that requests notifications/indications by writing
* to the "Client Configuration" descriptor for the given characteristic.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device The remote device to receive the notification/indication
* @param characteristic The local characteristic that has been updated
* @param confirm true to request confirmation from the client (indication), false to send a
@@ -686,6 +696,9 @@ public final class BluetoothGattServer implements BluetoothProfile {
* @return true, if the notification has been triggered successfully
* @throws IllegalArgumentException
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean notifyCharacteristicChanged(BluetoothDevice device,
BluetoothGattCharacteristic characteristic, boolean confirm) {
if (VDBG) Log.d(TAG, "notifyCharacteristicChanged() - device: " + device.getAddress());
@@ -724,11 +737,12 @@ public final class BluetoothGattServer implements BluetoothProfile {
* whether this service has been added successfully. Do not add another service
* before this callback.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param service Service to be added to the list of services provided by this device.
* @return true, if the request to add service has been initiated
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean addService(BluetoothGattService service) {
if (DBG) Log.d(TAG, "addService() - service: " + service.getUuid());
if (mService == null || mServerIf == 0) return false;
@@ -748,11 +762,12 @@ public final class BluetoothGattServer implements BluetoothProfile {
/**
* Removes a service from the list of services to be provided.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param service Service to be removed.
* @return true, if the service has been removed
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean removeService(BluetoothGattService service) {
if (DBG) Log.d(TAG, "removeService() - service: " + service.getUuid());
if (mService == null || mServerIf == 0) return false;
@@ -774,8 +789,10 @@ public final class BluetoothGattServer implements BluetoothProfile {
/**
* Remove all services from the list of provided services.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void clearServices() {
if (DBG) Log.d(TAG, "clearServices()");
if (mService == null || mServerIf == 0) return;
@@ -794,10 +811,9 @@ public final class BluetoothGattServer implements BluetoothProfile {
* <p>An application must call {@link #addService} to add a serice to the
* list of services offered by this device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return List of services. Returns an empty list if no services have been added yet.
*/
+ @RequiresLegacyBluetoothPermission
public List<BluetoothGattService> getServices() {
return mServices;
}
@@ -809,12 +825,11 @@ public final class BluetoothGattServer implements BluetoothProfile {
* <p>If multiple instances of the same service (as identified by UUID)
* exist, the first instance of the service is returned.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param uuid UUID of the requested service
* @return BluetoothGattService if supported, or null if the requested service is not offered by
* this device.
*/
+ @RequiresLegacyBluetoothPermission
public BluetoothGattService getService(UUID uuid) {
for (BluetoothGattService service : mServices) {
if (service.getUuid().equals(uuid)) {
diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java
index 23dc7c830855..f64d09fc30d9 100644
--- a/core/java/android/bluetooth/BluetoothGattService.java
+++ b/core/java/android/bluetooth/BluetoothGattService.java
@@ -15,6 +15,9 @@
*/
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -98,7 +101,6 @@ public class BluetoothGattService implements Parcelable {
/**
* Create a new BluetoothGattService.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param uuid The UUID for this service
* @param serviceType The type of this service,
@@ -225,11 +227,11 @@ public class BluetoothGattService implements Parcelable {
/**
* Add an included service to this service.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param service The service to be added
* @return true, if the included service was added to the service
*/
+ @RequiresLegacyBluetoothPermission
public boolean addService(BluetoothGattService service) {
mIncludedServices.add(service);
return true;
@@ -237,11 +239,11 @@ public class BluetoothGattService implements Parcelable {
/**
* Add a characteristic to this service.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param characteristic The characteristics to be added
* @return true, if the characteristic was added to the service
*/
+ @RequiresLegacyBluetoothPermission
public boolean addCharacteristic(BluetoothGattCharacteristic characteristic) {
mCharacteristics.add(characteristic);
characteristic.setService(this);
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 632572dea3c6..84e8c5134e7b 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -22,6 +22,9 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
@@ -70,10 +73,10 @@ public final class BluetoothHeadset implements BluetoothProfile {
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission 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.headset.profile.action.CONNECTION_STATE_CHANGED";
@@ -90,10 +93,10 @@ public final class BluetoothHeadset implements BluetoothProfile {
* </ul>
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_AUDIO_CONNECTED}, {@link #STATE_AUDIO_DISCONNECTED},
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission
- * to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_AUDIO_STATE_CHANGED =
"android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
@@ -107,11 +110,11 @@ public final class BluetoothHeadset implements BluetoothProfile {
* be null if no device is active. </li>
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@UnsupportedAppUsage(trackingBug = 171933273)
public static final String ACTION_ACTIVE_DEVICE_CHANGED =
@@ -147,9 +150,10 @@ public final class BluetoothHeadset implements BluetoothProfile {
* <li> EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE = AT_CMD_TYPE_SET </li>
* <li> EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS = foo, 3 </li>
* </ul>
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission
- * to receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT =
"android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
@@ -299,10 +303,12 @@ public final class BluetoothHeadset implements BluetoothProfile {
* are given an assigned number. Below shows the assigned number of Indicator added so far
* - Enhanced Safety - 1, Valid Values: 0 - Disabled, 1 - Enabled
* - Battery Level - 2, Valid Values: 0~100 - Remaining level of Battery
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to receive.
*
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public static final String ACTION_HF_INDICATORS_VALUE_CHANGED =
"android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED";
@@ -432,15 +438,17 @@ public final class BluetoothHeadset implements BluetoothProfile {
* the state. Users can get the connection state of the profile
* from this intent.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
final IBluetoothHeadset service = mService;
@@ -474,15 +482,14 @@ public final class BluetoothHeadset implements BluetoothProfile {
* {@link #STATE_DISCONNECTING} can be used to distinguish between the
* two scenarios.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothHeadset service = mService;
@@ -502,6 +509,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
final IBluetoothHeadset service = mService;
@@ -521,6 +529,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothHeadset service = mService;
@@ -540,6 +549,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getConnectionState(" + device + ")");
final IBluetoothHeadset service = mService;
@@ -571,7 +581,12 @@ public final class BluetoothHeadset implements BluetoothProfile {
*/
@Deprecated
@SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
final IBluetoothHeadset service = mService;
@@ -605,7 +620,11 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @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 setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -638,7 +657,9 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
final IBluetoothHeadset service = mService;
@@ -688,7 +709,9 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @param device Bluetooth device
* @return true if echo cancellation and/or noise reduction is supported, false otherwise
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isNoiseReductionSupported(@NonNull BluetoothDevice device) {
if (DBG) log("isNoiseReductionSupported()");
final IBluetoothHeadset service = mService;
@@ -709,7 +732,9 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @param device Bluetooth device
* @return true if voice recognition is supported, false otherwise
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isVoiceRecognitionSupported(@NonNull BluetoothDevice device) {
if (DBG) log("isVoiceRecognitionSupported()");
final IBluetoothHeadset service = mService;
@@ -738,13 +763,17 @@ public final class BluetoothHeadset implements BluetoothProfile {
* audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED}
* in case of failure to establish the audio connection.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Bluetooth headset
* @return false if there is no headset connected, or the connected headset doesn't support
* voice recognition, or voice recognition is already started, or audio channel is occupied,
* or on error, true otherwise
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public boolean startVoiceRecognition(BluetoothDevice device) {
if (DBG) log("startVoiceRecognition()");
final IBluetoothHeadset service = mService;
@@ -767,12 +796,13 @@ public final class BluetoothHeadset implements BluetoothProfile {
* If this function returns true, this intent will be broadcasted with
* {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Bluetooth headset
* @return false if there is no headset connected, or voice recognition has not started,
* or voice recognition has ended on this headset, or on error, true otherwise
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean stopVoiceRecognition(BluetoothDevice device) {
if (DBG) log("stopVoiceRecognition()");
final IBluetoothHeadset service = mService;
@@ -790,11 +820,12 @@ public final class BluetoothHeadset implements BluetoothProfile {
/**
* Check if Bluetooth SCO audio is connected.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Bluetooth headset
* @return true if SCO is connected, false otherwise or on error
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isAudioConnected(BluetoothDevice device) {
if (VDBG) log("isAudioConnected()");
final IBluetoothHeadset service = mService;
@@ -827,6 +858,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getAudioState(BluetoothDevice device) {
if (VDBG) log("getAudioState");
final IBluetoothHeadset service = mService;
@@ -853,6 +885,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @param allowed {@code true} if the profile can reroute audio, {@code false} otherwise.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setAudioRouteAllowed(boolean allowed) {
if (VDBG) log("setAudioRouteAllowed");
final IBluetoothHeadset service = mService;
@@ -874,6 +907,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean getAudioRouteAllowed() {
if (VDBG) log("getAudioRouteAllowed");
final IBluetoothHeadset service = mService;
@@ -897,6 +931,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* False to use SCO audio in normal manner
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void setForceScoAudio(boolean forced) {
if (VDBG) log("setForceScoAudio " + String.valueOf(forced));
final IBluetoothHeadset service = mService;
@@ -915,12 +950,13 @@ public final class BluetoothHeadset implements BluetoothProfile {
/**
* Check if at least one headset's SCO audio is connected or connecting
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @return true if at least one device's SCO audio is connected or connecting, false otherwise
* or on error
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isAudioOn() {
if (VDBG) log("isAudioOn()");
final IBluetoothHeadset service = mService;
@@ -955,6 +991,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connectAudio() {
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
@@ -982,6 +1019,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnectAudio() {
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
@@ -1018,7 +1056,12 @@ public final class BluetoothHeadset implements BluetoothProfile {
* - binder is dead or Bluetooth is disabled or other error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
@UnsupportedAppUsage
public boolean startScoUsingVirtualVoiceCall() {
if (DBG) log("startScoUsingVirtualVoiceCall()");
@@ -1048,7 +1091,12 @@ public final class BluetoothHeadset implements BluetoothProfile {
* - binder is dead or Bluetooth is disabled or other error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
@UnsupportedAppUsage
public boolean stopScoUsingVirtualVoiceCall() {
if (DBG) log("stopScoUsingVirtualVoiceCall()");
@@ -1075,6 +1123,10 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public void phoneStateChanged(int numActive, int numHeld, int callState, String number,
int type, String name) {
final IBluetoothHeadset service = mService;
@@ -1095,6 +1147,10 @@ public final class BluetoothHeadset implements BluetoothProfile {
*
* @hide
*/
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
public void clccResponse(int index, int direction, int status, int mode, boolean mpty,
String number, int type) {
final IBluetoothHeadset service = mService;
@@ -1119,8 +1175,6 @@ public final class BluetoothHeadset implements BluetoothProfile {
*
* <p>Currently only {@link #VENDOR_RESULT_CODE_COMMAND_ANDROID} is allowed as {@code command}.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device Bluetooth headset.
* @param command A vendor-specific command.
* @param arg The argument that will be attached to the command.
@@ -1128,6 +1182,9 @@ public final class BluetoothHeadset implements BluetoothProfile {
* vendor-specific unsolicited result code, or on error. {@code true} otherwise.
* @throws IllegalArgumentException if {@code command} is {@code null}.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendVendorSpecificResultCode(BluetoothDevice device, String command,
String arg) {
if (DBG) {
@@ -1164,15 +1221,17 @@ public final class BluetoothHeadset implements BluetoothProfile {
* {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
* with the active device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
- *
* @param device Remote Bluetooth Device, could be null if phone call audio should not be
* streamed to a headset
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.MODIFY_PHONE_STATE,
+ })
@UnsupportedAppUsage(trackingBug = 171933273)
public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) {
@@ -1201,7 +1260,9 @@ public final class BluetoothHeadset implements BluetoothProfile {
*/
@UnsupportedAppUsage(trackingBug = 171933273)
@Nullable
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothDevice getActiveDevice() {
if (VDBG) {
Log.d(TAG, "getActiveDevice");
@@ -1227,7 +1288,9 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @return true if in-band ringing is enabled, false if in-band ringing is disabled
* @hide
*/
- @RequiresPermission(android.Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isInbandRingingEnabled() {
if (DBG) {
log("isInbandRingingEnabled()");
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index e5b2a1e23cc1..092130d0ce91 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -19,6 +19,8 @@ package android.bluetooth;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Binder;
@@ -447,6 +449,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
final IBluetoothHeadsetClient service =
@@ -473,6 +476,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothHeadsetClient service =
@@ -495,6 +499,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return list of connected devices; empty list if nothing is connected.
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
final IBluetoothHeadsetClient service =
@@ -519,6 +524,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* list if nothing matches the <code>states</code>
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothHeadsetClient service =
@@ -542,6 +548,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return the state of connection of the device
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getConnectionState(" + device + ")");
final IBluetoothHeadsetClient service =
@@ -569,7 +576,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -587,7 +594,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -619,7 +626,9 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -636,7 +645,9 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return connection policy of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothHeadsetClient service =
@@ -664,6 +675,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* #EXTRA_AG_FEATURE_VOICE_RECOGNITION}. This method invocation will fail silently when feature
* is not supported.</p>
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean startVoiceRecognition(BluetoothDevice device) {
if (DBG) log("startVoiceRecognition()");
final IBluetoothHeadsetClient service =
@@ -688,6 +700,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return <code>true</code> if command has been issued successfully; <code>false</code>
* otherwise.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId,
String atCommand) {
if (DBG) log("sendVendorSpecificCommand()");
@@ -715,6 +728,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* #EXTRA_AG_FEATURE_VOICE_RECOGNITION}. This method invocation will fail silently when feature
* is not supported.</p>
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean stopVoiceRecognition(BluetoothDevice device) {
if (DBG) log("stopVoiceRecognition()");
final IBluetoothHeadsetClient service =
@@ -736,6 +750,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @param device remote device
* @return list of calls; empty list if none call exists
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) {
if (DBG) log("getCurrentCalls()");
final IBluetoothHeadsetClient service =
@@ -757,6 +772,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @param device remote device
* @return bundle of AG indicators; null if device is not in CONNECTED state
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public Bundle getCurrentAgEvents(BluetoothDevice device) {
if (DBG) log("getCurrentCalls()");
final IBluetoothHeadsetClient service =
@@ -782,6 +798,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean acceptCall(BluetoothDevice device, int flag) {
if (DBG) log("acceptCall()");
final IBluetoothHeadsetClient service =
@@ -804,6 +821,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return <code>true</code> if command has been issued successfully; <code>false</code>
* otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean holdCall(BluetoothDevice device) {
if (DBG) log("holdCall()");
final IBluetoothHeadsetClient service =
@@ -831,6 +849,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* supported.</p>
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean rejectCall(BluetoothDevice device) {
if (DBG) log("rejectCall()");
final IBluetoothHeadsetClient service =
@@ -862,6 +881,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* #EXTRA_AG_FEATURE_ECC}. This method invocation will fail silently when feature is not
* supported.</p>
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) {
if (DBG) log("terminateCall()");
final IBluetoothHeadsetClient service =
@@ -891,6 +911,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* #EXTRA_AG_FEATURE_ECC}. This method invocation will fail silently when feature is not
* supported.</p>
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean enterPrivateMode(BluetoothDevice device, int index) {
if (DBG) log("enterPrivateMode()");
final IBluetoothHeadsetClient service =
@@ -919,6 +940,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* #EXTRA_AG_FEATURE_MERGE_AND_DETACH}. This method invocation will fail silently when feature
* is not supported.</p>
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean explicitCallTransfer(BluetoothDevice device) {
if (DBG) log("explicitCallTransfer()");
final IBluetoothHeadsetClient service =
@@ -943,6 +965,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* successfully; <code>{@link null}</code> otherwise; upon completion HFP sends {@link
* #ACTION_CALL_CHANGED} intent in case of success; {@link #ACTION_RESULT} is sent otherwise;
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) {
if (DBG) log("dial()");
final IBluetoothHeadsetClient service =
@@ -968,6 +991,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return <code>true</code> if command has been issued successfully; <code>false</code>
* otherwise; upon completion HFP sends {@link #ACTION_RESULT} intent;
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendDTMF(BluetoothDevice device, byte code) {
if (DBG) log("sendDTMF()");
final IBluetoothHeadsetClient service =
@@ -1089,6 +1113,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return <code>true</code> if command has been issued successfully; <code>false</code>
* otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent;
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connectAudio(BluetoothDevice device) {
final IBluetoothHeadsetClient service =
getService();
@@ -1114,6 +1139,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @return <code>true</code> if command has been issued successfully; <code>false</code>
* otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent;
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnectAudio(BluetoothDevice device) {
final IBluetoothHeadsetClient service =
getService();
@@ -1136,6 +1162,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
* @param device remote device
* @return bundle of AG features; null if no service or AG not connected
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public Bundle getCurrentAgFeatures(BluetoothDevice device) {
final IBluetoothHeadsetClient service =
getService();
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 5fd60e001693..65f68a943e08 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -16,6 +16,10 @@
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.os.ParcelFileDescriptor;
import android.util.Log;
@@ -111,8 +115,6 @@ public final class BluetoothHealth implements BluetoothProfile {
* which will act as the {@link #SOURCE_ROLE}. This is an asynchronous call and so
* the callback is used to notify success or failure if the function returns true.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param name The friendly name associated with the application or configuration.
* @param dataType The dataType of the Source role of Health Profile to which the sink wants to
* connect to.
@@ -126,6 +128,10 @@ public final class BluetoothHealth implements BluetoothProfile {
* {@link BluetoothDevice#createL2capChannel(int)}
*/
@Deprecated
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public boolean registerSinkAppConfiguration(String name, int dataType,
BluetoothHealthCallback callback) {
Log.e(TAG, "registerSinkAppConfiguration(): BluetoothHealth is deprecated");
@@ -136,8 +142,6 @@ public final class BluetoothHealth implements BluetoothProfile {
* Unregister an application configuration that has been registered using
* {@link #registerSinkAppConfiguration}
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param config The health app configuration
* @return Success or failure.
*
@@ -147,6 +151,10 @@ public final class BluetoothHealth implements BluetoothProfile {
* {@link BluetoothDevice#createL2capChannel(int)}
*/
@Deprecated
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
Log.e(TAG, "unregisterAppConfiguration(): BluetoothHealth is deprecated");
return false;
@@ -157,8 +165,6 @@ public final class BluetoothHealth implements BluetoothProfile {
* This is an asynchronous call. If this function returns true, the callback
* associated with the application configuration will be called.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device The remote Bluetooth device.
* @param config The application configuration which has been registered using {@link
* #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
@@ -170,6 +176,10 @@ public final class BluetoothHealth implements BluetoothProfile {
* {@link BluetoothDevice#createL2capChannel(int)}
*/
@Deprecated
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public boolean connectChannelToSource(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
Log.e(TAG, "connectChannelToSource(): BluetoothHealth is deprecated");
@@ -181,8 +191,6 @@ public final class BluetoothHealth implements BluetoothProfile {
* This is an asynchronous call. If this function returns true, the callback
* associated with the application configuration will be called.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* @param device The remote Bluetooth device.
* @param config The application configuration which has been registered using {@link
* #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
@@ -195,6 +203,10 @@ public final class BluetoothHealth implements BluetoothProfile {
* {@link BluetoothDevice#createL2capChannel(int)}
*/
@Deprecated
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public boolean disconnectChannel(BluetoothDevice device,
BluetoothHealthAppConfiguration config, int channelId) {
Log.e(TAG, "disconnectChannel(): BluetoothHealth is deprecated");
@@ -205,8 +217,6 @@ public final class BluetoothHealth implements BluetoothProfile {
* Get the file descriptor of the main channel associated with the remote device
* and application configuration.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* <p> Its the responsibility of the caller to close the ParcelFileDescriptor
* when done.
*
@@ -220,6 +230,10 @@ public final class BluetoothHealth implements BluetoothProfile {
* {@link BluetoothDevice#createL2capChannel(int)}
*/
@Deprecated
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
Log.e(TAG, "getMainChannelFd(): BluetoothHealth is deprecated");
@@ -229,8 +243,6 @@ public final class BluetoothHealth implements BluetoothProfile {
/**
* Get the current connection state of the profile.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* This is not specific to any application configuration but represents the connection
* state of the local Bluetooth adapter with the remote device. This can be used
* by applications like status bar which would just like to know the state of the
@@ -241,6 +253,10 @@ public final class BluetoothHealth implements BluetoothProfile {
* #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
*/
@Override
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public int getConnectionState(BluetoothDevice device) {
Log.e(TAG, "getConnectionState(): BluetoothHealth is deprecated");
return STATE_DISCONNECTED;
@@ -251,8 +267,6 @@ public final class BluetoothHealth implements BluetoothProfile {
*
* <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* This is not specific to any application configuration but represents the connection
* state of the local Bluetooth adapter for this profile. This can be used
* by applications like status bar which would just like to know the state of the
@@ -261,6 +275,10 @@ public final class BluetoothHealth implements BluetoothProfile {
* @return List of devices. The list will be empty on error.
*/
@Override
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public List<BluetoothDevice> getConnectedDevices() {
Log.e(TAG, "getConnectedDevices(): BluetoothHealth is deprecated");
return new ArrayList<>();
@@ -273,8 +291,7 @@ public final class BluetoothHealth implements BluetoothProfile {
* <p> If none of the devices match any of the given states,
* an empty list will be returned.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- * This is not specific to any application configuration but represents the connection
+ * <p>This is not specific to any application configuration but represents the connection
* state of the local Bluetooth adapter for this profile. This can be used
* by applications like status bar which would just like to know the state of the
* local adapter.
@@ -284,6 +301,10 @@ public final class BluetoothHealth implements BluetoothProfile {
* @return List of devices. The list will be empty on error.
*/
@Override
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Log.e(TAG, "getDevicesMatchingConnectionStates(): BluetoothHealth is deprecated");
return new ArrayList<>();
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index ff78825e0f96..8ceeff53b130 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -22,6 +22,9 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -64,10 +67,10 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission 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.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
@@ -81,11 +84,11 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* be null if no device is active. </li>
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_ACTIVE_DEVICE_CHANGED =
@@ -167,7 +170,10 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
final IBluetoothHearingAid service = getService();
@@ -225,6 +231,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
final IBluetoothHearingAid service = getService();
@@ -244,6 +251,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
@NonNull int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
@@ -264,6 +272,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @BluetoothProfile.BtProfileState int getConnectionState(
@NonNull BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
@@ -295,14 +304,14 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
* with the active device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
- *
* @param device the remote Bluetooth device. Could be null to clear
* the active device and stop streaming audio to a Bluetooth device.
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) log("setActiveDevice(" + device + ")");
@@ -330,7 +339,9 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getActiveDevices() {
if (VDBG) log("getActiveDevices()");
final IBluetoothHearingAid service = getService();
@@ -357,7 +368,10 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -376,7 +390,10 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -531,7 +548,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* @return SIDE_LEFT or SIDE_RIGHT
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
public int getDeviceSide(BluetoothDevice device) {
if (VDBG) {
log("getDeviceSide(" + device + ")");
@@ -557,7 +574,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
* @return MODE_MONAURAL or MODE_BINAURAL
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
public int getDeviceMode(BluetoothDevice device) {
if (VDBG) {
log("getDeviceMode(" + device + ")");
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index 2baa73822c9c..c214d2b85ac5 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -21,6 +21,8 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.Binder;
@@ -56,9 +58,10 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link
* #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link
* #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission 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.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
@@ -436,6 +439,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
/** {@inheritDoc} */
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
final IBluetoothHidDevice service = getService();
if (service != null) {
@@ -453,6 +457,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
/** {@inheritDoc} */
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
final IBluetoothHidDevice service = getService();
if (service != null) {
@@ -470,6 +475,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
/** {@inheritDoc} */
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
final IBluetoothHidDevice service = getService();
if (service != null) {
@@ -508,6 +514,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* object is required.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean registerApp(
BluetoothHidDeviceAppSdpSettings sdp,
BluetoothHidDeviceAppQosSettings inQos,
@@ -553,6 +560,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
*
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean unregisterApp() {
boolean result = false;
@@ -578,6 +586,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @param data Report data, not including Report Id.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
boolean result = false;
@@ -604,6 +613,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @param data Report data, not including Report Id.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
boolean result = false;
@@ -628,6 +638,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @param error Error to be sent for SET_REPORT via HANDSHAKE.
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean reportError(BluetoothDevice device, byte error) {
boolean result = false;
@@ -651,6 +662,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @return the current user name, or empty string if cannot get the name
* {@hide}
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public String getUserAppName() {
final IBluetoothHidDevice service = getService();
@@ -675,6 +687,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
*
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect(BluetoothDevice device) {
boolean result = false;
@@ -699,6 +712,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
*
* @return true if the command is successfully sent; otherwise false.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
boolean result = false;
@@ -734,7 +748,10 @@ public final class BluetoothHidDevice implements BluetoothProfile {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java
index 9561d9383846..70e3809cb590 100644
--- a/core/java/android/bluetooth/BluetoothHidHost.java
+++ b/core/java/android/bluetooth/BluetoothHidHost.java
@@ -21,6 +21,9 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.content.Context;
@@ -65,11 +68,11 @@ public final class BluetoothHidHost implements BluetoothProfile {
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
@SuppressLint("ActionValue")
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
@@ -328,7 +331,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/
@SystemApi
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
final IBluetoothHidHost service = getService();
@@ -350,6 +353,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothHidHost service = getService();
@@ -372,7 +376,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
*/
@SystemApi
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(@NonNull BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
if (device == null) {
@@ -503,12 +507,13 @@ public final class BluetoothHidHost implements BluetoothProfile {
/**
* Initiate virtual unplug for a HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean virtualUnplug(BluetoothDevice device) {
if (DBG) log("virtualUnplug(" + device + ")");
final IBluetoothHidHost service = getService();
@@ -529,12 +534,13 @@ public final class BluetoothHidHost implements BluetoothProfile {
/**
* Send Get_Protocol_Mode command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean getProtocolMode(BluetoothDevice device) {
if (VDBG) log("getProtocolMode(" + device + ")");
final IBluetoothHidHost service = getService();
@@ -553,12 +559,13 @@ public final class BluetoothHidHost implements BluetoothProfile {
/**
* Send Set_Protocol_Mode command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
if (DBG) log("setProtocolMode(" + device + ")");
final IBluetoothHidHost service = getService();
@@ -577,8 +584,6 @@ public final class BluetoothHidHost implements BluetoothProfile {
/**
* Send Get_Report command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @param reportType Report type
* @param reportId Report ID
@@ -586,6 +591,9 @@ public final class BluetoothHidHost implements BluetoothProfile {
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean getReport(BluetoothDevice device, byte reportType, byte reportId,
int bufferSize) {
if (VDBG) {
@@ -608,14 +616,15 @@ public final class BluetoothHidHost implements BluetoothProfile {
/**
* Send Set_Report command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @param reportType Report type
* @param report Report receiving buffer size
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setReport(BluetoothDevice device, byte reportType, String report) {
if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
final IBluetoothHidHost service = getService();
@@ -634,13 +643,14 @@ public final class BluetoothHidHost implements BluetoothProfile {
/**
* Send Send_Data command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @param report Report to send
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean sendData(BluetoothDevice device, String report) {
if (DBG) log("sendData(" + device + "), report=" + report);
final IBluetoothHidHost service = getService();
@@ -659,12 +669,13 @@ public final class BluetoothHidHost implements BluetoothProfile {
/**
* Send Get_Idle_Time command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean getIdleTime(BluetoothDevice device) {
if (DBG) log("getIdletime(" + device + ")");
final IBluetoothHidHost service = getService();
@@ -683,13 +694,14 @@ public final class BluetoothHidHost implements BluetoothProfile {
/**
* Send Set_Idle_Time command to the connected HID input device.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
* @param device Remote Bluetooth Device
* @param idleTime Idle time to be set on HID Device
* @return false on immediate error, true otherwise
* @hide
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
final IBluetoothHidHost service = getService();
diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
index 3f00fa6f4181..4f095f6c7001 100644
--- a/core/java/android/bluetooth/BluetoothLeAudio.java
+++ b/core/java/android/bluetooth/BluetoothLeAudio.java
@@ -23,6 +23,9 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -65,10 +68,10 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED =
"android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
@@ -82,11 +85,11 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* be null if no device is active. </li>
* </ul>
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED =
"android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED";
@@ -122,7 +125,6 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
/**
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public void close() {
mProfileConnector.disconnect();
}
@@ -131,7 +133,6 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
return mProfileConnector.getService();
}
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
protected void finalize() {
if (mCloseGuard != null) {
mCloseGuard.warnIfOpen();
@@ -154,7 +155,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean connect(@Nullable BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
try {
@@ -193,7 +194,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(@Nullable BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
try {
@@ -213,6 +214,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
try {
@@ -232,6 +234,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
@NonNull int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
@@ -252,7 +255,9 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* {@inheritDoc}
*/
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
try {
@@ -289,7 +294,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @return false on immediate error, true otherwise
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) log("setActiveDevice(" + device + ")");
try {
@@ -314,7 +319,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @hide
*/
@NonNull
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
public List<BluetoothDevice> getActiveDevices() {
if (VDBG) log("getActiveDevices()");
try {
@@ -337,7 +342,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @return group id that this device currently belongs to
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
public int getGroupId(@NonNull BluetoothDevice device) {
if (VDBG) log("getGroupId()");
try {
@@ -365,7 +370,10 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -398,7 +406,7 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
* @return connection policy of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
try {
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index d5c1c3e2d61e..a1e1b6305083 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -20,6 +20,8 @@ import android.Manifest;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.IBinder;
@@ -109,7 +111,9 @@ public final class BluetoothManager {
* {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED},
* {@link BluetoothProfile#STATE_DISCONNECTING}
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device, int profile) {
if (DBG) Log.d(TAG, "getConnectionState()");
@@ -136,7 +140,9 @@ public final class BluetoothManager {
* @param profile GATT or GATT_SERVER
* @return List of devices. The list will be empty on error.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices(int profile) {
if (DBG) Log.d(TAG, "getConnectedDevices");
if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) {
@@ -177,7 +183,9 @@ public final class BluetoothManager {
* {@link BluetoothProfile#STATE_DISCONNECTING},
* @return List of devices. The list will be empty on error.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int profile, int[] states) {
if (DBG) Log.d(TAG, "getDevicesMatchingConnectionStates");
@@ -210,6 +218,7 @@ public final class BluetoothManager {
* @param callback GATT server callback handler that will receive asynchronous callbacks.
* @return BluetoothGattServer instance
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback) {
@@ -229,6 +238,7 @@ public final class BluetoothManager {
* @return BluetoothGattServer instance
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback, boolean eatt_support) {
return (openGattServer(context, callback, BluetoothDevice.TRANSPORT_AUTO, eatt_support));
@@ -249,6 +259,7 @@ public final class BluetoothManager {
* @return BluetoothGattServer instance
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback, int transport) {
return (openGattServer(context, callback, transport, false));
@@ -270,6 +281,7 @@ public final class BluetoothManager {
* @return BluetoothGattServer instance
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothGattServer openGattServer(Context context,
BluetoothGattServerCallback callback, int transport, boolean eatt_support) {
if (context == null || callback == null) {
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 35549954007e..3e7b75aa1f62 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -93,7 +93,6 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
mCloseGuard.open("close");
}
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
protected void finalize() {
if (mCloseGuard != null) {
mCloseGuard.warnIfOpen();
@@ -110,7 +109,6 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public void close() {
if (VDBG) log("close()");
mProfileConnector.disconnect();
@@ -128,6 +126,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getState() {
if (VDBG) log("getState()");
final IBluetoothMap service = getService();
@@ -152,6 +151,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothDevice getClient() {
if (VDBG) log("getClient()");
final IBluetoothMap service = getService();
@@ -175,6 +175,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isConnected(BluetoothDevice device) {
if (VDBG) log("isConnected(" + device + ")");
final IBluetoothMap service = getService();
@@ -211,6 +212,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothMap service = getService();
@@ -257,7 +259,10 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (DBG) log("getConnectedDevices()");
final IBluetoothMap service = getService();
@@ -280,6 +285,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
*
* @hide
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) log("getDevicesMatchingStates()");
final IBluetoothMap service = getService();
@@ -302,6 +308,7 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
*
* @hide
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) log("getConnectionState(" + device + ")");
final IBluetoothMap service = getService();
@@ -328,7 +335,10 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -347,7 +357,10 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -378,7 +391,10 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -396,7 +412,10 @@ public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothMap service = getService();
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 0312a2190a4b..db74a90f603b 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -192,6 +192,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* currently connected to the Map service.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isConnected(BluetoothDevice device) {
if (VDBG) Log.d(TAG, "isConnected(" + device + ")");
final IBluetoothMapClient service = getService();
@@ -214,7 +215,10 @@ public final class BluetoothMapClient implements BluetoothProfile {
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean connect(BluetoothDevice device) {
if (DBG) Log.d(TAG, "connect(" + device + ")" + "for MAPS MCE");
final IBluetoothMapClient service = getService();
@@ -239,7 +243,10 @@ public final class BluetoothMapClient implements BluetoothProfile {
*
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean disconnect(BluetoothDevice device) {
if (DBG) Log.d(TAG, "disconnect(" + device + ")");
final IBluetoothMapClient service = getService();
@@ -261,6 +268,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (DBG) Log.d(TAG, "getConnectedDevices()");
final IBluetoothMapClient service = getService();
@@ -283,6 +291,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) Log.d(TAG, "getDevicesMatchingStates()");
final IBluetoothMapClient service = getService();
@@ -305,6 +314,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getConnectionState(" + device + ")");
final IBluetoothMapClient service = getService();
@@ -331,7 +341,10 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) Log.d(TAG, "setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -349,7 +362,10 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) Log.d(TAG, "setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -380,7 +396,10 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public int getPriority(BluetoothDevice device) {
if (VDBG) Log.d(TAG, "getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -397,7 +416,10 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return connection policy of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
if (VDBG) Log.d(TAG, "getConnectionPolicy(" + device + ")");
final IBluetoothMapClient service = getService();
@@ -427,7 +449,10 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.SEND_SMS)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.SEND_SMS,
+ })
public boolean sendMessage(@NonNull BluetoothDevice device, @NonNull Collection<Uri> contacts,
@NonNull String message, @Nullable PendingIntent sentIntent,
@Nullable PendingIntent deliveredIntent) {
@@ -459,6 +484,10 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.SEND_SMS,
+ })
public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message,
PendingIntent sentIntent, PendingIntent deliveredIntent) {
if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message);
@@ -481,6 +510,10 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return true if the message is enqueued, false on error
* @hide
*/
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.READ_SMS,
+ })
public boolean getUnreadMessages(BluetoothDevice device) {
if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")");
final IBluetoothMapClient service = getService();
@@ -503,6 +536,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
* MapSupportedFeatures field is set. False is returned otherwise.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isUploadingSupported(BluetoothDevice device) {
final IBluetoothMapClient service = getService();
try {
@@ -530,7 +564,10 @@ public final class BluetoothMapClient implements BluetoothProfile {
* @return <code>true</code> if request has been sent, <code>false</code> on error
* @hide
*/
- @RequiresPermission(Manifest.permission.READ_SMS)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.READ_SMS,
+ })
public boolean setMessageStatus(BluetoothDevice device, String handle, int status) {
if (DBG) Log.d(TAG, "setMessageStatus(" + device + ", " + handle + ", " + status + ")");
final IBluetoothMapClient service = getService();
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index ecd718cec32b..b3924b1fa920 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -22,6 +22,8 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -74,10 +76,11 @@ public final class BluetoothPan implements BluetoothProfile {
*
* <p> {@link #EXTRA_LOCAL_ROLE} can be one of {@link #LOCAL_NAP_ROLE} or
* {@link #LOCAL_PANU_ROLE}
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
@SuppressLint("ActionValue")
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
@@ -102,9 +105,10 @@ public final class BluetoothPan implements BluetoothProfile {
*
* <p> {@link #EXTRA_TETHERING_STATE} can be any of {@link #TETHERING_STATE_OFF} or
* {@link #TETHERING_STATE_ON}
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_TETHERING_STATE_CHANGED =
"android.bluetooth.action.TETHERING_STATE_CHANGED";
@@ -236,6 +240,10 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
final IBluetoothPan service = getService();
@@ -274,6 +282,7 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothPan service = getService();
@@ -302,7 +311,10 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -330,7 +342,10 @@ public final class BluetoothPan implements BluetoothProfile {
*/
@SystemApi
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @NonNull List<BluetoothDevice> getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
final IBluetoothPan service = getService();
@@ -351,7 +366,12 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@Override
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothPan service = getService();
@@ -396,7 +416,11 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ })
public void setBluetoothTethering(boolean value) {
String pkgName = mContext.getOpPackageName();
if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName);
@@ -417,7 +441,7 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isTetheringOn() {
if (VDBG) log("isTetheringOn()");
final IBluetoothPan service = getService();
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index 6e5c45f3d129..6c2e5bf2d391 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -22,6 +22,8 @@ import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -82,8 +84,6 @@ public class BluetoothPbap implements BluetoothProfile {
* can be any of {@link BluetoothProfile#STATE_DISCONNECTED},
* {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED},
* {@link BluetoothProfile#STATE_DISCONNECTING}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
*
* @hide
*/
@@ -142,6 +142,7 @@ public class BluetoothPbap implements BluetoothProfile {
doBind();
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
boolean doBind() {
synchronized (mConnection) {
try {
@@ -216,6 +217,7 @@ public class BluetoothPbap implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
log("getConnectedDevices()");
final IBluetoothPbap service = mService;
@@ -262,6 +264,7 @@ public class BluetoothPbap implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
log("getDevicesMatchingConnectionStates: states=" + Arrays.toString(states));
final IBluetoothPbap service = mService;
@@ -294,7 +297,10 @@ public class BluetoothPbap implements BluetoothProfile {
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -324,6 +330,7 @@ public class BluetoothPbap implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
log("disconnect()");
final IBluetoothPbap service = mService;
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index f356da18fc73..2c8fbc2509ff 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -19,6 +19,7 @@ package android.bluetooth;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -160,6 +161,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
* @return list of connected devices
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (DBG) {
log("getConnectedDevices()");
@@ -185,6 +187,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
* @return list of matching devices
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) {
log("getDevicesMatchingStates()");
@@ -210,6 +213,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
* @return device connection state
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) {
log("getConnectionState(" + device + ")");
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 201d6c495d98..70053ee71491 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -14,12 +14,9 @@
* limitations under the License.
*/
-
package android.bluetooth;
-import android.Manifest;
import android.annotation.IntDef;
-import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -300,7 +297,6 @@ public interface BluetoothProfile {
*
* @return List of devices. The list will be empty on error.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
public List<BluetoothDevice> getConnectedDevices();
/**
@@ -314,7 +310,6 @@ public interface BluetoothProfile {
* #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
* @return List of devices. The list will be empty on error.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states);
/**
@@ -324,7 +319,6 @@ public interface BluetoothProfile {
* @return State of the profile connection. One of {@link #STATE_CONNECTED}, {@link
* #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH)
@BtProfileState int getConnectionState(BluetoothDevice device);
/**
diff --git a/core/java/android/bluetooth/BluetoothProfileConnector.java b/core/java/android/bluetooth/BluetoothProfileConnector.java
index 863fd3698cbd..12abcc4d11da 100644
--- a/core/java/android/bluetooth/BluetoothProfileConnector.java
+++ b/core/java/android/bluetooth/BluetoothProfileConnector.java
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -78,6 +80,7 @@ public abstract class BluetoothProfileConnector<T> {
mServiceName = serviceName;
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
private boolean doBind() {
synchronized (mConnection) {
if (mService == null) {
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index 0d70dbdd8427..c85494c01b25 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -18,6 +18,9 @@ package android.bluetooth;
import android.Manifest;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Binder;
@@ -61,11 +64,11 @@ public final class BluetoothSap implements BluetoothProfile {
* {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
- *
* @hide
*/
+ @RequiresLegacyBluetoothPermission
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public static final String ACTION_CONNECTION_STATE_CHANGED =
"android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED";
@@ -140,6 +143,7 @@ public final class BluetoothSap implements BluetoothProfile {
* connected to the Sap service.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public int getState() {
if (VDBG) log("getState()");
final IBluetoothSap service = getService();
@@ -163,6 +167,7 @@ public final class BluetoothSap implements BluetoothProfile {
* this proxy object is not connected to the Sap service.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public BluetoothDevice getClient() {
if (VDBG) log("getClient()");
final IBluetoothSap service = getService();
@@ -186,6 +191,7 @@ public final class BluetoothSap implements BluetoothProfile {
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean isConnected(BluetoothDevice device) {
if (VDBG) log("isConnected(" + device + ")");
final IBluetoothSap service = getService();
@@ -221,6 +227,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
final IBluetoothSap service = getService();
@@ -242,6 +249,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @return list of connected devices
* @hide
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getConnectedDevices() {
if (DBG) log("getConnectedDevices()");
final IBluetoothSap service = getService();
@@ -263,6 +271,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @return list of matching devices
* @hide
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) log("getDevicesMatchingStates()");
final IBluetoothSap service = getService();
@@ -284,6 +293,7 @@ public final class BluetoothSap implements BluetoothProfile {
* @return device connection state
* @hide
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
public int getConnectionState(BluetoothDevice device) {
if (DBG) log("getConnectionState(" + device + ")");
final IBluetoothSap service = getService();
@@ -310,7 +320,10 @@ public final class BluetoothSap implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
@@ -328,7 +341,10 @@ public final class BluetoothSap implements BluetoothProfile {
* @return true if connectionPolicy is set, false on error
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public boolean setConnectionPolicy(BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
@@ -359,7 +375,10 @@ public final class BluetoothSap implements BluetoothProfile {
* @return priority of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
@@ -376,7 +395,10 @@ public final class BluetoothSap implements BluetoothProfile {
* @return connection policy of the device
* @hide
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothSap service = getService();
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 5c1bcaf31319..50822354d69f 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -62,9 +62,6 @@ import java.io.IOException;
* safe. In particular, {@link #close} will always immediately abort ongoing
* operations and close the server socket.
*
- * <p class="note"><strong>Note:</strong>
- * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about using Bluetooth, read the
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 65381dbb2372..ef88147a40fb 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -16,6 +16,8 @@
package android.bluetooth;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.LocalSocket;
import android.os.Build;
@@ -70,9 +72,6 @@ import java.util.UUID;
* safe. In particular, {@link #close} will always immediately abort ongoing
* operations and close the socket.
*
- * <p class="note"><strong>Note:</strong>
- * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
- *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about using Bluetooth, read the
@@ -199,6 +198,7 @@ public final class BluetoothSocket implements Closeable {
* @throws IOException On error, for example Bluetooth not available, or insufficient
* privileges
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
/*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
BluetoothDevice device, int port, ParcelUuid uuid, boolean mitm, boolean min16DigitPin)
throws IOException {
@@ -386,6 +386,7 @@ public final class BluetoothSocket implements Closeable {
*
* @throws IOException on error, for example connection failure
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void connect() throws IOException {
if (mDevice == null) throw new IOException("Connect is called on null device");
@@ -427,6 +428,7 @@ public final class BluetoothSocket implements Closeable {
* Currently returns unix errno instead of throwing IOException,
* so that BluetoothAdapter can check the error code for EADDRINUSE
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
/*package*/ int bindListen() {
int ret;
if (mSocketState == SocketState.CLOSED) return EBADFD;
@@ -682,6 +684,7 @@ public final class BluetoothSocket implements Closeable {
* connection. This function is currently used for testing only.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void requestMaximumTxDataLength() throws IOException {
if (mDevice == null) {
throw new IOException("requestMaximumTxDataLength is called on null device");
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java
new file mode 100644
index 000000000000..c508c2c9ca0b
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+import android.os.Build;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher,
+ * this requires the {@link Manifest.permission#BLUETOOTH_ADVERTISE}
+ * permission which can be gained with
+ * {@link android.app.Activity#requestPermissions(String[], int)}.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresBluetoothAdvertisePermission {
+}
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java
new file mode 100644
index 000000000000..e159eaafe2e4
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+import android.os.Build;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher,
+ * this requires the {@link Manifest.permission#BLUETOOTH_CONNECT}
+ * permission which can be gained with
+ * {@link android.app.Activity#requestPermissions(String[], int)}.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresBluetoothConnectPermission {
+}
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java
new file mode 100644
index 000000000000..2bb320413941
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc In addition, this requires either the
+ * {@link Manifest.permission#ACCESS_FINE_LOCATION}
+ * permission or a strong assertion that you will never derive the
+ * physical location of the device. You can make this assertion by
+ * declaring {@code usesPermissionFlags="neverForLocation"} on the
+ * relevant {@code <uses-permission>} manifest tag, but it may
+ * restrict the types of Bluetooth devices you can interact with.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresBluetoothLocationPermission {
+}
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java
new file mode 100644
index 000000000000..800ff39933f2
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+import android.os.Build;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher,
+ * this requires the {@link Manifest.permission#BLUETOOTH_SCAN}
+ * permission which can be gained with
+ * {@link android.app.Activity#requestPermissions(String[], int)}.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresBluetoothScanPermission {
+}
diff --git a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java
new file mode 100644
index 000000000000..9adf695cde0f
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+import android.os.Build;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this
+ * requires the {@link Manifest.permission#BLUETOOTH_ADMIN}
+ * permission which can be gained with a simple
+ * {@code <uses-permission>} manifest tag.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresLegacyBluetoothAdminPermission {
+}
diff --git a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java
new file mode 100644
index 000000000000..79621c366f59
--- /dev/null
+++ b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.Manifest;
+import android.os.Build;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this
+ * requires the {@link Manifest.permission#BLUETOOTH} permission
+ * which can be gained with a simple {@code <uses-permission>}
+ * manifest tag.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, FIELD})
+public @interface RequiresLegacyBluetoothPermission {
+}
diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java
index 1df35e1e382f..54a18e6f1d62 100644
--- a/core/java/android/bluetooth/le/AdvertisingSet.java
+++ b/core/java/android/bluetooth/le/AdvertisingSet.java
@@ -16,9 +16,12 @@
package android.bluetooth.le;
+import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
+import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.os.RemoteException;
import android.util.Log;
@@ -27,9 +30,6 @@ import android.util.Log;
* <p>
* To get an instance of {@link AdvertisingSet}, call the
* {@link BluetoothLeAdvertiser#startAdvertisingSet} method.
- * <p>
- * <b>Note:</b> Most of the methods here require {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
*
* @see AdvertiseData
*/
@@ -58,8 +58,6 @@ public final class AdvertisingSet {
/**
* Enables Advertising. This method returns immediately, the operation status is
* delivered through {@code callback.onAdvertisingEnabled()}.
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
*
* @param enable whether the advertising should be enabled (true), or disabled (false)
* @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535
@@ -68,6 +66,9 @@ public final class AdvertisingSet {
* controller shall attempt to send prior to terminating the extended advertising, even if the
* duration has not expired. Valid range is from 1 to 255.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void enableAdvertising(boolean enable, int duration,
int maxExtendedAdvertisingEvents) {
try {
@@ -90,6 +91,9 @@ public final class AdvertisingSet {
* three bytes will be added for flags. If the update takes place when the advertising set is
* enabled, the data can be maximum 251 bytes long.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setAdvertisingData(AdvertiseData advertiseData) {
try {
mGatt.setAdvertisingData(mAdvertiserId, advertiseData);
@@ -107,6 +111,9 @@ public final class AdvertisingSet {
* exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes place
* when the advertising set is enabled, the data can be maximum 251 bytes long.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setScanResponseData(AdvertiseData scanResponse) {
try {
mGatt.setScanResponseData(mAdvertiserId, scanResponse);
@@ -122,6 +129,9 @@ public final class AdvertisingSet {
*
* @param parameters advertising set parameters.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setAdvertisingParameters(AdvertisingSetParameters parameters) {
try {
mGatt.setAdvertisingParameters(mAdvertiserId, parameters);
@@ -135,6 +145,9 @@ public final class AdvertisingSet {
* periodic advertising is not enabled. This method returns immediately, the operation
* status is delivered through {@code callback.onPeriodicAdvertisingParametersUpdated()}.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setPeriodicAdvertisingParameters(PeriodicAdvertisingParameters parameters) {
try {
mGatt.setPeriodicAdvertisingParameters(mAdvertiserId, parameters);
@@ -153,6 +166,9 @@ public final class AdvertisingSet {
* BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes place when the
* periodic advertising is enabled for this set, the data can be maximum 251 bytes long.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setPeriodicAdvertisingData(AdvertiseData periodicData) {
try {
mGatt.setPeriodicAdvertisingData(mAdvertiserId, periodicData);
@@ -168,6 +184,9 @@ public final class AdvertisingSet {
* @param enable whether the periodic advertising should be enabled (true), or disabled
* (false).
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void setPeriodicAdvertisingEnabled(boolean enable) {
try {
mGatt.setPeriodicAdvertisingEnable(mAdvertiserId, enable);
@@ -181,10 +200,9 @@ public final class AdvertisingSet {
* This method is exposed only for Bluetooth PTS tests, no app or system service
* should ever use it.
*
- * This method requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission.
- *
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public void getOwnAddress() {
try {
mGatt.getOwnAddress(mAdvertiserId);
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 5f166f4a41da..de11869e220e 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -16,11 +16,15 @@
package android.bluetooth.le;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
+import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
@@ -38,9 +42,6 @@ import java.util.Map;
* <p>
* To get an instance of {@link BluetoothLeAdvertiser}, call the
* {@link BluetoothAdapter#getBluetoothLeAdvertiser()} method.
- * <p>
- * <b>Note:</b> Most of the methods here require {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission.
*
* @see AdvertiseData
*/
@@ -81,13 +82,17 @@ public final class BluetoothLeAdvertiser {
/**
* Start Bluetooth LE Advertising. On success, the {@code advertiseData} will be broadcasted.
* Returns immediately, the operation status is delivered through {@code callback}.
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
*
* @param settings Settings for Bluetooth LE advertising.
* @param advertiseData Advertisement data to be broadcasted.
* @param callback Callback for advertising status.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertising(AdvertiseSettings settings,
AdvertiseData advertiseData, final AdvertiseCallback callback) {
startAdvertising(settings, advertiseData, null, callback);
@@ -98,14 +103,18 @@ public final class BluetoothLeAdvertiser {
* operation succeeds. The {@code scanResponse} is returned when a scanning device sends an
* active scan request. This method returns immediately, the operation status is delivered
* through {@code callback}.
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
*
* @param settings Settings for Bluetooth LE advertising.
* @param advertiseData Advertisement data to be advertised in advertisement packet.
* @param scanResponse Scan response associated with the advertisement data.
* @param callback Callback for advertising status.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertising(AdvertiseSettings settings,
AdvertiseData advertiseData, AdvertiseData scanResponse,
final AdvertiseCallback callback) {
@@ -160,9 +169,11 @@ public final class BluetoothLeAdvertiser {
}
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
AdvertisingSetCallback wrapOldCallback(AdvertiseCallback callback, AdvertiseSettings settings) {
return new AdvertisingSetCallback() {
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
int status) {
if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
@@ -175,6 +186,7 @@ public final class BluetoothLeAdvertiser {
/* Legacy advertiser is disabled on timeout */
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enabled,
int status) {
if (enabled) {
@@ -192,11 +204,12 @@ public final class BluetoothLeAdvertiser {
/**
* Stop Bluetooth LE advertising. The {@code callback} must be the same one use in
* {@link BluetoothLeAdvertiser#startAdvertising}.
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
*
* @param callback {@link AdvertiseCallback} identifies the advertising instance to stop.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void stopAdvertising(final AdvertiseCallback callback) {
synchronized (mLegacyAdvertisers) {
if (callback == null) {
@@ -232,6 +245,12 @@ public final class BluetoothLeAdvertiser {
* size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising
* feature is made when it's not supported by the controller.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertisingSet(AdvertisingSetParameters parameters,
AdvertiseData advertiseData, AdvertiseData scanResponse,
PeriodicAdvertisingParameters periodicParameters,
@@ -262,6 +281,12 @@ public final class BluetoothLeAdvertiser {
* size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising
* feature is made when it's not supported by the controller.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertisingSet(AdvertisingSetParameters parameters,
AdvertiseData advertiseData, AdvertiseData scanResponse,
PeriodicAdvertisingParameters periodicParameters,
@@ -297,6 +322,12 @@ public final class BluetoothLeAdvertiser {
* size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising
* feature is made when it's not supported by the controller.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertisingSet(AdvertisingSetParameters parameters,
AdvertiseData advertiseData, AdvertiseData scanResponse,
PeriodicAdvertisingParameters periodicParameters,
@@ -337,6 +368,12 @@ public final class BluetoothLeAdvertiser {
* maxExtendedAdvertisingEvents is used on a controller that doesn't support the LE Extended
* Advertising
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_ADVERTISE,
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ })
public void startAdvertisingSet(AdvertisingSetParameters parameters,
AdvertiseData advertiseData, AdvertiseData scanResponse,
PeriodicAdvertisingParameters periodicParameters,
@@ -445,6 +482,9 @@ public final class BluetoothLeAdvertiser {
* Used to dispose of a {@link AdvertisingSet} object, obtained with {@link
* BluetoothLeAdvertiser#startAdvertisingSet}.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothAdvertisePermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
public void stopAdvertisingSet(AdvertisingSetCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback cannot be null");
@@ -476,6 +516,7 @@ public final class BluetoothLeAdvertiser {
}
// Compute the size of advertisement data or scan resp
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private int totalBytes(AdvertiseData data, boolean isFlagsIncluded) {
if (data == null) return 0;
// Flags field is omitted if the advertising is not connectable.
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 2601cd4300ea..4271a905c220 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -20,12 +20,16 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
+import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
+import android.bluetooth.annotations.RequiresBluetoothScanPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.content.AttributionSource;
import android.os.Handler;
import android.os.Looper;
@@ -45,9 +49,6 @@ import java.util.Map;
* <p>
* Use {@link BluetoothAdapter#getBluetoothLeScanner()} to get an instance of
* {@link BluetoothLeScanner}.
- * <p>
- * <b>Note:</b> Most of the scan methods here require
- * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
*
* @see ScanFilter
*/
@@ -117,7 +118,10 @@ public final class BluetoothLeScanner {
* @param callback Callback used to deliver scan results.
* @throws IllegalArgumentException If {@code callback} is null.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void startScan(final ScanCallback callback) {
startScan(null, new ScanSettings.Builder().build(), callback);
}
@@ -139,7 +143,10 @@ public final class BluetoothLeScanner {
* @param callback Callback used to deliver scan results.
* @throws IllegalArgumentException If {@code settings} or {@code callback} is null.
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void startScan(List<ScanFilter> filters, ScanSettings settings,
final ScanCallback callback) {
startScan(filters, settings, null, callback, /*callbackIntent=*/ null, null);
@@ -168,7 +175,10 @@ public final class BluetoothLeScanner {
* could not be sent.
* @see #stopScan(PendingIntent)
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public int startScan(@Nullable List<ScanFilter> filters, @Nullable ScanSettings settings,
@NonNull PendingIntent callbackIntent) {
return startScan(filters,
@@ -186,8 +196,13 @@ public final class BluetoothLeScanner {
* @hide
*/
@SystemApi
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
@RequiresPermission(allOf = {
- Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS})
+ android.Manifest.permission.BLUETOOTH_SCAN,
+ android.Manifest.permission.UPDATE_DEVICE_STATS
+ })
public void startScanFromSource(final WorkSource workSource, final ScanCallback callback) {
startScanFromSource(null, new ScanSettings.Builder().build(), workSource, callback);
}
@@ -204,13 +219,20 @@ public final class BluetoothLeScanner {
* @hide
*/
@SystemApi
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
@RequiresPermission(allOf = {
- Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.UPDATE_DEVICE_STATS})
+ android.Manifest.permission.BLUETOOTH_SCAN,
+ android.Manifest.permission.UPDATE_DEVICE_STATS
+ })
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void startScanFromSource(List<ScanFilter> filters, ScanSettings settings,
final WorkSource workSource, final ScanCallback callback) {
startScan(filters, settings, workSource, callback, null, null);
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
private int startScan(List<ScanFilter> filters, ScanSettings settings,
final WorkSource workSource, final ScanCallback callback,
final PendingIntent callbackIntent,
@@ -268,7 +290,9 @@ public final class BluetoothLeScanner {
*
* @param callback
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void stopScan(ScanCallback callback) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
synchronized (mLeScanClients) {
@@ -289,7 +313,9 @@ public final class BluetoothLeScanner {
* @param callbackIntent The PendingIntent that was used to start the scan.
* @see #startScan(List, ScanSettings, PendingIntent)
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void stopScan(PendingIntent callbackIntent) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
IBluetoothGatt gatt;
@@ -308,6 +334,9 @@ public final class BluetoothLeScanner {
* @param callback Callback of the Bluetooth LE Scan, it has to be the same instance as the one
* used to start scan.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void flushPendingScanResults(ScanCallback callback) {
BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
if (callback == null) {
@@ -328,6 +357,7 @@ public final class BluetoothLeScanner {
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void startTruncatedScan(List<TruncatedFilter> truncatedFilters, ScanSettings settings,
final ScanCallback callback) {
int filterSize = truncatedFilters.size();
@@ -382,6 +412,8 @@ public final class BluetoothLeScanner {
mResultStorages = resultStorages;
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void startRegistration() {
synchronized (this) {
// Scan stopped.
@@ -409,6 +441,8 @@ public final class BluetoothLeScanner {
}
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void stopLeScan() {
synchronized (this) {
if (mScannerId <= 0) {
@@ -425,6 +459,8 @@ public final class BluetoothLeScanner {
}
}
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
void flushPendingBatchResults() {
synchronized (this) {
if (mScannerId <= 0) {
@@ -443,6 +479,7 @@ public final class BluetoothLeScanner {
* Application interface registered - app is ready to go
*/
@Override
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onScannerRegistered(int status, int scannerId) {
Log.d(TAG, "onScannerRegistered() - status=" + status
+ " scannerId=" + scannerId + " mScannerId=" + mScannerId);
@@ -595,6 +632,7 @@ public final class BluetoothLeScanner {
return true;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private boolean isHardwareResourcesAvailableForScan(ScanSettings settings) {
final int callbackType = settings.getCallbackType();
if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
index 0f1a8e913ba8..9ea6c4866f6d 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
@@ -16,10 +16,14 @@
package android.bluetooth.le;
+import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
+import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
+import android.bluetooth.annotations.RequiresBluetoothScanPermission;
+import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -35,9 +39,6 @@ import java.util.Map;
* <p>
* Use {@link BluetoothAdapter#getPeriodicAdvertisingManager()} to get an
* instance of {@link PeriodicAdvertisingManager}.
- * <p>
- * <b>Note:</b> Most of the methods here require
- * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
*
* @hide
*/
@@ -89,6 +90,10 @@ public final class PeriodicAdvertisingManager {
* @throws IllegalArgumentException if {@code scanResult} is null or {@code skip} is invalid or
* {@code timeout} is invalid or {@code callback} is null.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void registerSync(ScanResult scanResult, int skip, int timeout,
PeriodicAdvertisingCallback callback) {
registerSync(scanResult, skip, timeout, callback, null);
@@ -113,6 +118,10 @@ public final class PeriodicAdvertisingManager {
* @throws IllegalArgumentException if {@code scanResult} is null or {@code skip} is invalid or
* {@code timeout} is invalid or {@code callback} is null.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresBluetoothLocationPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void registerSync(ScanResult scanResult, int skip, int timeout,
PeriodicAdvertisingCallback callback, Handler handler) {
if (callback == null) {
@@ -170,6 +179,9 @@ public final class PeriodicAdvertisingManager {
* @throws IllegalArgumentException if {@code callback} is null, or not a properly registered
* callback.
*/
+ @RequiresLegacyBluetoothAdminPermission
+ @RequiresBluetoothScanPermission
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
public void unregisterSync(PeriodicAdvertisingCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback can't be null");
diff --git a/core/java/com/android/internal/util/State.java b/core/java/com/android/internal/util/State.java
index 4613dad8cc67..d5c0f60f4b37 100644
--- a/core/java/com/android/internal/util/State.java
+++ b/core/java/com/android/internal/util/State.java
@@ -16,6 +16,7 @@
package com.android.internal.util;
+import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Message;
@@ -25,6 +26,7 @@ import android.os.Message;
*
* The class for implementing states in a StateMachine
*/
+@SuppressLint("AndroidFrameworkRequiresPermission")
public class State implements IState {
/**
diff --git a/errorprone/java/android/annotation/SuppressLint.java b/errorprone/java/android/annotation/SuppressLint.java
new file mode 100644
index 000000000000..2d3456b0ea46
--- /dev/null
+++ b/errorprone/java/android/annotation/SuppressLint.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should ignore the specified warnings for the annotated element. */
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressLint {
+ /**
+ * The set of warnings (identified by the lint issue id) that should be
+ * ignored by lint. It is not an error to specify an unrecognized name.
+ */
+ String[] value();
+}
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
new file mode 100644
index 000000000000..3b5a58c46f71
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/RequiresPermissionChecker.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2021 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 com.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.matchers.Matchers.allOf;
+import static com.google.errorprone.matchers.Matchers.anyOf;
+import static com.google.errorprone.matchers.Matchers.enclosingClass;
+import static com.google.errorprone.matchers.Matchers.instanceMethod;
+import static com.google.errorprone.matchers.Matchers.isSubtypeOf;
+import static com.google.errorprone.matchers.Matchers.methodInvocation;
+import static com.google.errorprone.matchers.Matchers.methodIsNamed;
+import static com.google.errorprone.matchers.Matchers.staticMethod;
+
+import android.annotation.SuppressLint;
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.Matcher;
+import com.google.errorprone.util.ASTHelpers;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodInvocationTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.util.TreeScanner;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.ClassType;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ExecutableElement;
+
+/**
+ * Inspects both the client and server side of AIDL interfaces to ensure that
+ * any {@code RequiresPermission} annotations are consistently declared and
+ * enforced.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+ name = "AndroidFrameworkRequiresPermission",
+ summary = "Verifies that @RequiresPermission annotations are consistent across AIDL",
+ severity = WARNING)
+public final class RequiresPermissionChecker extends BugChecker implements MethodTreeMatcher {
+ private static final String ANNOTATION_REQUIRES_PERMISSION = "RequiresPermission";
+
+ private static final Matcher<ExpressionTree> ENFORCE_VIA_CONTEXT = methodInvocation(
+ instanceMethod()
+ .onDescendantOf("android.content.Context")
+ .withNameMatching(
+ Pattern.compile("^(enforce|check)(Calling)?(OrSelf)?Permission$")));
+ private static final Matcher<ExpressionTree> ENFORCE_VIA_CHECKER = methodInvocation(
+ staticMethod()
+ .onClass("android.content.PermissionChecker")
+ .withNameMatching(Pattern.compile("^check.*")));
+
+ private static final Matcher<MethodTree> BINDER_INTERNALS = allOf(
+ enclosingClass(isSubtypeOf("android.os.IInterface")),
+ anyOf(
+ methodIsNamed("onTransact"),
+ methodIsNamed("dump"),
+ enclosingClass(simpleNameMatches(Pattern.compile("^(Stub|Default|Proxy)$")))));
+ private static final Matcher<MethodTree> LOCAL_INTERNALS = anyOf(
+ methodIsNamed("finalize"),
+ allOf(
+ enclosingClass(isSubtypeOf("android.content.BroadcastReceiver")),
+ methodIsNamed("onReceive")),
+ allOf(
+ enclosingClass(isSubtypeOf("android.database.ContentObserver")),
+ methodIsNamed("onChange")),
+ allOf(
+ enclosingClass(isSubtypeOf("android.os.Handler")),
+ methodIsNamed("handleMessage")),
+ allOf(
+ enclosingClass(isSubtypeOf("android.os.IBinder.DeathRecipient")),
+ methodIsNamed("binderDied")));
+
+ private static final Matcher<ExpressionTree> CLEAR_CALL = methodInvocation(staticMethod()
+ .onClass("android.os.Binder").withSignature("clearCallingIdentity()"));
+ private static final Matcher<ExpressionTree> RESTORE_CALL = methodInvocation(staticMethod()
+ .onClass("android.os.Binder").withSignature("restoreCallingIdentity(long)"));
+
+ @Override
+ public Description matchMethod(MethodTree tree, VisitorState state) {
+ // Ignore methods without an implementation
+ if (tree.getBody() == null) return Description.NO_MATCH;
+
+ // Ignore certain types of Binder generated code
+ if (BINDER_INTERNALS.matches(tree, state)) return Description.NO_MATCH;
+
+ // Ignore known-local methods which don't need to propagate
+ if (LOCAL_INTERNALS.matches(tree, state)) return Description.NO_MATCH;
+
+ // Ignore when suppressed via superclass
+ final MethodSymbol method = ASTHelpers.getSymbol(tree);
+ if (isSuppressedRecursively(method, state)) return Description.NO_MATCH;
+
+ // First, look at all outgoing method invocations to ensure that we
+ // carry those annotations forward; yell if we're too narrow
+ final ParsedRequiresPermission expectedPerm = parseRequiresPermissionRecursively(
+ method, state);
+ final ParsedRequiresPermission actualPerm = new ParsedRequiresPermission();
+ final Description desc = tree.accept(new TreeScanner<Description, Void>() {
+ private boolean clearedCallingIdentity = false;
+
+ @Override
+ public Description visitMethodInvocation(MethodInvocationTree node, Void param) {
+ if (CLEAR_CALL.matches(node, state)) {
+ clearedCallingIdentity = true;
+ } else if (RESTORE_CALL.matches(node, state)) {
+ clearedCallingIdentity = false;
+ } else if (!clearedCallingIdentity) {
+ final ParsedRequiresPermission nodePerm = parseRequiresPermissionRecursively(
+ node, state);
+ if (!expectedPerm.containsAll(nodePerm)) {
+ return buildDescription(node).setMessage("Annotated " + expectedPerm
+ + " but too narrow; invokes method requiring " + nodePerm).build();
+ } else {
+ actualPerm.addAll(nodePerm);
+ }
+ }
+ return super.visitMethodInvocation(node, param);
+ }
+
+ @Override
+ public Description reduce(Description r1, Description r2) {
+ return (r1 != null) ? r1 : r2;
+ }
+ }, null);
+ if (desc != null) return desc;
+
+ // Second, determine if we actually used all permissions that we claim
+ // to require; yell if we're too broad
+ if (!actualPerm.containsAll(expectedPerm)) {
+ return buildDescription(tree).setMessage("Annotated " + expectedPerm
+ + " but too wide; only invokes methods requiring " + actualPerm).build();
+ }
+
+ return Description.NO_MATCH;
+ }
+
+ static class ParsedRequiresPermission {
+ final Set<String> allOf = new HashSet<>();
+ final Set<String> anyOf = new HashSet<>();
+
+ public boolean isEmpty() {
+ return allOf.isEmpty() && anyOf.isEmpty();
+ }
+
+ /**
+ * Validate that this annotation effectively "contains" the given
+ * annotation. This is typically used to ensure that a method carries
+ * along all relevant annotations for the methods it invokes.
+ */
+ public boolean containsAll(ParsedRequiresPermission perm) {
+ boolean allMet = allOf.containsAll(perm.allOf);
+ boolean anyMet = false;
+ if (perm.anyOf.isEmpty()) {
+ anyMet = true;
+ } else {
+ for (String anyPerm : perm.anyOf) {
+ if (allOf.contains(anyPerm) || anyOf.contains(anyPerm)) {
+ anyMet = true;
+ }
+ }
+ }
+ return allMet && anyMet;
+ }
+
+ @Override
+ public String toString() {
+ if (isEmpty()) {
+ return "[none]";
+ }
+ String res = "{allOf=" + allOf;
+ if (!anyOf.isEmpty()) {
+ res += " anyOf=" + anyOf;
+ }
+ res += "}";
+ return res;
+ }
+
+ public void addAll(ParsedRequiresPermission perm) {
+ this.allOf.addAll(perm.allOf);
+ this.anyOf.addAll(perm.anyOf);
+ }
+
+ public void addAll(AnnotationMirror a) {
+ for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : a
+ .getElementValues().entrySet()) {
+ if (entry.getKey().getSimpleName().contentEquals("value")) {
+ maybeAdd(allOf, entry.getValue());
+ } else if (entry.getKey().getSimpleName().contentEquals("allOf")) {
+ maybeAdd(allOf, entry.getValue());
+ } else if (entry.getKey().getSimpleName().contentEquals("anyOf")) {
+ maybeAdd(anyOf, entry.getValue());
+ }
+ }
+ }
+
+ private static void maybeAdd(Set<String> set, Object value) {
+ if (value instanceof AnnotationValue) {
+ maybeAdd(set, ((AnnotationValue) value).getValue());
+ } else if (value instanceof String) {
+ set.add((String) value);
+ } else if (value instanceof Collection) {
+ for (Object o : (Collection) value) {
+ maybeAdd(set, o);
+ }
+ } else {
+ throw new RuntimeException(String.valueOf(value.getClass()));
+ }
+ }
+ }
+
+ private static ParsedRequiresPermission parseRequiresPermissionRecursively(
+ MethodInvocationTree tree, VisitorState state) {
+ if (ENFORCE_VIA_CONTEXT.matches(tree, state)) {
+ final ParsedRequiresPermission res = new ParsedRequiresPermission();
+ res.allOf.add(String.valueOf(ASTHelpers.constValue(tree.getArguments().get(0))));
+ return res;
+ } else if (ENFORCE_VIA_CHECKER.matches(tree, state)) {
+ final ParsedRequiresPermission res = new ParsedRequiresPermission();
+ res.allOf.add(String.valueOf(ASTHelpers.constValue(tree.getArguments().get(1))));
+ return res;
+ } else {
+ final MethodSymbol method = ASTHelpers.getSymbol(tree);
+ return parseRequiresPermissionRecursively(method, state);
+ }
+ }
+
+ /**
+ * Parse any {@code RequiresPermission} annotations associated with the
+ * given method, defined either directly on the method or by any superclass.
+ */
+ private static ParsedRequiresPermission parseRequiresPermissionRecursively(
+ MethodSymbol method, VisitorState state) {
+ final List<MethodSymbol> symbols = new ArrayList<>();
+ symbols.add(method);
+ symbols.addAll(ASTHelpers.findSuperMethods(method, state.getTypes()));
+
+ final ParsedRequiresPermission res = new ParsedRequiresPermission();
+ for (MethodSymbol symbol : symbols) {
+ for (AnnotationMirror a : symbol.getAnnotationMirrors()) {
+ if (a.getAnnotationType().asElement().getSimpleName()
+ .contentEquals(ANNOTATION_REQUIRES_PERMISSION)) {
+ res.addAll(a);
+ }
+ }
+ }
+ return res;
+ }
+
+ private boolean isSuppressedRecursively(MethodSymbol method, VisitorState state) {
+ // Is method suppressed anywhere?
+ if (isSuppressed(method)) return true;
+ for (MethodSymbol symbol : ASTHelpers.findSuperMethods(method, state.getTypes())) {
+ if (isSuppressed(symbol)) return true;
+ }
+
+ // Is class suppressed anywhere?
+ final ClassSymbol clazz = ASTHelpers.enclosingClass(method);
+ if (isSuppressed(clazz)) return true;
+ Type type = clazz.getSuperclass();
+ while (type != null) {
+ if (isSuppressed(type.tsym)) return true;
+ if (type instanceof ClassType) {
+ type = ((ClassType) type).supertype_field;
+ } else {
+ type = null;
+ }
+ }
+ return false;
+ }
+
+ public boolean isSuppressed(Symbol symbol) {
+ return isSuppressed(ASTHelpers.getAnnotation(symbol, SuppressWarnings.class))
+ || isSuppressed(ASTHelpers.getAnnotation(symbol, SuppressLint.class));
+ }
+
+ private boolean isSuppressed(SuppressWarnings anno) {
+ return (anno != null) && !Collections.disjoint(Arrays.asList(anno.value()), allNames());
+ }
+
+ private boolean isSuppressed(SuppressLint anno) {
+ return (anno != null) && !Collections.disjoint(Arrays.asList(anno.value()), allNames());
+ }
+
+ private static Matcher<ClassTree> simpleNameMatches(Pattern pattern) {
+ return new Matcher<ClassTree>() {
+ @Override
+ public boolean matches(ClassTree tree, VisitorState state) {
+ final CharSequence name = tree.getSimpleName().toString();
+ return pattern.matcher(name).matches();
+ }
+ };
+ }
+}
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java
new file mode 100644
index 000000000000..771258d7d265
--- /dev/null
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/RequiresPermissionCheckerTest.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2020 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 com.google.errorprone.bugpatterns.android;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.errorprone.CompilationTestHelper;
+import com.google.errorprone.bugpatterns.android.RequiresPermissionChecker.ParsedRequiresPermission;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(JUnit4.class)
+public class RequiresPermissionCheckerTest {
+ private CompilationTestHelper compilationHelper;
+
+ private static final String RED = "red";
+ private static final String BLUE = "blue";
+
+ @Before
+ public void setUp() {
+ compilationHelper = CompilationTestHelper.newInstance(
+ RequiresPermissionChecker.class, getClass());
+ }
+
+ private static ParsedRequiresPermission build(Collection<String> allOf,
+ Collection<String> anyOf) {
+ ParsedRequiresPermission res = new ParsedRequiresPermission();
+ res.allOf.addAll(allOf);
+ res.anyOf.addAll(anyOf);
+ return res;
+ }
+
+ @Test
+ public void testParser_AllOf() {
+ final ParsedRequiresPermission a = build(Arrays.asList(RED, BLUE), Arrays.asList());
+ final ParsedRequiresPermission b = build(Arrays.asList(RED), Arrays.asList());
+ assertTrue(a.containsAll(b));
+ assertFalse(b.containsAll(a));
+ }
+
+ @Test
+ public void testParser_AnyOf() {
+ final ParsedRequiresPermission a = build(Arrays.asList(), Arrays.asList(RED, BLUE));
+ final ParsedRequiresPermission b = build(Arrays.asList(), Arrays.asList(RED));
+ assertTrue(a.containsAll(b));
+ assertTrue(b.containsAll(a));
+ }
+
+ @Test
+ public void testParser_AnyOf_AllOf() {
+ final ParsedRequiresPermission a = build(Arrays.asList(RED, BLUE), Arrays.asList());
+ final ParsedRequiresPermission b = build(Arrays.asList(), Arrays.asList(RED));
+ assertTrue(a.containsAll(b));
+ assertFalse(b.containsAll(a));
+ }
+
+ @Test
+ public void testSimple() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.content.Context;",
+ "public abstract class ColorManager extends Context {",
+ " private static final String RED = \"red\";",
+ " private static final String BLUE = \"blue\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " @RequiresPermission(BLUE) abstract int blue();",
+ " @RequiresPermission(allOf={RED, BLUE}) abstract int all();",
+ " @RequiresPermission(anyOf={RED, BLUE}) abstract int any();",
+ " @RequiresPermission(allOf={RED, BLUE})",
+ " int redPlusBlue() { return red() + blue(); }",
+ " @RequiresPermission(allOf={RED, BLUE})",
+ " int allPlusRed() { return all() + red(); }",
+ " @RequiresPermission(allOf={RED})",
+ " int anyPlusRed() { return any() + red(); }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testManager() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/foo/IColorService.java")
+ .addSourceFile("/android/os/IInterface.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.foo.IColorService;",
+ "public class ColorManager {",
+ " IColorService mService;",
+ " @RequiresPermission(IColorService.RED)",
+ " void redValid() {",
+ " mService.red();",
+ " }",
+ " @RequiresPermission(allOf={IColorService.RED, IColorService.BLUE})",
+ " // BUG: Diagnostic contains:",
+ " void redOverbroad() {",
+ " mService.red();",
+ " }",
+ " @RequiresPermission(IColorService.BLUE)",
+ " void redInvalid() {",
+ " // BUG: Diagnostic contains:",
+ " mService.red();",
+ " }",
+ " void redMissing() {",
+ " // BUG: Diagnostic contains:",
+ " mService.red();",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testService() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/foo/IColorService.java")
+ .addSourceFile("/android/os/IInterface.java")
+ .addSourceLines("ColorService.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.content.Context;",
+ "import android.foo.IColorService;",
+ "class ColorService extends Context implements IColorService {",
+ " public void none() {}",
+ " // BUG: Diagnostic contains:",
+ " public void red() {}",
+ " // BUG: Diagnostic contains:",
+ " public void redAndBlue() {}",
+ " // BUG: Diagnostic contains:",
+ " public void redOrBlue() {}",
+ " void onTransact(int code) {",
+ " red();",
+ " }",
+ "}",
+ "class ValidService extends ColorService {",
+ " public void red() {",
+ " ((Context) this).enforceCallingOrSelfPermission(RED, null);",
+ " }",
+ "}",
+ "class InvalidService extends ColorService {",
+ " public void red() {",
+ " // BUG: Diagnostic contains:",
+ " ((Context) this).enforceCallingOrSelfPermission(BLUE, null);",
+ " }",
+ "}",
+ "class NestedService extends ColorService {",
+ " public void red() {",
+ " enforceRed();",
+ " }",
+ " @RequiresPermission(RED)",
+ " public void enforceRed() {",
+ " ((Context) this).enforceCallingOrSelfPermission(RED, null);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testBroadcastReceiver() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/content/BroadcastReceiver.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.content.BroadcastReceiver;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public abstract class ColorManager extends BroadcastReceiver {",
+ " private static final String RED = \"red\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " // BUG: Diagnostic contains:",
+ " public void onSend() { red(); }",
+ " public void onReceive(Context context, Intent intent) { red(); }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ @Ignore
+ public void testContentObserver() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/database/ContentObserver.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.database.ContentObserver;",
+ "public abstract class ColorManager {",
+ " private static final String RED = \"red\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " public void example() {",
+ " ContentObserver ob = new ContentObserver() {",
+ " public void onChange(boolean selfChange) {",
+ " red();",
+ " }",
+ " };",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testHandler() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/os/Handler.java")
+ .addSourceFile("/android/os/Message.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.os.Handler;",
+ "import android.os.Message;",
+ "public abstract class ColorManager extends Handler {",
+ " private static final String RED = \"red\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " // BUG: Diagnostic contains:",
+ " public void sendMessage() { red(); }",
+ " public void handleMessage(Message msg) { red(); }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testDeathRecipient() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/os/IBinder.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.os.IBinder;",
+ "public abstract class ColorManager implements IBinder.DeathRecipient {",
+ " private static final String RED = \"red\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " // BUG: Diagnostic contains:",
+ " public void binderAlive() { red(); }",
+ " public void binderDied() { red(); }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testClearCallingIdentity() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/os/Binder.java")
+ .addSourceLines("ColorManager.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.os.Binder;",
+ "public abstract class ColorManager {",
+ " private static final String RED = \"red\";",
+ " private static final String BLUE = \"blue\";",
+ " @RequiresPermission(RED) abstract int red();",
+ " @RequiresPermission(BLUE) abstract int blue();",
+ " @RequiresPermission(BLUE)",
+ " public void half() {",
+ " final long token = Binder.clearCallingIdentity();",
+ " try {",
+ " red();",
+ " } finally {",
+ " Binder.restoreCallingIdentity(token);",
+ " }",
+ " blue();",
+ " }",
+ " public void full() {",
+ " final long token = Binder.clearCallingIdentity();",
+ " red();",
+ " blue();",
+ " }",
+ " @RequiresPermission(allOf={RED, BLUE})",
+ " public void none() {",
+ " red();",
+ " blue();",
+ " final long token = Binder.clearCallingIdentity();",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testSuppressLint() {
+ compilationHelper
+ .addSourceFile("/android/annotation/RequiresPermission.java")
+ .addSourceFile("/android/annotation/SuppressLint.java")
+ .addSourceLines("Example.java",
+ "import android.annotation.RequiresPermission;",
+ "import android.annotation.SuppressLint;",
+ "@SuppressLint(\"AndroidFrameworkRequiresPermission\")",
+ "abstract class Parent {",
+ " private static final String RED = \"red\";",
+ " @RequiresPermission(RED) abstract int red();",
+ "}",
+ "abstract class Child extends Parent {",
+ " private static final String BLUE = \"blue\";",
+ " @RequiresPermission(BLUE) abstract int blue();",
+ " public void toParent() { red(); }",
+ " public void toSibling() { blue(); }",
+ "}")
+ .doTest();
+ }
+}
diff --git a/errorprone/tests/res/android/annotation/RequiresPermission.java b/errorprone/tests/res/android/annotation/RequiresPermission.java
new file mode 100644
index 000000000000..670eb3b619ce
--- /dev/null
+++ b/errorprone/tests/res/android/annotation/RequiresPermission.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 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.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Retention(SOURCE)
+@Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER})
+public @interface RequiresPermission {
+ String value() default "";
+ String[] allOf() default {};
+ String[] anyOf() default {};
+}
diff --git a/errorprone/tests/res/android/annotation/SuppressLint.java b/errorprone/tests/res/android/annotation/SuppressLint.java
new file mode 100644
index 000000000000..4150c478cc69
--- /dev/null
+++ b/errorprone/tests/res/android/annotation/SuppressLint.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 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.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressLint {
+ String[] value();
+}
diff --git a/errorprone/tests/res/android/content/BroadcastReceiver.java b/errorprone/tests/res/android/content/BroadcastReceiver.java
new file mode 100644
index 000000000000..9d066b768015
--- /dev/null
+++ b/errorprone/tests/res/android/content/BroadcastReceiver.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 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.content;
+
+public class BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/errorprone/tests/res/android/content/Context.java b/errorprone/tests/res/android/content/Context.java
index 7ba3fbb56245..323b8dd46e8f 100644
--- a/errorprone/tests/res/android/content/Context.java
+++ b/errorprone/tests/res/android/content/Context.java
@@ -20,4 +20,7 @@ public class Context {
public int getUserId() {
return 0;
}
+
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ }
}
diff --git a/errorprone/tests/res/android/database/ContentObserver.java b/errorprone/tests/res/android/database/ContentObserver.java
new file mode 100644
index 000000000000..4c73a10cad26
--- /dev/null
+++ b/errorprone/tests/res/android/database/ContentObserver.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 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.database;
+
+public abstract class ContentObserver {
+ public void onChange(boolean selfChange) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/errorprone/tests/res/android/foo/IColorService.java b/errorprone/tests/res/android/foo/IColorService.java
new file mode 100644
index 000000000000..20c8e95832e0
--- /dev/null
+++ b/errorprone/tests/res/android/foo/IColorService.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.foo;
+
+import android.annotation.RequiresPermission;
+
+public interface IColorService extends android.os.IInterface {
+ public static final String RED = "red";
+ public static final String BLUE = "blue";
+
+ public void none();
+ @RequiresPermission(RED)
+ public void red();
+ @RequiresPermission(allOf = { RED, BLUE })
+ public void redAndBlue();
+ @RequiresPermission(anyOf = { RED, BLUE })
+ public void redOrBlue();
+}
diff --git a/errorprone/tests/res/android/os/Handler.java b/errorprone/tests/res/android/os/Handler.java
new file mode 100644
index 000000000000..f001896cc497
--- /dev/null
+++ b/errorprone/tests/res/android/os/Handler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 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.os;
+
+public class Handler {
+ public void handleMessage(Message msg) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/errorprone/tests/res/android/os/IBinder.java b/errorprone/tests/res/android/os/IBinder.java
new file mode 100644
index 000000000000..214a396d4fde
--- /dev/null
+++ b/errorprone/tests/res/android/os/IBinder.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 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.os;
+
+public interface IBinder {
+ public interface DeathRecipient {
+ public void binderDied();
+ }
+}
diff --git a/errorprone/tests/res/android/os/Message.java b/errorprone/tests/res/android/os/Message.java
new file mode 100644
index 000000000000..2421263969e9
--- /dev/null
+++ b/errorprone/tests/res/android/os/Message.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2021 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.os;
+
+public class Message {
+}
diff --git a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
index aa56da5773e9..197321f1cb6a 100644
--- a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
+++ b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.RequiresPermission;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
@@ -106,6 +107,7 @@ class BluetoothAirplaneModeListener {
}
@VisibleForTesting
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
void handleAirplaneModeChange() {
if (shouldSkipAirplaneModeChange()) {
Log.i(TAG, "Ignore airplane mode change");
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 09cfac005677..feed2205dc41 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -23,6 +23,8 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.UserHandle.USER_SYSTEM;
import android.Manifest;
+import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -304,6 +306,19 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
"Need BLUETOOTH_PRIVILEGED permission");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return onFactoryResetInternal();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
+ private boolean onFactoryResetInternal() {
// Wait for stable state if bluetooth is temporary state.
int state = getState();
if (state == BluetoothAdapter.STATE_BLE_TURNING_ON
@@ -343,6 +358,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return false;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public void onAirplaneModeChanged() {
synchronized (this) {
if (isBluetoothPersistedStateOn()) {
@@ -707,9 +723,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
- if (!checkConnectPermissionForPreflight(mContext)) {
- return;
- }
if (callback == null) {
Slog.w(TAG, "registerStateChangeCallback: Callback is null!");
return;
@@ -720,9 +733,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
- if (!checkConnectPermissionForPreflight(mContext)) {
- return;
- }
if (callback == null) {
Slog.w(TAG, "unregisterStateChangeCallback: Callback is null!");
return;
@@ -935,6 +945,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return appCount;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private boolean checkBluetoothPermissions(String packageName, boolean requireForeground) {
if (isBluetoothDisallowed()) {
if (DBG) {
@@ -990,6 +1001,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return true;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean disableBle(String packageName, IBinder token) throws RemoteException {
if (!checkBluetoothPermissions(packageName, false)) {
if (DBG) {
@@ -1040,6 +1052,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
* Call IBluetooth.onLeServiceUp() to continue if Bluetooth should be on,
* call IBluetooth.onBrEdrDown() to disable if Bluetooth should be off.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
private void continueFromBleOnState() {
if (DBG) {
Slog.d(TAG, "continueFromBleOnState()");
@@ -1072,6 +1085,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
* Inform BluetoothAdapter instances that BREDR part is down
* and turn off all service and stack if no LE app needs it
*/
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
private void sendBrEdrDownCallback() {
if (DBG) {
Slog.d(TAG, "Calling sendBrEdrDownCallback callbacks");
@@ -1265,12 +1282,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
*
* @hide
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
private boolean checkBluetoothPermissionWhenWirelessConsentRequired() {
int result = mContext.checkCallingPermission(
android.Manifest.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED);
return result == PackageManager.PERMISSION_GRANTED;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public void unbindAndFinish() {
if (DBG) {
Slog.d(TAG, "unbindAndFinish(): " + mBluetooth + " mBinding = " + mBinding
@@ -2300,6 +2319,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED
+ })
private void restartForReason(int reason) {
try {
mBluetoothLock.readLock().lock();
@@ -2376,6 +2399,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void handleEnable(boolean quietMode) {
mQuietEnable = quietMode;
@@ -2418,6 +2442,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return true;
}
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private void handleDisable() {
try {
mBluetoothLock.readLock().lock();
@@ -2475,6 +2500,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_CONNECT);
}
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
private void bluetoothStateChangeHandler(int prevState, int newState) {
boolean isStandardBroadcast = true;
if (prevState == newState) { // No change. Nothing to do.
@@ -2615,6 +2644,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
}
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.BLUETOOTH_CONNECT,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED,
+ })
private void recoverBluetoothServiceFromError(boolean clearBle) {
Slog.e(TAG, "recoverBluetoothServiceFromError");
try {
@@ -2848,6 +2881,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
*
* <p>Should be used in situations where the app op should not be noted.
*/
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
private static boolean checkConnectPermissionForPreflight(Context context) {
int permissionCheckResult = PermissionChecker.checkCallingOrSelfPermissionForPreflight(
context, BLUETOOTH_CONNECT);
diff --git a/services/core/java/com/android/server/BluetoothModeChangeHelper.java b/services/core/java/com/android/server/BluetoothModeChangeHelper.java
index 242fa848c25e..3642e4dccf34 100644
--- a/services/core/java/com/android/server/BluetoothModeChangeHelper.java
+++ b/services/core/java/com/android/server/BluetoothModeChangeHelper.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHearingAid;
@@ -101,6 +102,7 @@ public class BluetoothModeChangeHelper {
}
@VisibleForTesting
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
public void onAirplaneModeChanged(BluetoothManagerService managerService) {
managerService.onAirplaneModeChanged();
}