diff options
| author | Xin Li <delphij@google.com> | 2021-10-06 22:53:28 +0000 |
|---|---|---|
| committer | Xin Li <delphij@google.com> | 2021-10-06 22:53:28 +0000 |
| commit | 68e41e54ff587aa4d6976b57f91c2c71dda03227 (patch) | |
| tree | 81737c0faf16ad7c721df5c0e039e641041bec9c /framework/java/android/bluetooth/BluetoothDevice.java | |
| parent | 7151fef225d7b92b21c938dab2d5c5aac0ae6864 (diff) | |
| parent | faffc6e464445c0378296c2106f9f6b7075d23ec (diff) | |
Merge Android 12
Bug: 202323961
Merged-In: Iba1443da42161f4a41830081f2e1985b30444cc0
Change-Id: I2bebe60bb7114706a3ba6af35522268cdf031f41
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothDevice.java')
| -rw-r--r-- | framework/java/android/bluetooth/BluetoothDevice.java | 554 |
1 files changed, 441 insertions, 113 deletions
diff --git a/framework/java/android/bluetooth/BluetoothDevice.java b/framework/java/android/bluetooth/BluetoothDevice.java index 1054b4cd49..c71fcc637c 100644 --- a/framework/java/android/bluetooth/BluetoothDevice.java +++ b/framework/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,7 +25,15 @@ 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.Attributable; +import android.content.AttributionSource; import android.content.Context; import android.os.Build; import android.os.Handler; @@ -65,9 +72,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> @@ -80,7 +84,7 @@ import java.util.UUID; * {@see BluetoothAdapter} * {@see BluetoothSocket} */ -public final class BluetoothDevice implements Parcelable { +public final class BluetoothDevice implements Parcelable, Attributable { private static final String TAG = "BluetoothDevice"; private static final boolean DBG = false; @@ -107,10 +111,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} and/or {@link #EXTRA_IS_COORDINATED_SET_MEMBER} 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"; @@ -119,9 +125,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"; @@ -132,8 +140,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"; @@ -145,8 +155,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"; @@ -157,8 +169,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"; @@ -168,8 +182,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"; @@ -178,9 +194,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"; @@ -190,10 +208,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"; @@ -203,10 +223,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"; @@ -337,6 +359,26 @@ public final class BluetoothDevice implements Parcelable { public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY"; /** + * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} + * intents as the value of passkey. + * @hide + */ + public static final String EXTRA_PAIRING_INITIATOR = + "android.bluetooth.device.extra.PAIRING_INITIATOR"; + + /** + * Bluetooth pairing initiator, Foreground App + * @hide + */ + public static final int EXTRA_PAIRING_INITIATOR_FOREGROUND = 1; + + /** + * Bluetooth pairing initiator, Background + * @hide + */ + public static final int EXTRA_PAIRING_INITIATOR_BACKGROUND = 2; + + /** * Bluetooth device type, Unknown */ public static final int DEVICE_TYPE_UNKNOWN = 0; @@ -358,6 +400,8 @@ public final class BluetoothDevice implements Parcelable { /** @hide */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final String ACTION_SDP_RECORD = @@ -630,13 +674,17 @@ 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 + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_UUID = "android.bluetooth.device.action.UUID"; /** @hide */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_MAS_INSTANCE = "android.bluetooth.device.action.MAS_INSTANCE"; @@ -645,40 +693,51 @@ 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 + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST"; /** @hide */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @UnsupportedAppUsage public static final String ACTION_PAIRING_CANCEL = "android.bluetooth.device.action.PAIRING_CANCEL"; /** @hide */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CONNECTION_ACCESS_REQUEST = "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST"; /** @hide */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CONNECTION_ACCESS_REPLY = "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY"; /** @hide */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CONNECTION_ACCESS_CANCEL = "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL"; @@ -689,6 +748,8 @@ public final class BluetoothDevice implements Parcelable { * * @hide */ + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @SystemApi public static final String ACTION_SILENCE_MODE_CHANGED = @@ -1056,6 +1117,8 @@ public final class BluetoothDevice implements Parcelable { private final String mAddress; @AddressType private final int mAddressType; + private AttributionSource mAttributionSource; + /*package*/ @UnsupportedAppUsage static IBluetooth getService() { @@ -1101,6 +1164,7 @@ public final class BluetoothDevice implements Parcelable { * and is validated in this constructor. * * @param address valid Bluetooth MAC address + * @param attributionSource attribution for permission-protected calls * @throws RuntimeException Bluetooth is not available on this platform * @throws IllegalArgumentException address is invalid * @hide @@ -1114,10 +1178,21 @@ public final class BluetoothDevice implements Parcelable { mAddress = address; mAddressType = ADDRESS_TYPE_PUBLIC; + mAttributionSource = BluetoothManager.resolveAttributionSource(null); + } + + /** {@hide} */ + public void setAttributionSource(@NonNull AttributionSource attributionSource) { + mAttributionSource = attributionSource; + } + + /** {@hide} */ + public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) { + setAttributionSource(attributionSource); } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (o instanceof BluetoothDevice) { return mAddress.equals(((BluetoothDevice) o).getAddress()); } @@ -1176,6 +1251,18 @@ public final class BluetoothDevice implements Parcelable { } /** + * Returns the anonymized hardware address of this BluetoothDevice. The first three octets + * will be suppressed for anonymization. + * <p> For example, "XX:XX:XX:AA:BB:CC". + * + * @return Anonymized bluetooth hardware address as string + * @hide + */ + public String getAnonymizedAddress() { + return "XX:XX:XX" + getAddress().substring(8); + } + + /** * Get the friendly Bluetooth name of the remote device. * * <p>The local adapter will automatically retrieve remote names when @@ -1184,7 +1271,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) { @@ -1192,7 +1281,7 @@ public final class BluetoothDevice implements Parcelable { return null; } try { - String name = service.getRemoteName(this); + String name = service.getRemoteName(this, mAttributionSource); if (name != null) { // remove whitespace characters from the name return name @@ -1213,7 +1302,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) { @@ -1221,7 +1312,7 @@ public final class BluetoothDevice implements Parcelable { return DEVICE_TYPE_UNKNOWN; } try { - return service.getRemoteType(this); + return service.getRemoteType(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1229,14 +1320,15 @@ public final class BluetoothDevice implements Parcelable { } /** - * Get the Bluetooth alias of the remote device. - * <p>Alias is the locally modified name of a remote device. + * Get the locally modifiable name (alias) of the remote Bluetooth device. * * @return the Bluetooth alias, the friendly device name if no alias, or * 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) { @@ -1244,7 +1336,7 @@ public final class BluetoothDevice implements Parcelable { return null; } try { - String alias = service.getRemoteAlias(this); + String alias = service.getRemoteAliasWithAttribution(this, mAttributionSource); if (alias == null) { return getName(); } @@ -1255,30 +1347,53 @@ public final class BluetoothDevice implements Parcelable { return null; } - /** - * Set the Bluetooth alias of the remote device. - * <p>Alias is the locally modified name of a remote device. - * <p>This methoid overwrites the alias. The changed - * alias is saved in the local storage so that the change - * is preserved over power cycle. - * - * @return true on success, false on error - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @RequiresPermission(Manifest.permission.BLUETOOTH) - public boolean setAlias(@NonNull String alias) { + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + BluetoothStatusCodes.SUCCESS, + BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, + BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED, + BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, + BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED + }) + public @interface SetAliasReturnValues{} + + /** + * Sets the locally modifiable name (alias) of the remote Bluetooth device. This method + * overwrites the previously stored alias. The new alias is saved in local + * storage so that the change is preserved over power cycles. + * + * <p>This method requires the calling app to be associated with Companion Device Manager (see + * {@link android.companion.CompanionDeviceManager#associate(AssociationRequest, + * android.companion.CompanionDeviceManager.Callback, Handler)}) and have the + * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission. Alternatively, if the + * caller has the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission, they can + * bypass the Companion Device Manager association requirement as well as other permission + * requirements. + * + * @param alias is the new locally modifiable name for the remote Bluetooth device which must + * be the empty string. If null, we clear the alias. + * @return whether the alias was successfully changed + * @throws IllegalArgumentException if the alias is the empty string + */ + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) + public @SetAliasReturnValues int setAlias(@Nullable String alias) { + if (alias != null && alias.isEmpty()) { + throw new IllegalArgumentException("alias cannot be the empty string"); + } final IBluetooth service = sService; if (service == null) { Log.e(TAG, "BT not enabled. Cannot set Remote Device name"); - return false; + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; } try { - return service.setRemoteAlias(this, alias); + return service.setRemoteAlias(this, alias, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); + throw e.rethrowFromSystemServer(); } - return false; } /** @@ -1290,7 +1405,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) { @@ -1298,7 +1415,7 @@ public final class BluetoothDevice implements Parcelable { return BATTERY_LEVEL_BLUETOOTH_OFF; } try { - return service.getBatteryLevel(this); + return service.getBatteryLevel(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1315,7 +1432,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); } @@ -1336,7 +1455,9 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) + @RequiresLegacyBluetoothAdminPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBond(int transport) { return createBondInternal(transport, null, null); } @@ -1364,7 +1485,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) { @@ -1375,6 +1496,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; @@ -1387,7 +1509,8 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.createBond(this, transport, remoteP192Data, remoteP256Data); + return service.createBond( + this, transport, remoteP192Data, remoteP256Data, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1402,7 +1525,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) { @@ -1410,7 +1535,7 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.isBondingInitiatedLocally(this); + return service.isBondingInitiatedLocally(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1424,7 +1549,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) { @@ -1435,7 +1560,7 @@ public final class BluetoothDevice implements Parcelable { Log.i(TAG, "cancelBondProcess() for device " + getAddress() + " called by pid: " + Process.myPid() + " tid: " + Process.myTid()); - return service.cancelBondProcess(this); + return service.cancelBondProcess(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1452,7 +1577,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) { @@ -1463,7 +1588,7 @@ public final class BluetoothDevice implements Parcelable { Log.i(TAG, "removeBond() for device " + getAddress() + " called by pid: " + Process.myPid() + " tid: " + Process.myTid()); - return service.removeBond(this); + return service.removeBond(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1476,9 +1601,10 @@ 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); + return sService.getBondState(query, mAttributionSource); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -1504,7 +1630,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) { @@ -1524,13 +1653,127 @@ public final class BluetoothDevice implements Parcelable { } /** + * Checks whether this bluetooth device is associated with CDM and meets the criteria to skip + * the bluetooth pairing dialog because it has been already consented by the CDM prompt. + * + * @return true if we can bond without the dialog, false otherwise + * + * @hide + */ + @SystemApi + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public boolean canBondWithoutDialog() { + final IBluetooth service = sService; + if (service == null) { + Log.e(TAG, "BT not enabled. Cannot check if we can skip pairing dialog"); + return false; + } + try { + if (DBG) Log.d(TAG, "canBondWithoutDialog, device: " + this); + return service.canBondWithoutDialog(this, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + return false; + } + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + BluetoothStatusCodes.SUCCESS, + BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, + BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED, + BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, + BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED + }) + public @interface ConnectionReturnValues{} + + /** + * Connects all user enabled and supported bluetooth profiles between the local and remote + * device. If no profiles are user enabled (e.g. first connection), we connect all supported + * profiles. If the device is not already connected, this will page the device before initiating + * profile connections. Connection is asynchronous and you should listen to each profile's + * broadcast intent ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful. + * For example, to verify a2dp is connected, you would listen for + * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} + * + * @return whether the messages were successfully sent to try to connect all profiles + * @throws IllegalArgumentException if the device address is invalid + * + * @hide + */ + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + android.Manifest.permission.MODIFY_PHONE_STATE, + }) + public @ConnectionReturnValues int connect() { + if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + + try { + if (sService == null) { + Log.e(TAG, "BT not enabled. Cannot connect to remote device."); + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + return sService.connectAllEnabledProfiles(this, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Disconnects all connected bluetooth profiles between the local and remote device. + * Disconnection is asynchronous and you should listen to each profile's broadcast intent + * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example, + * to verify a2dp is disconnected, you would listen for + * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} + * + * @return whether the messages were successfully sent to try to disconnect all profiles + * @throws IllegalArgumentException if the device address is invalid + * + * @hide + */ + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public @ConnectionReturnValues int disconnect() { + if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + + try { + if (sService == null) { + Log.e(TAG, "BT not enabled. Cannot disconnect from remote device."); + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + return sService.disconnectAllEnabledProfiles(this, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "", e); + throw e.rethrowFromSystemServer(); + } + } + + /** * Returns whether there is an open connection to this device. * * @return True if there is at least one open connection to this device. * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isConnected() { final IBluetooth service = sService; if (service == null) { @@ -1538,7 +1781,8 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.getConnectionState(this) != CONNECTION_STATE_DISCONNECTED; + return service.getConnectionStateWithAttribution(this, mAttributionSource) + != CONNECTION_STATE_DISCONNECTED; } catch (RemoteException e) { Log.e(TAG, "", e); return false; @@ -1553,7 +1797,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) { @@ -1561,7 +1807,8 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.getConnectionState(this) > CONNECTION_STATE_CONNECTED; + return service.getConnectionStateWithAttribution(this, mAttributionSource) + > CONNECTION_STATE_CONNECTED; } catch (RemoteException e) { Log.e(TAG, "", e); return false; @@ -1573,7 +1820,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) { @@ -1581,7 +1830,7 @@ public final class BluetoothDevice implements Parcelable { return null; } try { - int classInt = service.getRemoteClass(this); + int classInt = service.getRemoteClass(this, mAttributionSource); if (classInt == BluetoothClass.ERROR) return null; return new BluetoothClass(classInt); } catch (RemoteException e) { @@ -1600,7 +1849,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()) { @@ -1608,7 +1859,7 @@ public final class BluetoothDevice implements Parcelable { return null; } try { - return service.getRemoteUuids(this); + return service.getRemoteUuids(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1629,7 +1880,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 or cached UUIDs will be broadcast. */ - @RequiresPermission(Manifest.permission.BLUETOOTH) + @RequiresLegacyBluetoothPermission + @RequiresBluetoothConnectPermission + @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean fetchUuidsWithSdp() { return fetchUuidsWithSdp(TRANSPORT_AUTO); } @@ -1654,7 +1907,10 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean fetchUuidsWithSdp(@Transport int transport) { final IBluetooth service = sService; if (service == null || !isBluetoothEnabled()) { @@ -1662,7 +1918,7 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.fetchRemoteUuids(this, transport); + return service.fetchRemoteUuidsWithAttribution(this, transport, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1680,8 +1936,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. * @@ -1690,6 +1945,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) { @@ -1697,7 +1955,7 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.sdpSearch(this, uuid); + return service.sdpSearch(this, uuid, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1706,10 +1964,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) { @@ -1717,7 +1977,7 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.setPin(this, true, pin.length, pin); + return service.setPin(this, true, pin.length, pin, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1731,7 +1991,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) { @@ -1745,7 +2007,10 @@ public final class BluetoothDevice implements Parcelable { * * @return true confirmation has been sent out false for error */ - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setPairingConfirmation(boolean confirm) { final IBluetooth service = sService; if (service == null) { @@ -1753,7 +2018,7 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.setPairingConfirmation(this, confirm); + return service.setPairingConfirmation(this, confirm, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1768,7 +2033,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) { @@ -1776,7 +2043,7 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.cancelBondProcess(this); + return service.cancelBondProcess(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1800,14 +2067,16 @@ 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) { return ACCESS_UNKNOWN; } try { - return service.getPhonebookAccessPermission(this); + return service.getPhonebookAccessPermission(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1832,22 +2101,23 @@ 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. * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setSilenceMode(boolean silence) { final IBluetooth service = sService; if (service == null) { throw new IllegalStateException("Bluetooth is not turned ON"); } try { - return service.setSilenceMode(this, silence); + return service.setSilenceMode(this, silence, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "setSilenceMode fail", e); return false; @@ -1857,21 +2127,22 @@ 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 */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean isInSilenceMode() { final IBluetooth service = sService; if (service == null) { throw new IllegalStateException("Bluetooth is not turned ON"); } try { - return service.getSilenceMode(this); + return service.getSilenceMode(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "isInSilenceMode fail", e); return false; @@ -1887,14 +2158,17 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setPhonebookAccessPermission(@AccessPermission int value) { final IBluetooth service = sService; if (service == null) { return false; } try { - return service.setPhonebookAccessPermission(this, value); + return service.setPhonebookAccessPermission(this, value, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1908,14 +2182,16 @@ 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) { return ACCESS_UNKNOWN; } try { - return service.getMessageAccessPermission(this); + return service.getMessageAccessPermission(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1932,7 +2208,10 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + 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) { @@ -1943,7 +2222,7 @@ public final class BluetoothDevice implements Parcelable { return false; } try { - return service.setMessageAccessPermission(this, value); + return service.setMessageAccessPermission(this, value, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1957,14 +2236,16 @@ 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) { return ACCESS_UNKNOWN; } try { - return service.getSimAccessPermission(this); + return service.getSimAccessPermission(this, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1981,14 +2262,17 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setSimAccessPermission(int value) { final IBluetooth service = sService; if (service == null) { return false; } try { - return service.setSimAccessPermission(this, value); + return service.setSimAccessPermission(this, value, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -2012,7 +2296,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 @@ -2021,6 +2304,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"); @@ -2047,7 +2334,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 @@ -2055,6 +2341,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); @@ -2068,7 +2358,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 @@ -2076,6 +2365,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); @@ -2111,7 +2404,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"); @@ -2149,7 +2445,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"); @@ -2165,7 +2464,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 @@ -2175,6 +2473,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"); @@ -2187,7 +2489,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 @@ -2195,6 +2496,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"); @@ -2242,6 +2547,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)); @@ -2262,6 +2569,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)); @@ -2286,6 +2595,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); @@ -2312,6 +2623,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) { @@ -2345,6 +2658,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) { @@ -2362,7 +2677,8 @@ public final class BluetoothDevice implements Parcelable { // BLE is not supported return null; } - BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport, opportunistic, phy); + BluetoothGatt gatt = new BluetoothGatt( + iGatt, this, transport, opportunistic, phy, mAttributionSource); gatt.connect(autoConnect, callback, handler); return gatt; } catch (RemoteException e) { @@ -2389,7 +2705,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"); @@ -2417,7 +2736,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"); @@ -2445,7 +2767,10 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) { final IBluetooth service = sService; if (service == null) { @@ -2457,7 +2782,7 @@ public final class BluetoothDevice implements Parcelable { + ", should not over " + METADATA_MAX_LENGTH); } try { - return service.setMetadata(this, key, value); + return service.setMetadata(this, key, value, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "setMetadata fail", e); return false; @@ -2473,7 +2798,10 @@ public final class BluetoothDevice implements Parcelable { */ @SystemApi @Nullable - @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) public byte[] getMetadata(@MetadataKey int key) { final IBluetooth service = sService; if (service == null) { @@ -2481,7 +2809,7 @@ public final class BluetoothDevice implements Parcelable { return null; } try { - return service.getMetadata(this, key); + return service.getMetadata(this, key, mAttributionSource); } catch (RemoteException e) { Log.e(TAG, "getMetadata fail", e); return null; |
