diff options
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(); } |