1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.bluetooth; 18 19 import static android.Manifest.permission.BLUETOOTH_CONNECT; 20 import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; 21 import static android.Manifest.permission.BLUETOOTH_SCAN; 22 import static android.Manifest.permission.MODIFY_PHONE_STATE; 23 24 import android.annotation.BroadcastBehavior; 25 import android.annotation.FlaggedApi; 26 import android.annotation.IntDef; 27 import android.annotation.IntRange; 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.annotation.RequiresPermission; 31 import android.annotation.SdkConstant; 32 import android.annotation.SdkConstant.SdkConstantType; 33 import android.annotation.SuppressLint; 34 import android.annotation.SystemApi; 35 import android.app.compat.CompatChanges; 36 import android.bluetooth.annotations.RequiresBluetoothConnectPermission; 37 import android.bluetooth.annotations.RequiresBluetoothLocationPermission; 38 import android.bluetooth.annotations.RequiresBluetoothScanPermission; 39 import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; 40 import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; 41 import android.companion.AssociationRequest; 42 import android.compat.annotation.ChangeId; 43 import android.compat.annotation.EnabledSince; 44 import android.compat.annotation.UnsupportedAppUsage; 45 import android.content.AttributionSource; 46 import android.content.Context; 47 import android.os.Build; 48 import android.os.Handler; 49 import android.os.IpcDataCache; 50 import android.os.Parcel; 51 import android.os.ParcelUuid; 52 import android.os.Parcelable; 53 import android.os.Process; 54 import android.os.RemoteException; 55 import android.util.Log; 56 import android.util.Pair; 57 58 import com.android.bluetooth.flags.Flags; 59 60 import java.io.IOException; 61 import java.lang.annotation.Retention; 62 import java.lang.annotation.RetentionPolicy; 63 import java.nio.charset.StandardCharsets; 64 import java.util.List; 65 import java.util.UUID; 66 67 /** 68 * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you create a connection with 69 * the respective device or query information about it, such as the name, address, class, and 70 * bonding state. 71 * 72 * <p>This class is really just a thin wrapper for a Bluetooth hardware address. Objects of this 73 * class are immutable. Operations on this class are performed on the remote Bluetooth hardware 74 * address, using the {@link BluetoothAdapter} that was used to create this {@link BluetoothDevice}. 75 * 76 * <p>To get a {@link BluetoothDevice}, use {@link BluetoothAdapter#getRemoteDevice(String) 77 * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device of a known MAC 78 * address (which you can get through device discovery with {@link BluetoothAdapter}) or get one 79 * from the set of bonded devices returned by {@link BluetoothAdapter#getBondedDevices() 80 * BluetoothAdapter.getBondedDevices()}. You can then open a {@link BluetoothSocket} for 81 * communication with the remote device, using {@link #createRfcommSocketToServiceRecord(UUID)} over 82 * Bluetooth BR/EDR or using {@link #createL2capChannel(int)} over Bluetooth LE. 83 * 84 * <p><div class="special reference"> 85 * 86 * <h3>Developer Guides</h3> 87 * 88 * <p>For more information about using Bluetooth, read the <a href= 89 * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide. </div> 90 * 91 * @see BluetoothAdapter 92 * @see BluetoothSocket 93 */ 94 public final class BluetoothDevice implements Parcelable, Attributable { 95 private static final String TAG = BluetoothDevice.class.getSimpleName(); 96 97 private static final boolean DBG = false; 98 99 /** 100 * Connection state bitmask disconnected bit as returned by getConnectionState. 101 * 102 * @hide 103 */ 104 public static final int CONNECTION_STATE_DISCONNECTED = 0; 105 106 /** 107 * Connection state bitmask connected bit as returned by getConnectionState. 108 * 109 * @hide 110 */ 111 public static final int CONNECTION_STATE_CONNECTED = 1; 112 113 /** 114 * Connection state bitmask encrypted BREDR bit as returned by getConnectionState. 115 * 116 * @hide 117 */ 118 public static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2; 119 120 /** 121 * Connection state bitmask encrypted LE bit as returned by getConnectionState. 122 * 123 * @hide 124 */ 125 public static final int CONNECTION_STATE_ENCRYPTED_LE = 4; 126 127 /** 128 * Sentinel error value for this class. Guaranteed to not equal any other integer constant in 129 * this class. Provided as a convenience for functions that require a sentinel error value, for 130 * example: 131 * 132 * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 133 * BluetoothDevice.ERROR)</code> 134 */ 135 public static final int ERROR = Integer.MIN_VALUE; 136 137 /** 138 * Broadcast Action: Remote device discovered. 139 * 140 * <p>Sent when a remote device is found during discovery. 141 * 142 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_CLASS}. Can 143 * contain the extra fields {@link #EXTRA_NAME} and/or {@link #EXTRA_RSSI} and/or {@link 144 * #EXTRA_IS_COORDINATED_SET_MEMBER} if they are available. 145 */ 146 // TODO: Change API to not broadcast RSSI if not available (incoming connection) 147 @RequiresLegacyBluetoothPermission 148 @RequiresBluetoothScanPermission 149 @RequiresBluetoothLocationPermission 150 @RequiresPermission(BLUETOOTH_SCAN) 151 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 152 public static final String ACTION_FOUND = "android.bluetooth.device.action.FOUND"; 153 154 /** 155 * Broadcast Action: Bluetooth class of a remote device has changed. 156 * 157 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_CLASS}. 158 * 159 * @see BluetoothClass 160 */ 161 @RequiresLegacyBluetoothPermission 162 @RequiresBluetoothConnectPermission 163 @RequiresPermission(BLUETOOTH_CONNECT) 164 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 165 public static final String ACTION_CLASS_CHANGED = 166 "android.bluetooth.device.action.CLASS_CHANGED"; 167 168 /** 169 * Broadcast Action: Indicates a low level (ACL) connection has been established with a remote 170 * device. 171 * 172 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_TRANSPORT}. 173 * 174 * <p>ACL connections are managed automatically by the Android Bluetooth stack. 175 */ 176 @RequiresLegacyBluetoothPermission 177 @RequiresBluetoothConnectPermission 178 @RequiresPermission(BLUETOOTH_CONNECT) 179 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 180 public static final String ACTION_ACL_CONNECTED = 181 "android.bluetooth.device.action.ACL_CONNECTED"; 182 183 /** 184 * Broadcast Action: Indicates that a low level (ACL) disconnection has been requested for a 185 * remote device, and it will soon be disconnected. 186 * 187 * <p>This is useful for graceful disconnection. Applications should use this intent as a hint 188 * to immediately terminate higher level connections (RFCOMM, L2CAP, or profile connections) to 189 * the remote device. 190 * 191 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 192 */ 193 @RequiresLegacyBluetoothPermission 194 @RequiresBluetoothConnectPermission 195 @RequiresPermission(BLUETOOTH_CONNECT) 196 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 197 public static final String ACTION_ACL_DISCONNECT_REQUESTED = 198 "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED"; 199 200 /** 201 * Broadcast Action: Indicates a low level (ACL) disconnection from a remote device. 202 * 203 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_TRANSPORT}. 204 * 205 * <p>ACL connections are managed automatically by the Android Bluetooth stack. 206 */ 207 @RequiresLegacyBluetoothPermission 208 @RequiresBluetoothConnectPermission 209 @RequiresPermission(BLUETOOTH_CONNECT) 210 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 211 public static final String ACTION_ACL_DISCONNECTED = 212 "android.bluetooth.device.action.ACL_DISCONNECTED"; 213 214 /** 215 * Broadcast Action: Indicates the friendly name of a remote device has been retrieved for the 216 * first time, or changed since the last retrieval. 217 * 218 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_NAME}. 219 */ 220 @RequiresLegacyBluetoothPermission 221 @RequiresBluetoothConnectPermission 222 @RequiresPermission(BLUETOOTH_CONNECT) 223 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 224 public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED"; 225 226 /** 227 * Broadcast Action: Indicates the alias of a remote device has been changed. 228 * 229 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 230 */ 231 @SuppressLint("ActionValue") 232 @RequiresLegacyBluetoothPermission 233 @RequiresBluetoothConnectPermission 234 @RequiresPermission(BLUETOOTH_CONNECT) 235 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 236 public static final String ACTION_ALIAS_CHANGED = 237 "android.bluetooth.device.action.ALIAS_CHANGED"; 238 239 /** 240 * Broadcast Action: Indicates a change in the bond state of a remote device. For example, if a 241 * device is bonded (paired). 242 * 243 * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link #EXTRA_BOND_STATE} and 244 * {@link #EXTRA_PREVIOUS_BOND_STATE}. 245 */ 246 // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also 247 // contain a hidden extra field EXTRA_UNBOND_REASON with the result code. 248 @RequiresLegacyBluetoothPermission 249 @RequiresBluetoothConnectPermission 250 @RequiresPermission(BLUETOOTH_CONNECT) 251 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 252 public static final String ACTION_BOND_STATE_CHANGED = 253 "android.bluetooth.device.action.BOND_STATE_CHANGED"; 254 255 /** 256 * Broadcast Action: Indicates the battery level of a remote device has been retrieved for the 257 * first time, or changed since the last retrieval 258 * 259 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_BATTERY_LEVEL}. 260 * 261 * @hide 262 */ 263 @SystemApi 264 @RequiresLegacyBluetoothPermission 265 @RequiresBluetoothConnectPermission 266 @RequiresPermission(BLUETOOTH_CONNECT) 267 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 268 @SuppressLint("ActionValue") 269 public static final String ACTION_BATTERY_LEVEL_CHANGED = 270 "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED"; 271 272 /** 273 * Broadcast Action: Indicates the audio buffer size should be switched between a low latency 274 * buffer size and a higher and larger latency buffer size. Only registered receivers will 275 * receive this intent. 276 * 277 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 278 * #EXTRA_LOW_LATENCY_BUFFER_SIZE}. 279 * 280 * @hide 281 */ 282 @SuppressLint("ActionValue") 283 @RequiresBluetoothConnectPermission 284 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) 285 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 286 @SystemApi 287 public static final String ACTION_SWITCH_BUFFER_SIZE = 288 "android.bluetooth.device.action.SWITCH_BUFFER_SIZE"; 289 290 /** 291 * Broadcast Action: Indicates that previously bonded device couldn't provide keys to establish 292 * encryption. This can have numerous reasons, i.e.: 293 * 294 * <ul> 295 * <li>remote was factory reset, or removed bond 296 * <li>spoofing attack, someone is impersonating remote device 297 * <li>in case of LE devices, very unlikely address collision 298 * </ul> 299 * 300 * <p>Always contains the extra field {@link #EXTRA_DEVICE} 301 * 302 * <p>This method requires the calling app to have the {@link 303 * android.Manifest.permission#BLUETOOTH_CONNECT} permission. Before {@link 304 * android.os.Build.VERSION_CODES#BAKLAVA} this method also required {@link 305 * android.Manifest.permission#BLUETOOTH_PRIVILEGED} 306 */ 307 @SuppressLint("ActionValue") 308 @RequiresPermission( 309 allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}, 310 conditional = true) 311 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 312 @BroadcastBehavior(protectedBroadcast = true) 313 @FlaggedApi(Flags.FLAG_KEY_MISSING_PUBLIC) 314 public static final String ACTION_KEY_MISSING = "android.bluetooth.device.action.KEY_MISSING"; 315 316 /** 317 * Broadcast Action: Indicates that encryption state changed 318 * 319 * <p>Always contains the extra field {@link #EXTRA_DEVICE} 320 * 321 * <p>Always contains the extra field {@link #EXTRA_TRANSPORT} 322 * 323 * <p>Always contains the extra field {@link #EXTRA_ENCRYPTION_STATUS} 324 * 325 * <p>Always contains the extra field {@link #EXTRA_ENCRYPTION_ENABLED} 326 * 327 * <p>Always contains the extra field {@link #EXTRA_KEY_SIZE} 328 * 329 * <p>Always contains the extra field {@link #EXTRA_ENCRYPTION_ALGORITHM} 330 */ 331 @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST) 332 @SuppressLint("ActionValue") 333 @RequiresPermission(BLUETOOTH_CONNECT) 334 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 335 @BroadcastBehavior(protectedBroadcast = true) 336 public static final String ACTION_ENCRYPTION_CHANGE = 337 "android.bluetooth.device.action.ENCRYPTION_CHANGE"; 338 339 /** 340 * Used as an Integer extra field in {@link #ACTION_BATTERY_LEVEL_CHANGED} intent. It contains 341 * the most recently retrieved battery level information ranging from 0% to 100% for a remote 342 * device, {@link #BATTERY_LEVEL_UNKNOWN} when the valid is unknown or there is an error, {@link 343 * #BATTERY_LEVEL_BLUETOOTH_OFF} when the bluetooth is off 344 * 345 * @hide 346 */ 347 @SuppressLint("ActionValue") 348 @SystemApi 349 public static final String EXTRA_BATTERY_LEVEL = "android.bluetooth.device.extra.BATTERY_LEVEL"; 350 351 /** 352 * Used as the unknown value for {@link #EXTRA_BATTERY_LEVEL} and {@link #getBatteryLevel()} 353 * 354 * @hide 355 */ 356 @SystemApi public static final int BATTERY_LEVEL_UNKNOWN = -1; 357 358 /** 359 * Used as an error value for {@link #getBatteryLevel()} to represent bluetooth is off 360 * 361 * @hide 362 */ 363 @SystemApi public static final int BATTERY_LEVEL_BLUETOOTH_OFF = -100; 364 365 /** 366 * Used as a Parcelable {@link BluetoothDevice} extra field in every intent broadcast by this 367 * class. It contains the {@link BluetoothDevice} that the intent applies to. 368 */ 369 public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE"; 370 371 /** 372 * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link #ACTION_FOUND} 373 * intents. It contains the friendly Bluetooth name. 374 */ 375 public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME"; 376 377 /** 378 * Used as an optional short extra field in {@link #ACTION_FOUND} intents. Contains the RSSI 379 * value of the remote device as reported by the Bluetooth hardware. 380 */ 381 public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI"; 382 383 /** 384 * Used as a boolean extra field in {@link #ACTION_FOUND} intents. It contains the information 385 * if device is discovered as member of a coordinated set or not. Pairing with device that 386 * belongs to a set would trigger pairing with the rest of set members. See Bluetooth CSIP 387 * specification for more details. 388 */ 389 public static final String EXTRA_IS_COORDINATED_SET_MEMBER = 390 "android.bluetooth.extra.IS_COORDINATED_SET_MEMBER"; 391 392 /** 393 * Used as a Parcelable {@link BluetoothClass} extra field in {@link #ACTION_FOUND} and {@link 394 * #ACTION_CLASS_CHANGED} intents. 395 */ 396 public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS"; 397 398 /** 399 * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. Contains the bond 400 * state of the remote device. 401 * 402 * <p>Possible values are: {@link #BOND_NONE}, {@link #BOND_BONDING}, {@link #BOND_BONDED}. 403 */ 404 public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE"; 405 406 /** 407 * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. Contains the 408 * previous bond state of the remote device. 409 * 410 * <p>Possible values are: {@link #BOND_NONE}, {@link #BOND_BONDING}, {@link #BOND_BONDED}. 411 */ 412 public static final String EXTRA_PREVIOUS_BOND_STATE = 413 "android.bluetooth.device.extra.PREVIOUS_BOND_STATE"; 414 415 /** 416 * Used as a boolean extra field to indicate if audio buffer size is low latency or not 417 * 418 * @hide 419 */ 420 @SuppressLint("ActionValue") 421 @SystemApi 422 public static final String EXTRA_LOW_LATENCY_BUFFER_SIZE = 423 "android.bluetooth.device.extra.LOW_LATENCY_BUFFER_SIZE"; 424 425 /** 426 * Indicates the remote device is not bonded (paired). 427 * 428 * <p>There is no shared link key with the remote device, so communication (if it is allowed at 429 * all) will be unauthenticated and unencrypted. 430 */ 431 public static final int BOND_NONE = 10; 432 433 /** Indicates bonding (pairing) is in progress with the remote device. */ 434 public static final int BOND_BONDING = 11; 435 436 /** 437 * Indicates the remote device is bonded (paired). 438 * 439 * <p>A shared link keys exists locally for the remote device, so communication can be 440 * authenticated and encrypted. 441 * 442 * <p><i>Being bonded (paired) with a remote device does not necessarily mean the device is 443 * currently connected. It just means that the pending procedure was completed at some earlier 444 * time, and the link key is still stored locally, ready to use on the next connection. </i> 445 */ 446 public static final int BOND_BONDED = 12; 447 448 /** 449 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} intents for unbond reason. 450 * Possible value are : - {@link #UNBOND_REASON_AUTH_FAILED} - {@link 451 * #UNBOND_REASON_AUTH_REJECTED} - {@link #UNBOND_REASON_AUTH_CANCELED} - {@link 452 * #UNBOND_REASON_REMOTE_DEVICE_DOWN} - {@link #UNBOND_REASON_DISCOVERY_IN_PROGRESS} - {@link 453 * #UNBOND_REASON_AUTH_TIMEOUT} - {@link #UNBOND_REASON_REPEATED_ATTEMPTS} - {@link 454 * #UNBOND_REASON_REMOTE_AUTH_CANCELED} - {@link #UNBOND_REASON_REMOVED} 455 * 456 * <p>Note: Can be added as a hidden extra field for {@link #ACTION_BOND_STATE_CHANGED} when the 457 * {@link #EXTRA_BOND_STATE} is {@link #BOND_NONE} 458 * 459 * @hide 460 */ 461 @SystemApi 462 @SuppressLint("ActionValue") 463 public static final String EXTRA_UNBOND_REASON = "android.bluetooth.device.extra.REASON"; 464 465 /** 466 * Use {@link EXTRA_UNBOND_REASON} instead 467 * 468 * @hide 469 */ 470 @UnsupportedAppUsage public static final String EXTRA_REASON = EXTRA_UNBOND_REASON; 471 472 /** 473 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} intents to indicate pairing 474 * method used. Possible values are: {@link #PAIRING_VARIANT_PIN}, {@link 475 * #PAIRING_VARIANT_PASSKEY_CONFIRMATION}, 476 */ 477 public static final String EXTRA_PAIRING_VARIANT = 478 "android.bluetooth.device.extra.PAIRING_VARIANT"; 479 480 /** 481 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} intents as the value of 482 * passkey. The Bluetooth Passkey is a 6-digit numerical value represented as integer value in 483 * the range 0x00000000 – 0x000F423F (000000 to 999999). 484 */ 485 public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY"; 486 487 /** 488 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} intents as the location of 489 * initiator. Possible value are: {@link #EXTRA_PAIRING_INITIATOR_FOREGROUND}, {@link 490 * #EXTRA_PAIRING_INITIATOR_BACKGROUND}, 491 * 492 * @hide 493 */ 494 @SystemApi 495 @SuppressLint("ActionValue") 496 public static final String EXTRA_PAIRING_INITIATOR = 497 "android.bluetooth.device.extra.PAIRING_INITIATOR"; 498 499 /** 500 * Used as an int extra field in {@link #ACTION_ENCRYPTION_CHANGE} intents as the size of the 501 * encryption key, in number of bytes. i.e. value of 16 means 16-byte, or 128 bit key size. 502 */ 503 @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST) 504 @SuppressLint("ActionValue") 505 public static final String EXTRA_KEY_SIZE = "android.bluetooth.device.extra.KEY_SIZE"; 506 507 /** 508 * Used as an int extra field in {@link #ACTION_ENCRYPTION_CHANGE} intents as the algorithm used 509 * for encryption. 510 * 511 * <p>Possible values are: {@link #ENCRYPTION_ALGORITHM_NONE}, {@link #ENCRYPTION_ALGORITHM_E0}, 512 * {@link #ENCRYPTION_ALGORITHM_AES}. 513 */ 514 @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST) 515 @SuppressLint("ActionValue") 516 public static final String EXTRA_ENCRYPTION_ALGORITHM = 517 "android.bluetooth.device.extra.EXTRA_ENCRYPTION_ALGORITHM"; 518 519 /** Indicates that link was not encrypted using any algorithm */ 520 @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST) 521 public static final int ENCRYPTION_ALGORITHM_NONE = 0; 522 523 /** Indicates link was encrypted using E0 algorithm */ 524 @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST) 525 public static final int ENCRYPTION_ALGORITHM_E0 = 1; 526 527 /** Indicates link was encrypted using AES algorithm */ 528 @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST) 529 public static final int ENCRYPTION_ALGORITHM_AES = 2; 530 531 /** 532 * Used as an int extra field in {@link #ACTION_ENCRYPTION_CHANGE} intent. This is the status 533 * value as returned from controller in "HCI Encryption Change event" i.e. value of 0 means 534 * success. 535 */ 536 @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST) 537 @SuppressLint("ActionValue") 538 public static final String EXTRA_ENCRYPTION_STATUS = 539 "android.bluetooth.device.extra.ENCRYPTION_STATUS"; 540 541 /** 542 * Used as a boolean extra field in {@link #ACTION_ENCRYPTION_CHANGE} intent. false mean 543 * encryption is OFF, true means encryption is ON 544 */ 545 @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST) 546 @SuppressLint("ActionValue") 547 public static final String EXTRA_ENCRYPTION_ENABLED = 548 "android.bluetooth.device.extra.ENCRYPTION_ENABLED"; 549 550 /** 551 * Bluetooth pairing initiator, Foreground App 552 * 553 * @hide 554 */ 555 @SystemApi public static final int EXTRA_PAIRING_INITIATOR_FOREGROUND = 1; 556 557 /** 558 * Bluetooth pairing initiator, Background 559 * 560 * @hide 561 */ 562 @SystemApi public static final int EXTRA_PAIRING_INITIATOR_BACKGROUND = 2; 563 564 /** Bluetooth device type, Unknown */ 565 public static final int DEVICE_TYPE_UNKNOWN = 0; 566 567 /** Bluetooth device type, Classic - BR/EDR devices */ 568 public static final int DEVICE_TYPE_CLASSIC = 1; 569 570 /** Bluetooth device type, Low Energy - LE-only */ 571 public static final int DEVICE_TYPE_LE = 2; 572 573 /** Bluetooth device type, Dual Mode - BR/EDR/LE */ 574 public static final int DEVICE_TYPE_DUAL = 3; 575 576 /** @hide */ 577 @RequiresBluetoothConnectPermission 578 @RequiresPermission(BLUETOOTH_CONNECT) 579 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 580 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 581 public static final String ACTION_SDP_RECORD = "android.bluetooth.device.action.SDP_RECORD"; 582 583 /** @hide */ 584 @IntDef( 585 prefix = "METADATA_", 586 value = { 587 METADATA_MANUFACTURER_NAME, 588 METADATA_MODEL_NAME, 589 METADATA_MODEL_YEAR, 590 METADATA_SOFTWARE_VERSION, 591 METADATA_HARDWARE_VERSION, 592 METADATA_COMPANION_APP, 593 METADATA_MAIN_ICON, 594 METADATA_IS_UNTETHERED_HEADSET, 595 METADATA_UNTETHERED_LEFT_ICON, 596 METADATA_UNTETHERED_RIGHT_ICON, 597 METADATA_UNTETHERED_CASE_ICON, 598 METADATA_UNTETHERED_LEFT_BATTERY, 599 METADATA_UNTETHERED_RIGHT_BATTERY, 600 METADATA_UNTETHERED_CASE_BATTERY, 601 METADATA_UNTETHERED_LEFT_CHARGING, 602 METADATA_UNTETHERED_RIGHT_CHARGING, 603 METADATA_UNTETHERED_CASE_CHARGING, 604 METADATA_ENHANCED_SETTINGS_UI_URI, 605 METADATA_DEVICE_TYPE, 606 METADATA_MAIN_BATTERY, 607 METADATA_MAIN_CHARGING, 608 METADATA_MAIN_LOW_BATTERY_THRESHOLD, 609 METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD, 610 METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD, 611 METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD, 612 METADATA_SPATIAL_AUDIO, 613 METADATA_FAST_PAIR_CUSTOMIZED_FIELDS, 614 METADATA_LE_AUDIO, 615 METADATA_GMCS_CCCD, 616 METADATA_GTBS_CCCD, 617 METADATA_EXCLUSIVE_MANAGER, 618 METADATA_HEAD_UNIT_MANUFACTURER_NAME, 619 METADATA_HEAD_UNIT_MODEL_NAME, 620 METADATA_HEAD_UNIT_BUILD, 621 METADATA_HEAD_UNIT_SOFTWARE_VERSION 622 }) 623 @Retention(RetentionPolicy.SOURCE) 624 public @interface MetadataKey {} 625 626 /** 627 * Maximum length of a metadata entry, this is to avoid exploding Bluetooth disk usage 628 * 629 * @hide 630 */ 631 @SystemApi public static final int METADATA_MAX_LENGTH = 2048; 632 633 /** 634 * Manufacturer name of this Bluetooth device Data type should be {@link String} as {@link Byte} 635 * array. 636 * 637 * @hide 638 */ 639 @SystemApi public static final int METADATA_MANUFACTURER_NAME = 0; 640 641 /** 642 * Model name of this Bluetooth device Data type should be {@link String} as {@link Byte} array. 643 * 644 * @hide 645 */ 646 @SystemApi public static final int METADATA_MODEL_NAME = 1; 647 648 /** 649 * Model year of the Bluetooth device. Data type should be {@link String} as {@link Byte} array. 650 * 651 * @hide 652 */ 653 @FlaggedApi(Flags.FLAG_SUPPORT_REMOTE_DEVICE_METADATA) 654 @SystemApi 655 public static final int METADATA_MODEL_YEAR = 30; 656 657 /** 658 * Software version of this Bluetooth device Data type should be {@link String} as {@link Byte} 659 * array. 660 * 661 * @hide 662 */ 663 @SystemApi public static final int METADATA_SOFTWARE_VERSION = 2; 664 665 /** 666 * Hardware version of this Bluetooth device Data type should be {@link String} as {@link Byte} 667 * array. 668 * 669 * @hide 670 */ 671 @SystemApi public static final int METADATA_HARDWARE_VERSION = 3; 672 673 /** 674 * Package name of the companion app, if any Data type should be {@link String} as {@link Byte} 675 * array. 676 * 677 * @hide 678 */ 679 @SystemApi public static final int METADATA_COMPANION_APP = 4; 680 681 /** 682 * URI to the main icon shown on the settings UI Data type should be {@link Byte} array. 683 * 684 * @hide 685 */ 686 @SystemApi public static final int METADATA_MAIN_ICON = 5; 687 688 /** 689 * Whether this device is an untethered headset with left, right and case Data type should be 690 * {@link String} as {@link Byte} array. 691 * 692 * @hide 693 */ 694 @SystemApi public static final int METADATA_IS_UNTETHERED_HEADSET = 6; 695 696 /** 697 * URI to icon of the left headset Data type should be {@link Byte} array. 698 * 699 * @hide 700 */ 701 @SystemApi public static final int METADATA_UNTETHERED_LEFT_ICON = 7; 702 703 /** 704 * URI to icon of the right headset Data type should be {@link Byte} array. 705 * 706 * @hide 707 */ 708 @SystemApi public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; 709 710 /** 711 * URI to icon of the headset charging case Data type should be {@link Byte} array. 712 * 713 * @hide 714 */ 715 @SystemApi public static final int METADATA_UNTETHERED_CASE_ICON = 9; 716 717 /** 718 * Battery level of left headset Data type should be {@link String} 0-100 as {@link Byte} array, 719 * otherwise as invalid. 720 * 721 * @hide 722 */ 723 @SystemApi public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; 724 725 /** 726 * Battery level of right headset Data type should be {@link String} 0-100 as {@link Byte} 727 * array, otherwise as invalid. 728 * 729 * @hide 730 */ 731 @SystemApi public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; 732 733 /** 734 * Battery level of the headset charging case Data type should be {@link String} 0-100 as {@link 735 * Byte} array, otherwise as invalid. 736 * 737 * @hide 738 */ 739 @SystemApi public static final int METADATA_UNTETHERED_CASE_BATTERY = 12; 740 741 /** 742 * Whether the left headset is charging Data type should be {@link String} as {@link Byte} 743 * array. 744 * 745 * @hide 746 */ 747 @SystemApi public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; 748 749 /** 750 * Whether the right headset is charging Data type should be {@link String} as {@link Byte} 751 * array. 752 * 753 * @hide 754 */ 755 @SystemApi public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; 756 757 /** 758 * Whether the headset charging case is charging Data type should be {@link String} as {@link 759 * Byte} array. 760 * 761 * @hide 762 */ 763 @SystemApi public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; 764 765 /** 766 * URI to the enhanced settings UI slice Data type should be {@link String} as {@link Byte} 767 * array, null means the UI does not exist. 768 * 769 * @hide 770 */ 771 @SystemApi public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; 772 773 /** @hide */ 774 public static final String COMPANION_TYPE_PRIMARY = "COMPANION_PRIMARY"; 775 776 /** @hide */ 777 public static final String COMPANION_TYPE_SECONDARY = "COMPANION_SECONDARY"; 778 779 /** @hide */ 780 public static final String COMPANION_TYPE_NONE = "COMPANION_NONE"; 781 782 /** 783 * Type of the Bluetooth device, must be within the list of BluetoothDevice.DEVICE_TYPE_* Data 784 * type should be {@link String} as {@link Byte} array. 785 * 786 * @hide 787 */ 788 @SystemApi public static final int METADATA_DEVICE_TYPE = 17; 789 790 /** 791 * Battery level of the Bluetooth device, use when the Bluetooth device does not support HFP 792 * battery indicator. Data type should be {@link String} as {@link Byte} array. 793 * 794 * @hide 795 */ 796 @SystemApi public static final int METADATA_MAIN_BATTERY = 18; 797 798 /** 799 * Whether the device is charging. Data type should be {@link String} as {@link Byte} array. 800 * 801 * @hide 802 */ 803 @SystemApi public static final int METADATA_MAIN_CHARGING = 19; 804 805 /** 806 * The battery threshold of the Bluetooth device to show low battery icon. Data type should be 807 * {@link String} as {@link Byte} array. 808 * 809 * @hide 810 */ 811 @SystemApi public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20; 812 813 /** 814 * The battery threshold of the left headset to show low battery icon. Data type should be 815 * {@link String} as {@link Byte} array. 816 * 817 * @hide 818 */ 819 @SystemApi public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21; 820 821 /** 822 * The battery threshold of the right headset to show low battery icon. Data type should be 823 * {@link String} as {@link Byte} array. 824 * 825 * @hide 826 */ 827 @SystemApi public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22; 828 829 /** 830 * The battery threshold of the case to show low battery icon. Data type should be {@link 831 * String} as {@link Byte} array. 832 * 833 * @hide 834 */ 835 @SystemApi public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23; 836 837 /** 838 * The metadata of the audio spatial data. Data type should be {@link Byte} array. 839 * 840 * @hide 841 */ 842 public static final int METADATA_SPATIAL_AUDIO = 24; 843 844 /** 845 * The metadata of the Fast Pair for any customized feature. Data type should be {@link Byte} 846 * array. 847 * 848 * @hide 849 */ 850 public static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25; 851 852 /** 853 * The metadata of the Fast Pair for LE Audio capable devices. Data type should be {@link Byte} 854 * array. 855 * 856 * @hide 857 */ 858 @SystemApi public static final int METADATA_LE_AUDIO = 26; 859 860 /** 861 * The UUIDs (16-bit) of registered to CCC characteristics from Media Control services. Data 862 * type should be {@link Byte} array. 863 * 864 * @hide 865 */ 866 public static final int METADATA_GMCS_CCCD = 27; 867 868 /** 869 * The UUIDs (16-bit) of registered to CCC characteristics from Telephony Bearer service. Data 870 * type should be {@link Byte} array. 871 * 872 * @hide 873 */ 874 public static final int METADATA_GTBS_CCCD = 28; 875 876 /** 877 * Specify the exclusive manager app for this BluetoothDevice. 878 * 879 * <p>If there's a manager app specified for this BluetoothDevice, and the app is currently 880 * installed and enabled on the device, that manager app shall be responsible for providing the 881 * BluetoothDevice management functionality (e.g. connect, disconnect, forget, etc.). Android 882 * Settings app or Quick Settings System UI shall not provide any management functionality for 883 * such BluetoothDevice. 884 * 885 * <p>Data type should be a {@link String} representation of the {@link ComponentName} (e.g. 886 * "com.android.settings/.SettingsActivity") or the package name (e.g. "com.android.settings") 887 * of the exclusive manager, provided as a {@link Byte} array. 888 * 889 * @hide 890 */ 891 @SystemApi public static final int METADATA_EXCLUSIVE_MANAGER = 29; 892 893 private static final int METADATA_MAX_KEY = METADATA_EXCLUSIVE_MANAGER; 894 895 /** 896 * Head unit manufacturer name of the Bluetooth device. Data type should be {@link String} as 897 * {@link Byte} array. Should only be set/available for a car device. 898 * 899 * @hide 900 */ 901 @FlaggedApi(Flags.FLAG_SUPPORT_REMOTE_DEVICE_METADATA) 902 @SystemApi 903 public static final int METADATA_HEAD_UNIT_MANUFACTURER_NAME = 31; 904 905 /** 906 * Head unit model name of the Bluetooth device. Data type should be {@link String} as {@link 907 * Byte} array. Should only be set/available for a car device. 908 * 909 * @hide 910 */ 911 @FlaggedApi(Flags.FLAG_SUPPORT_REMOTE_DEVICE_METADATA) 912 @SystemApi 913 public static final int METADATA_HEAD_UNIT_MODEL_NAME = 32; 914 915 /** 916 * Build of the overall head unit device. Not specific to hardware or software. Example can be 917 * 'manufacturer_country'. Data type should be {@link String} as {@link Byte} array. Should only 918 * be set/available for a car device. 919 * 920 * @hide 921 */ 922 @FlaggedApi(Flags.FLAG_SUPPORT_REMOTE_DEVICE_METADATA) 923 @SystemApi 924 public static final int METADATA_HEAD_UNIT_BUILD = 33; 925 926 /** 927 * Head unit software version of the Bluetooth device. Data type should be {@link String} as 928 * {@link Byte} array. Should only be set/available for a car device. 929 * 930 * @hide 931 */ 932 @FlaggedApi(Flags.FLAG_SUPPORT_REMOTE_DEVICE_METADATA) 933 @SystemApi 934 public static final int METADATA_HEAD_UNIT_SOFTWARE_VERSION = 34; 935 936 /** 937 * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a 938 * standard Bluetooth accessory or not listed in METADATA_DEVICE_TYPE_*. 939 * 940 * @hide 941 */ 942 @SystemApi public static final String DEVICE_TYPE_DEFAULT = "Default"; 943 944 /** 945 * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a watch. 946 * 947 * @hide 948 */ 949 @SystemApi public static final String DEVICE_TYPE_WATCH = "Watch"; 950 951 /** 952 * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is an 953 * untethered headset. 954 * 955 * @hide 956 */ 957 @SystemApi public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset"; 958 959 /** 960 * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a 961 * stylus. 962 * 963 * @hide 964 */ 965 @SystemApi public static final String DEVICE_TYPE_STYLUS = "Stylus"; 966 967 /** 968 * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a 969 * speaker. 970 * 971 * @hide 972 */ 973 @FlaggedApi(Flags.FLAG_SUPPORT_METADATA_DEVICE_TYPES_APIS) 974 @SystemApi 975 public static final String DEVICE_TYPE_SPEAKER = "Speaker"; 976 977 /** 978 * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a 979 * tethered headset. 980 * 981 * @hide 982 */ 983 @FlaggedApi(Flags.FLAG_SUPPORT_METADATA_DEVICE_TYPES_APIS) 984 @SystemApi 985 public static final String DEVICE_TYPE_HEADSET = "Headset"; 986 987 /** 988 * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a 989 * Carkit. 990 * 991 * @hide 992 */ 993 @FlaggedApi(Flags.FLAG_SUPPORT_METADATA_DEVICE_TYPES_APIS) 994 @SystemApi 995 public static final String DEVICE_TYPE_CARKIT = "Carkit"; 996 997 /** 998 * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a 999 * HearingAid. 1000 * 1001 * @hide 1002 */ 1003 @FlaggedApi(Flags.FLAG_SUPPORT_METADATA_DEVICE_TYPES_APIS) 1004 @SystemApi 1005 public static final String DEVICE_TYPE_HEARING_AID = "HearingAid"; 1006 1007 /** 1008 * Broadcast Action: This intent is used to broadcast the {@link UUID} wrapped as a {@link 1009 * android.os.ParcelUuid} of the remote device after it has been fetched. This intent is sent 1010 * only when the UUIDs of the remote device are requested to be fetched using Service Discovery 1011 * Protocol 1012 * 1013 * <p>Always contains the extra field {@link #EXTRA_DEVICE} 1014 * 1015 * <p>Always contains the extra field {@link #EXTRA_UUID} 1016 */ 1017 @RequiresLegacyBluetoothAdminPermission 1018 @RequiresBluetoothConnectPermission 1019 @RequiresPermission(BLUETOOTH_CONNECT) 1020 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1021 public static final String ACTION_UUID = "android.bluetooth.device.action.UUID"; 1022 1023 /** @hide */ 1024 @RequiresBluetoothConnectPermission 1025 @RequiresPermission(BLUETOOTH_CONNECT) 1026 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1027 public static final String ACTION_MAS_INSTANCE = "android.bluetooth.device.action.MAS_INSTANCE"; 1028 1029 /** 1030 * Broadcast Action: Indicates a failure to retrieve the name of a remote device. 1031 * 1032 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 1033 * 1034 * @hide 1035 */ 1036 // TODO: is this actually useful? 1037 @RequiresLegacyBluetoothPermission 1038 @RequiresBluetoothConnectPermission 1039 @RequiresPermission(BLUETOOTH_CONNECT) 1040 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1041 public static final String ACTION_NAME_FAILED = "android.bluetooth.device.action.NAME_FAILED"; 1042 1043 /** Broadcast Action: This intent is used to broadcast PAIRING REQUEST */ 1044 @RequiresLegacyBluetoothAdminPermission 1045 @RequiresBluetoothConnectPermission 1046 @RequiresPermission(BLUETOOTH_CONNECT) 1047 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1048 public static final String ACTION_PAIRING_REQUEST = 1049 "android.bluetooth.device.action.PAIRING_REQUEST"; 1050 1051 /** 1052 * Starting from {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the return value of 1053 * {@link BluetoothDevice#toString()} has changed to improve privacy. 1054 */ 1055 @ChangeId 1056 @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 1057 private static final long CHANGE_TO_STRING_REDACTED = 265103382L; 1058 1059 /** 1060 * Broadcast Action: This intent is used to broadcast PAIRING CANCEL 1061 * 1062 * @hide 1063 */ 1064 @SystemApi 1065 @RequiresBluetoothConnectPermission 1066 @RequiresPermission(BLUETOOTH_CONNECT) 1067 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1068 @SuppressLint("ActionValue") 1069 public static final String ACTION_PAIRING_CANCEL = 1070 "android.bluetooth.device.action.PAIRING_CANCEL"; 1071 1072 /** 1073 * Broadcast Action: This intent is used to broadcast CONNECTION ACCESS REQUEST 1074 * 1075 * <p>This action will trigger a prompt for the user to accept or deny giving the permission for 1076 * this device. Permissions can be specified with {@link #EXTRA_ACCESS_REQUEST_TYPE}. 1077 * 1078 * <p>The reply will be an {@link #ACTION_CONNECTION_ACCESS_REPLY} sent to the specified {@link 1079 * #EXTRA_PACKAGE_NAME} and {@link #EXTRA_CLASS_NAME}. 1080 * 1081 * <p>This action can be cancelled with {@link #ACTION_CONNECTION_ACCESS_CANCEL}. 1082 * 1083 * @hide 1084 */ 1085 @SystemApi 1086 @RequiresBluetoothConnectPermission 1087 @RequiresPermission(BLUETOOTH_CONNECT) 1088 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1089 @SuppressLint("ActionValue") 1090 public static final String ACTION_CONNECTION_ACCESS_REQUEST = 1091 "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST"; 1092 1093 /** 1094 * Broadcast Action: This intent is used to broadcast CONNECTION ACCESS REPLY 1095 * 1096 * <p>This action is the reply from {@link #ACTION_CONNECTION_ACCESS_REQUEST} that is sent to 1097 * the specified {@link #EXTRA_PACKAGE_NAME} and {@link #EXTRA_CLASS_NAME}. 1098 * 1099 * <p>See the extra fields {@link #EXTRA_CONNECTION_ACCESS_RESULT} and {@link 1100 * #EXTRA_ALWAYS_ALLOWED} for possible results. 1101 * 1102 * @hide 1103 */ 1104 @SystemApi 1105 @RequiresBluetoothConnectPermission 1106 @RequiresPermission(BLUETOOTH_CONNECT) 1107 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1108 @SuppressLint("ActionValue") 1109 public static final String ACTION_CONNECTION_ACCESS_REPLY = 1110 "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY"; 1111 1112 /** 1113 * Broadcast Action: This intent is used to broadcast CONNECTION ACCESS CANCEL 1114 * 1115 * @hide 1116 */ 1117 @SystemApi 1118 @RequiresBluetoothConnectPermission 1119 @RequiresPermission(BLUETOOTH_CONNECT) 1120 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1121 @SuppressLint("ActionValue") 1122 public static final String ACTION_CONNECTION_ACCESS_CANCEL = 1123 "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL"; 1124 1125 /** 1126 * Intent to broadcast silence mode changed. Always contains the extra field {@link 1127 * #EXTRA_DEVICE} 1128 * 1129 * @hide 1130 */ 1131 @RequiresBluetoothConnectPermission 1132 @RequiresPermission(BLUETOOTH_CONNECT) 1133 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 1134 @SystemApi 1135 public static final String ACTION_SILENCE_MODE_CHANGED = 1136 "android.bluetooth.device.action.SILENCE_MODE_CHANGED"; 1137 1138 /** 1139 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST}. 1140 * 1141 * <p>Possible values are {@link #REQUEST_TYPE_PROFILE_CONNECTION}, {@link 1142 * #REQUEST_TYPE_PHONEBOOK_ACCESS}, {@link #REQUEST_TYPE_MESSAGE_ACCESS} and {@link 1143 * #REQUEST_TYPE_SIM_ACCESS} 1144 * 1145 * @hide 1146 */ 1147 @SystemApi 1148 @SuppressLint("ActionValue") 1149 public static final String EXTRA_ACCESS_REQUEST_TYPE = 1150 "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE"; 1151 1152 /** @hide */ 1153 @SystemApi public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1; 1154 1155 /** @hide */ 1156 @SystemApi public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2; 1157 1158 /** @hide */ 1159 @SystemApi public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3; 1160 1161 /** @hide */ 1162 @SystemApi public static final int REQUEST_TYPE_SIM_ACCESS = 4; 1163 1164 /** 1165 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, Contains package 1166 * name to return reply intent to. 1167 * 1168 * @hide 1169 */ 1170 public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME"; 1171 1172 /** 1173 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, Contains class 1174 * name to return reply intent to. 1175 * 1176 * @hide 1177 */ 1178 public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME"; 1179 1180 /** 1181 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent. 1182 * 1183 * <p>Possible values are {@link #CONNECTION_ACCESS_YES} and {@link #CONNECTION_ACCESS_NO}. 1184 * 1185 * @hide 1186 */ 1187 @SystemApi 1188 @SuppressLint("ActionValue") 1189 public static final String EXTRA_CONNECTION_ACCESS_RESULT = 1190 "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT"; 1191 1192 /** @hide */ 1193 @SystemApi public static final int CONNECTION_ACCESS_YES = 1; 1194 1195 /** @hide */ 1196 @SystemApi public static final int CONNECTION_ACCESS_NO = 2; 1197 1198 /** 1199 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents, Contains boolean 1200 * to indicate if the allowed response is once-for-all so that next request will be granted 1201 * without asking user again. 1202 * 1203 * @hide 1204 */ 1205 @SystemApi 1206 @SuppressLint("ActionValue") 1207 public static final String EXTRA_ALWAYS_ALLOWED = 1208 "android.bluetooth.device.extra.ALWAYS_ALLOWED"; 1209 1210 /** 1211 * A bond attempt succeeded 1212 * 1213 * @hide 1214 */ 1215 public static final int BOND_SUCCESS = 0; 1216 1217 /** 1218 * A bond attempt failed because pins did not match, or remote device did not respond to pin 1219 * request in time 1220 * 1221 * @hide 1222 */ 1223 @SystemApi public static final int UNBOND_REASON_AUTH_FAILED = 1; 1224 1225 /** 1226 * A bond attempt failed because the other side explicitly rejected bonding 1227 * 1228 * @hide 1229 */ 1230 @SystemApi public static final int UNBOND_REASON_AUTH_REJECTED = 2; 1231 1232 /** 1233 * A bond attempt failed because we canceled the bonding process 1234 * 1235 * @hide 1236 */ 1237 @SystemApi public static final int UNBOND_REASON_AUTH_CANCELED = 3; 1238 1239 /** 1240 * A bond attempt failed because we could not contact the remote device 1241 * 1242 * @hide 1243 */ 1244 @SystemApi public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4; 1245 1246 /** 1247 * A bond attempt failed because a discovery is in progress 1248 * 1249 * @hide 1250 */ 1251 @SystemApi public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5; 1252 1253 /** 1254 * A bond attempt failed because of authentication timeout 1255 * 1256 * @hide 1257 */ 1258 @SystemApi public static final int UNBOND_REASON_AUTH_TIMEOUT = 6; 1259 1260 /** 1261 * A bond attempt failed because of repeated attempts 1262 * 1263 * @hide 1264 */ 1265 @SystemApi public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7; 1266 1267 /** 1268 * A bond attempt failed because we received an Authentication Cancel by remote end 1269 * 1270 * @hide 1271 */ 1272 @SystemApi public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8; 1273 1274 /** 1275 * An existing bond was explicitly revoked 1276 * 1277 * @hide 1278 */ 1279 @SystemApi public static final int UNBOND_REASON_REMOVED = 9; 1280 1281 /** The user will be prompted to enter a pin or an app will enter a pin for user. */ 1282 public static final int PAIRING_VARIANT_PIN = 0; 1283 1284 /** 1285 * The user will be prompted to enter a passkey 1286 * 1287 * @hide 1288 */ 1289 @SystemApi public static final int PAIRING_VARIANT_PASSKEY = 1; 1290 1291 /** 1292 * The user will be prompted to confirm the passkey displayed on the screen or an app will 1293 * confirm the passkey for the user. 1294 */ 1295 public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2; 1296 1297 /** 1298 * The user will be prompted to accept or deny the incoming pairing request 1299 * 1300 * @hide 1301 */ 1302 @SystemApi public static final int PAIRING_VARIANT_CONSENT = 3; 1303 1304 /** 1305 * The user will be prompted to enter the passkey displayed on remote device This is used for 1306 * Bluetooth 2.1 pairing. 1307 * 1308 * @hide 1309 */ 1310 @SystemApi public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4; 1311 1312 /** 1313 * The user will be prompted to enter the PIN displayed on remote device. This is used for 1314 * Bluetooth 2.0 pairing. 1315 * 1316 * @hide 1317 */ 1318 @SystemApi public static final int PAIRING_VARIANT_DISPLAY_PIN = 5; 1319 1320 /** 1321 * The user will be prompted to accept or deny the OOB pairing request. This is used for 1322 * Bluetooth 2.1 secure simple pairing. 1323 * 1324 * @hide 1325 */ 1326 @SystemApi public static final int PAIRING_VARIANT_OOB_CONSENT = 6; 1327 1328 /** 1329 * The user will be prompted to enter a 16 digit pin or an app will enter a 16 digit pin for 1330 * user. 1331 * 1332 * @hide 1333 */ 1334 @SystemApi public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7; 1335 1336 /** 1337 * Used as an extra field in {@link #ACTION_UUID} intents, Contains the {@link 1338 * android.os.ParcelUuid}s of the remote device which is a parcelable version of {@link UUID}. A 1339 * {@code null} EXTRA_UUID indicates a timeout. 1340 */ 1341 public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID"; 1342 1343 /** @hide */ 1344 public static final String EXTRA_SDP_RECORD = "android.bluetooth.device.extra.SDP_RECORD"; 1345 1346 /** @hide */ 1347 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1348 public static final String EXTRA_SDP_SEARCH_STATUS = 1349 "android.bluetooth.device.extra.SDP_SEARCH_STATUS"; 1350 1351 /** @hide */ 1352 @IntDef( 1353 prefix = "ACCESS_", 1354 value = {ACCESS_UNKNOWN, ACCESS_ALLOWED, ACCESS_REJECTED}) 1355 @Retention(RetentionPolicy.SOURCE) 1356 public @interface AccessPermission {} 1357 1358 /** 1359 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, {@link 1360 * #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 1361 * 1362 * @hide 1363 */ 1364 @SystemApi public static final int ACCESS_UNKNOWN = 0; 1365 1366 /** 1367 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, {@link 1368 * #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 1369 * 1370 * @hide 1371 */ 1372 @SystemApi public static final int ACCESS_ALLOWED = 1; 1373 1374 /** 1375 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, {@link 1376 * #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 1377 * 1378 * @hide 1379 */ 1380 @SystemApi public static final int ACCESS_REJECTED = 2; 1381 1382 /** @hide */ 1383 @Retention(RetentionPolicy.SOURCE) 1384 @IntDef( 1385 prefix = {"TRANSPORT_"}, 1386 value = { 1387 TRANSPORT_AUTO, 1388 TRANSPORT_BREDR, 1389 TRANSPORT_LE, 1390 }) 1391 public @interface Transport {} 1392 1393 /** No preference of physical transport for GATT connections to remote dual-mode devices */ 1394 public static final int TRANSPORT_AUTO = 0; 1395 1396 /** Constant representing the BR/EDR transport. */ 1397 public static final int TRANSPORT_BREDR = 1; 1398 1399 /** Constant representing the Bluetooth Low Energy (BLE) Transport. */ 1400 public static final int TRANSPORT_LE = 2; 1401 1402 /** 1403 * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or 1404 * connection. 1405 */ 1406 public static final int PHY_LE_1M = 1; 1407 1408 /** 1409 * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or 1410 * connection. 1411 */ 1412 public static final int PHY_LE_2M = 2; 1413 1414 /** 1415 * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning 1416 * or connection. 1417 */ 1418 public static final int PHY_LE_CODED = 3; 1419 1420 /** 1421 * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available 1422 * options in a bitmask. 1423 */ 1424 public static final int PHY_LE_1M_MASK = 1; 1425 1426 /** 1427 * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available 1428 * options in a bitmask. 1429 */ 1430 public static final int PHY_LE_2M_MASK = 2; 1431 1432 /** 1433 * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many 1434 * available options in a bitmask. 1435 */ 1436 public static final int PHY_LE_CODED_MASK = 4; 1437 1438 /** No preferred coding when transmitting on the LE Coded PHY. */ 1439 public static final int PHY_OPTION_NO_PREFERRED = 0; 1440 1441 /** Prefer the S=2 coding to be used when transmitting on the LE Coded PHY. */ 1442 public static final int PHY_OPTION_S2 = 1; 1443 1444 /** Prefer the S=8 coding to be used when transmitting on the LE Coded PHY. */ 1445 public static final int PHY_OPTION_S8 = 2; 1446 1447 /** @hide */ 1448 public static final String EXTRA_MAS_INSTANCE = "android.bluetooth.device.extra.MAS_INSTANCE"; 1449 1450 /** 1451 * Used as an int extra field in {@link #ACTION_ACL_CONNECTED}, {@link #ACTION_ACL_DISCONNECTED} 1452 * and {@link #ACTION_ENCRYPTION_CHANGE} intents to indicate which transport is connected. 1453 * Possible values are: {@link #TRANSPORT_BREDR} and {@link #TRANSPORT_LE}. 1454 */ 1455 @SuppressLint("ActionValue") 1456 public static final String EXTRA_TRANSPORT = "android.bluetooth.device.extra.TRANSPORT"; 1457 1458 /** @hide */ 1459 @Retention(RetentionPolicy.SOURCE) 1460 @IntDef( 1461 prefix = {"ADDRESS_TYPE_"}, 1462 value = { 1463 ADDRESS_TYPE_PUBLIC, 1464 ADDRESS_TYPE_RANDOM, 1465 ADDRESS_TYPE_ANONYMOUS, 1466 ADDRESS_TYPE_UNKNOWN, 1467 }) 1468 public @interface AddressType {} 1469 1470 /** Hardware MAC Address of the device */ 1471 public static final int ADDRESS_TYPE_PUBLIC = 0; 1472 1473 /** Address is either resolvable, non-resolvable or static. */ 1474 public static final int ADDRESS_TYPE_RANDOM = 1; 1475 1476 /** Address type is unknown or unavailable */ 1477 public static final int ADDRESS_TYPE_UNKNOWN = 0xFFFF; 1478 1479 /** Address type used to indicate an anonymous advertisement. */ 1480 public static final int ADDRESS_TYPE_ANONYMOUS = 0xFF; 1481 1482 /** 1483 * Indicates default active audio device policy is applied to this device 1484 * 1485 * @hide 1486 */ 1487 @SystemApi public static final int ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT = 0; 1488 1489 /** 1490 * Indicates all profiles active audio device policy is applied to this device 1491 * 1492 * <p>all profiles are active upon device connection 1493 * 1494 * @hide 1495 */ 1496 @SystemApi 1497 public static final int ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_ACTIVE_UPON_CONNECTION = 1; 1498 1499 /** 1500 * Indicates all profiles inactive audio device policy is applied to this device 1501 * 1502 * <p>all profiles are inactive upon device connection 1503 * 1504 * @hide 1505 */ 1506 @SystemApi 1507 public static final int ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_INACTIVE_UPON_CONNECTION = 2; 1508 1509 private static final String NULL_MAC_ADDRESS = "00:00:00:00:00:00"; 1510 1511 private final String mAddress; 1512 @AddressType private final int mAddressType; 1513 1514 private AttributionSource mAttributionSource; 1515 getService()1516 static IBluetooth getService() { 1517 return BluetoothAdapter.getDefaultAdapter().getBluetoothService(); 1518 } 1519 1520 /** 1521 * Create a new BluetoothDevice. Bluetooth MAC address must be upper case, such as 1522 * "00:11:22:33:AA:BB", and is validated in this constructor. 1523 * 1524 * @param address valid Bluetooth MAC address 1525 * @param addressType valid address type 1526 * @throws RuntimeException Bluetooth is not available on this platform 1527 * @throws IllegalArgumentException address or addressType is invalid 1528 * @hide 1529 */ BluetoothDevice(String address, int addressType)1530 /*package*/ BluetoothDevice(String address, int addressType) { 1531 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1532 throw new IllegalArgumentException(address + " is not a valid Bluetooth address"); 1533 } 1534 1535 if (addressType != ADDRESS_TYPE_PUBLIC 1536 && addressType != ADDRESS_TYPE_RANDOM 1537 && addressType != ADDRESS_TYPE_ANONYMOUS) { 1538 throw new IllegalArgumentException(addressType + " is not a Bluetooth address type"); 1539 } 1540 1541 if (addressType == ADDRESS_TYPE_ANONYMOUS && !NULL_MAC_ADDRESS.equals(address)) { 1542 throw new IllegalArgumentException( 1543 "Invalid address for anonymous address type: " 1544 + BluetoothUtils.toAnonymizedAddress(address)); 1545 } 1546 1547 mAddress = address; 1548 mAddressType = addressType; 1549 mAttributionSource = AttributionSource.myAttributionSource(); 1550 } 1551 1552 /** 1553 * Create a new BluetoothDevice. Bluetooth MAC address must be upper case, such as 1554 * "00:11:22:33:AA:BB", and is validated in this constructor. 1555 * 1556 * @param address valid Bluetooth MAC address 1557 * @throws RuntimeException Bluetooth is not available on this platform 1558 * @throws IllegalArgumentException address is invalid 1559 * @hide 1560 */ 1561 @UnsupportedAppUsage BluetoothDevice(String address)1562 /*package*/ BluetoothDevice(String address) { 1563 this(address, ADDRESS_TYPE_PUBLIC); 1564 } 1565 1566 /** 1567 * Create a new BluetoothDevice. 1568 * 1569 * @param in valid parcel 1570 * @throws RuntimeException Bluetooth is not available on this platform 1571 * @throws IllegalArgumentException address is invalid 1572 * @hide 1573 */ 1574 @UnsupportedAppUsage BluetoothDevice(Parcel in)1575 /*package*/ BluetoothDevice(Parcel in) { 1576 this(in.readString(), in.readInt()); 1577 } 1578 1579 /** @hide */ setAttributionSource(@onNull AttributionSource attributionSource)1580 public void setAttributionSource(@NonNull AttributionSource attributionSource) { 1581 mAttributionSource = attributionSource; 1582 } 1583 1584 /** 1585 * Method should never be used anywhere. Only exception is from {@link Intent} Used to set the 1586 * device current attribution source 1587 * 1588 * @param attributionSource The associated {@link AttributionSource} for this device in this 1589 * process 1590 * @hide 1591 */ 1592 @SystemApi prepareToEnterProcess(@onNull AttributionSource attributionSource)1593 public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) { 1594 setAttributionSource(attributionSource); 1595 } 1596 1597 @Override equals(@ullable Object o)1598 public boolean equals(@Nullable Object o) { 1599 if (o instanceof BluetoothDevice) { 1600 return mAddress.equals(((BluetoothDevice) o).getAddress()); 1601 } 1602 return false; 1603 } 1604 1605 @Override hashCode()1606 public int hashCode() { 1607 return mAddress.hashCode(); 1608 } 1609 1610 /** 1611 * Returns a string representation of this BluetoothDevice. 1612 * 1613 * <p>For apps targeting {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} (API level 34) 1614 * or higher, this returns the MAC address of the device redacted by replacing the hexadecimal 1615 * digits of leftmost 4 bytes (in big endian order) with "XX", e.g., "XX:XX:XX:XX:12:34". For 1616 * apps targeting earlier versions, the MAC address is returned without redaction. 1617 * 1618 * <p>Warning: The return value of {@link #toString()} may change in the future. It is intended 1619 * to be used in logging statements. Thus apps should never rely on the return value of {@link 1620 * #toString()} in their logic. Always use other appropriate APIs instead (e.g., use {@link 1621 * #getAddress()} to get the MAC address). 1622 * 1623 * @return string representation of this BluetoothDevice 1624 */ 1625 @Override toString()1626 public String toString() { 1627 if (!CompatChanges.isChangeEnabled(CHANGE_TO_STRING_REDACTED)) { 1628 return mAddress; 1629 } 1630 return getAnonymizedAddress(); 1631 } 1632 1633 @Override describeContents()1634 public int describeContents() { 1635 return 0; 1636 } 1637 1638 public static final @NonNull Creator<BluetoothDevice> CREATOR = 1639 new Creator<>() { 1640 public BluetoothDevice createFromParcel(Parcel in) { 1641 return new BluetoothDevice(in); 1642 } 1643 1644 public BluetoothDevice[] newArray(int size) { 1645 return new BluetoothDevice[size]; 1646 } 1647 }; 1648 1649 @Override writeToParcel(Parcel out, int flags)1650 public void writeToParcel(Parcel out, int flags) { 1651 BluetoothUtils.writeStringToParcel(out, mAddress); 1652 out.writeInt(mAddressType); 1653 } 1654 1655 /** 1656 * Returns the hardware address of this BluetoothDevice. 1657 * 1658 * <p>For example, "00:11:22:AA:BB:CC". 1659 * 1660 * @return Bluetooth hardware address as string 1661 */ getAddress()1662 public String getAddress() { 1663 if (DBG) Log.d(TAG, "getAddress: mAddress=" + this); 1664 return mAddress; 1665 } 1666 1667 /** 1668 * Returns the address type of this BluetoothDevice, one of {@link #ADDRESS_TYPE_PUBLIC}, {@link 1669 * #ADDRESS_TYPE_RANDOM}, {@link #ADDRESS_TYPE_ANONYMOUS}, or {@link #ADDRESS_TYPE_UNKNOWN}. 1670 * 1671 * @return Bluetooth address type 1672 */ getAddressType()1673 public @AddressType int getAddressType() { 1674 if (DBG) Log.d(TAG, "mAddressType: " + mAddressType); 1675 return mAddressType; 1676 } 1677 1678 /** 1679 * Returns the anonymized hardware address of this BluetoothDevice. The first three octets will 1680 * be suppressed for anonymization. 1681 * 1682 * <p>For example, "XX:XX:XX:AA:BB:CC". 1683 * 1684 * @return Anonymized bluetooth hardware address as string 1685 * @hide 1686 */ 1687 @SystemApi 1688 @NonNull getAnonymizedAddress()1689 public String getAnonymizedAddress() { 1690 return BluetoothUtils.toAnonymizedAddress(mAddress); 1691 } 1692 1693 /** 1694 * Returns the identity address of this BluetoothDevice. 1695 * 1696 * <p>For example, "00:11:22:AA:BB:CC". 1697 * 1698 * @return Bluetooth identity address as a string 1699 * @hide 1700 */ 1701 @SystemApi 1702 @RequiresBluetoothConnectPermission 1703 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) getIdentityAddress()1704 public @Nullable String getIdentityAddress() { 1705 if (DBG) log("getIdentityAddress()"); 1706 final IBluetooth service = getService(); 1707 if (service == null || !isBluetoothEnabled()) { 1708 Log.e(TAG, "BT not enabled. Cannot get identity address"); 1709 } else { 1710 try { 1711 return service.getIdentityAddress(mAddress); 1712 } catch (RemoteException e) { 1713 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 1714 } 1715 } 1716 return null; 1717 } 1718 1719 /** 1720 * Returns the identity address and identity address type of this BluetoothDevice. An identity 1721 * address is a public or static random Bluetooth LE device address that serves as a unique 1722 * identifier. 1723 * 1724 * @return a {@link BluetoothAddress} containing identity address and identity address type. If 1725 * Bluetooth is not enabled or identity address type is not available, it will return a 1726 * {@link BluetoothAddress} containing {@link #ADDRESS_TYPE_UNKNOWN} device for the identity 1727 * address type. 1728 */ 1729 @FlaggedApi(Flags.FLAG_IDENTITY_ADDRESS_TYPE_API) 1730 @RequiresBluetoothConnectPermission 1731 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) 1732 @NonNull getIdentityAddressWithType()1733 public BluetoothAddress getIdentityAddressWithType() { 1734 if (DBG) log("getIdentityAddressWithType()"); 1735 final IBluetooth service = getService(); 1736 if (service == null || !isBluetoothEnabled()) { 1737 Log.e(TAG, "BT not enabled. Cannot get identity address with type"); 1738 } else { 1739 try { 1740 return service.getIdentityAddressWithType(mAddress); 1741 } catch (RemoteException e) { 1742 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 1743 } 1744 } 1745 return new BluetoothAddress(null, BluetoothDevice.ADDRESS_TYPE_UNKNOWN); 1746 } 1747 1748 /** 1749 * Get the friendly Bluetooth name of the remote device. 1750 * 1751 * <p>The local adapter will automatically retrieve remote names when performing a device scan, 1752 * and will cache them. This method just returns the name for this device from the cache. 1753 * 1754 * @return the Bluetooth name, or null if there was a problem. 1755 */ 1756 @RequiresLegacyBluetoothPermission 1757 @RequiresBluetoothConnectPermission 1758 @RequiresPermission(BLUETOOTH_CONNECT) getName()1759 public String getName() { 1760 if (DBG) log("getName()"); 1761 final IBluetooth service = getService(); 1762 if (service == null || !isBluetoothEnabled()) { 1763 Log.e(TAG, "BT not enabled. Cannot get Remote Device name"); 1764 if (DBG) log(Log.getStackTraceString(new Throwable())); 1765 } else { 1766 try { 1767 String name = service.getRemoteName(this, mAttributionSource); 1768 if (name != null) { 1769 // remove whitespace characters from the name 1770 return name.replace('\t', ' ').replace('\n', ' ').replace('\r', ' '); 1771 } 1772 } catch (RemoteException e) { 1773 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 1774 } 1775 } 1776 return null; 1777 } 1778 1779 /** 1780 * Get the Bluetooth device type of the remote device. 1781 * 1782 * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} {@link 1783 * #DEVICE_TYPE_DUAL}. {@link #DEVICE_TYPE_UNKNOWN} if it's not available 1784 */ 1785 @RequiresLegacyBluetoothPermission 1786 @RequiresBluetoothConnectPermission 1787 @RequiresPermission(BLUETOOTH_CONNECT) getType()1788 public int getType() { 1789 if (DBG) log("getType()"); 1790 final IBluetooth service = getService(); 1791 if (service == null || !isBluetoothEnabled()) { 1792 Log.e(TAG, "BT not enabled. Cannot get Remote Device type"); 1793 if (DBG) log(Log.getStackTraceString(new Throwable())); 1794 } else { 1795 try { 1796 return service.getRemoteType(this, mAttributionSource); 1797 } catch (RemoteException e) { 1798 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 1799 } 1800 } 1801 return DEVICE_TYPE_UNKNOWN; 1802 } 1803 1804 /** 1805 * Get the locally modifiable name (alias) of the remote Bluetooth device. 1806 * 1807 * @return the Bluetooth alias, the friendly device name if no alias, or null if there was a 1808 * problem 1809 */ 1810 @Nullable 1811 @RequiresLegacyBluetoothPermission 1812 @RequiresBluetoothConnectPermission 1813 @RequiresPermission(BLUETOOTH_CONNECT) getAlias()1814 public String getAlias() { 1815 if (DBG) log("getAlias()"); 1816 final IBluetooth service = getService(); 1817 if (service == null || !isBluetoothEnabled()) { 1818 Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias"); 1819 if (DBG) log(Log.getStackTraceString(new Throwable())); 1820 } else { 1821 try { 1822 String alias = service.getRemoteAlias(this, mAttributionSource); 1823 if (alias == null) { 1824 return getName(); 1825 } 1826 return alias.replace('\t', ' ').replace('\n', ' ').replace('\r', ' '); 1827 } catch (RemoteException e) { 1828 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 1829 } 1830 } 1831 return null; 1832 } 1833 1834 /** @hide */ 1835 @Retention(RetentionPolicy.SOURCE) 1836 @IntDef( 1837 value = { 1838 BluetoothStatusCodes.SUCCESS, 1839 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, 1840 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED, 1841 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, 1842 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED 1843 }) 1844 public @interface SetAliasReturnValues {} 1845 1846 /** 1847 * Sets the locally modifiable name (alias) of the remote Bluetooth device. This method 1848 * overwrites the previously stored alias. The new alias is saved in local storage so that the 1849 * change is preserved over power cycles. 1850 * 1851 * <p>This method requires the calling app to have the {@link 1852 * android.Manifest.permission#BLUETOOTH_CONNECT} permission. Additionally, an app must either 1853 * have the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} or be associated with the 1854 * Companion Device manager (see {@link android.companion.CompanionDeviceManager#associate( 1855 * AssociationRequest, android.companion.CompanionDeviceManager.Callback, Handler)}) 1856 * 1857 * @param alias is the new locally modifiable name for the remote Bluetooth device which must be 1858 * the empty string. If null, we clear the alias. 1859 * @return whether the alias was successfully changed 1860 * @throws IllegalArgumentException if the alias is the empty string 1861 */ 1862 @RequiresLegacyBluetoothPermission 1863 @RequiresBluetoothConnectPermission 1864 @RequiresPermission( 1865 allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}, 1866 conditional = true) setAlias(@ullable String alias)1867 public @SetAliasReturnValues int setAlias(@Nullable String alias) { 1868 if (alias != null && alias.isEmpty()) { 1869 throw new IllegalArgumentException("alias cannot be the empty string"); 1870 } 1871 if (DBG) log("setAlias(" + alias + ")"); 1872 final IBluetooth service = getService(); 1873 if (service == null || !isBluetoothEnabled()) { 1874 Log.e(TAG, "BT not enabled. Cannot set Remote Device name"); 1875 if (DBG) log(Log.getStackTraceString(new Throwable())); 1876 } else { 1877 try { 1878 return service.setRemoteAlias(this, alias, mAttributionSource); 1879 } catch (RemoteException e) { 1880 Log.e(TAG, "", e); 1881 } 1882 } 1883 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; 1884 } 1885 1886 /** 1887 * Get the most recent identified battery level of this Bluetooth device 1888 * 1889 * @return Battery level in percents from 0 to 100, {@link #BATTERY_LEVEL_BLUETOOTH_OFF} if 1890 * Bluetooth is disabled or {@link #BATTERY_LEVEL_UNKNOWN} if device is disconnected, or 1891 * does not have any battery reporting service, or return value is invalid 1892 * @hide 1893 */ 1894 @SystemApi 1895 @RequiresLegacyBluetoothPermission 1896 @RequiresBluetoothConnectPermission 1897 @RequiresPermission(BLUETOOTH_CONNECT) getBatteryLevel()1898 public @IntRange(from = -100, to = 100) int getBatteryLevel() { 1899 if (DBG) log("getBatteryLevel()"); 1900 final IBluetooth service = getService(); 1901 if (service == null || !isBluetoothEnabled()) { 1902 Log.e(TAG, "Bluetooth disabled. Cannot get remote device battery level"); 1903 if (DBG) log(Log.getStackTraceString(new Throwable())); 1904 } else { 1905 try { 1906 return service.getBatteryLevel(this, mAttributionSource); 1907 } catch (RemoteException e) { 1908 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 1909 } 1910 } 1911 return BATTERY_LEVEL_BLUETOOTH_OFF; 1912 } 1913 1914 /** 1915 * Start the bonding (pairing) process with the remote device. 1916 * 1917 * <p>This is an asynchronous call, it will return immediately. Register for {@link 1918 * #ACTION_BOND_STATE_CHANGED} intents to be notified when the bonding process completes, and 1919 * its result. 1920 * 1921 * <p>Android system services will handle the necessary user interactions to confirm and 1922 * complete the bonding process. 1923 * 1924 * @return false on immediate error, true if bonding will begin 1925 */ 1926 @RequiresLegacyBluetoothAdminPermission 1927 @RequiresBluetoothConnectPermission 1928 @RequiresPermission(BLUETOOTH_CONNECT) createBond()1929 public boolean createBond() { 1930 return createBond(TRANSPORT_AUTO); 1931 } 1932 1933 /** 1934 * Start the bonding (pairing) process with the remote device using the specified transport. 1935 * 1936 * <p>This is an asynchronous call, it will return immediately. Register for {@link 1937 * #ACTION_BOND_STATE_CHANGED} intents to be notified when the bonding process completes, and 1938 * its result. 1939 * 1940 * <p>Android system services will handle the necessary user interactions to confirm and 1941 * complete the bonding process. 1942 * 1943 * @param transport The transport to use for the pairing procedure. 1944 * @return false on immediate error, true if bonding will begin 1945 * @throws IllegalArgumentException if an invalid transport was specified 1946 * @hide 1947 */ 1948 @SystemApi 1949 @RequiresLegacyBluetoothAdminPermission 1950 @RequiresBluetoothConnectPermission 1951 @RequiresPermission(BLUETOOTH_CONNECT) createBond(int transport)1952 public boolean createBond(int transport) { 1953 if (DBG) log("createBond()"); 1954 final IBluetooth service = getService(); 1955 if (service == null || !isBluetoothEnabled()) { 1956 Log.w(TAG, "BT not enabled, createBond failed"); 1957 if (DBG) log(Log.getStackTraceString(new Throwable())); 1958 } else if (NULL_MAC_ADDRESS.equals(mAddress)) { 1959 Log.e(TAG, "Unable to create bond, invalid address " + mAddress); 1960 } else { 1961 try { 1962 return service.createBond(this, transport, mAttributionSource); 1963 } catch (RemoteException e) { 1964 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 1965 } 1966 } 1967 return false; 1968 } 1969 1970 /** 1971 * Start the bonding (pairing) process with the remote device using the Out Of Band mechanism. 1972 * 1973 * <p>This is an asynchronous call, it will return immediately. Register for {@link 1974 * #ACTION_BOND_STATE_CHANGED} intents to be notified when the bonding process completes, and 1975 * its result. 1976 * 1977 * <p>Android system services will handle the necessary user interactions to confirm and 1978 * complete the bonding process. 1979 * 1980 * <p>There are two possible versions of OOB Data. This data can come in as P192 or P256. This 1981 * is a reference to the cryptography used to generate the key. The caller may pass one or both. 1982 * If both types of data are passed, then the P256 data will be preferred, and thus used. 1983 * 1984 * @param transport - Transport to use 1985 * @param remoteP192Data - Out Of Band data (P192) or null 1986 * @param remoteP256Data - Out Of Band data (P256) or null 1987 * @return false on immediate error, true if bonding will begin 1988 * @hide 1989 */ 1990 @SystemApi 1991 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) createBondOutOfBand( int transport, @Nullable OobData remoteP192Data, @Nullable OobData remoteP256Data)1992 public boolean createBondOutOfBand( 1993 int transport, @Nullable OobData remoteP192Data, @Nullable OobData remoteP256Data) { 1994 if (DBG) log("createBondOutOfBand()"); 1995 final IBluetooth service = getService(); 1996 1997 if (remoteP192Data == null && remoteP256Data == null) { 1998 throw new IllegalArgumentException( 1999 "One or both arguments for the OOB data types are required to not be null. " 2000 + " Please use createBond() instead if you do not have OOB data to pass."); 2001 } 2002 if (service == null || !isBluetoothEnabled()) { 2003 Log.w(TAG, "BT not enabled, createBondOutOfBand failed"); 2004 if (DBG) log(Log.getStackTraceString(new Throwable())); 2005 } else if (NULL_MAC_ADDRESS.equals(mAddress)) { 2006 Log.e(TAG, "Unable to create bond Out of Band, invalid address " + mAddress); 2007 } else { 2008 try { 2009 return service.createBondOutOfBand( 2010 this, transport, remoteP192Data, remoteP256Data, mAttributionSource); 2011 } catch (RemoteException e) { 2012 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2013 } 2014 } 2015 return false; 2016 } 2017 2018 /** 2019 * Gets whether bonding was initiated locally 2020 * 2021 * @return true if bonding is initiated locally, false otherwise 2022 * @hide 2023 */ 2024 @SystemApi 2025 @RequiresLegacyBluetoothPermission 2026 @RequiresBluetoothConnectPermission 2027 @RequiresPermission(BLUETOOTH_CONNECT) isBondingInitiatedLocally()2028 public boolean isBondingInitiatedLocally() { 2029 if (DBG) log("isBondingInitiatedLocally()"); 2030 final IBluetooth service = getService(); 2031 if (service == null || !isBluetoothEnabled()) { 2032 Log.w(TAG, "BT not enabled, isBondingInitiatedLocally failed"); 2033 if (DBG) log(Log.getStackTraceString(new Throwable())); 2034 } else { 2035 try { 2036 return service.isBondingInitiatedLocally(this, mAttributionSource); 2037 } catch (RemoteException e) { 2038 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2039 } 2040 } 2041 return false; 2042 } 2043 2044 /** 2045 * Cancel an in-progress bonding request started with {@link #createBond}. 2046 * 2047 * @return true on success, false on error 2048 * @hide 2049 */ 2050 @SystemApi 2051 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) cancelBondProcess()2052 public boolean cancelBondProcess() { 2053 if (DBG) log("cancelBondProcess()"); 2054 final IBluetooth service = getService(); 2055 if (service == null || !isBluetoothEnabled()) { 2056 Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond"); 2057 if (DBG) log(Log.getStackTraceString(new Throwable())); 2058 } else { 2059 Log.i( 2060 TAG, 2061 "cancelBondProcess() for" 2062 + (" device " + this) 2063 + (" called by pid: " + Process.myPid()) 2064 + (" tid: " + Process.myTid())); 2065 try { 2066 return service.cancelBondProcess(this, mAttributionSource); 2067 } catch (RemoteException e) { 2068 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2069 } 2070 } 2071 return false; 2072 } 2073 2074 /** 2075 * Remove bond (pairing) with the remote device. 2076 * 2077 * <p>Delete the link key associated with the remote device, and immediately terminate 2078 * connections to that device that require authentication and encryption. 2079 * 2080 * @return true on success, false on error 2081 * @hide 2082 */ 2083 @SystemApi 2084 @RequiresPermission(BLUETOOTH_CONNECT) removeBond()2085 public boolean removeBond() { 2086 if (DBG) log("removeBond()"); 2087 final IBluetooth service = getService(); 2088 if (service == null || !isBluetoothEnabled()) { 2089 Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond"); 2090 if (DBG) log(Log.getStackTraceString(new Throwable())); 2091 } else { 2092 Log.i( 2093 TAG, 2094 "removeBond() for" 2095 + (" device " + this) 2096 + (" called by pid: " + Process.myPid()) 2097 + (" tid: " + Process.myTid())); 2098 try { 2099 return service.removeBond(this, mAttributionSource); 2100 } catch (RemoteException e) { 2101 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2102 } 2103 } 2104 return false; 2105 } 2106 2107 /** 2108 * There are several instances of IpcDataCache used in this class. BluetoothCache wraps up the 2109 * common code. All caches are created with a maximum of eight entries, and the key is in the 2110 * bluetooth module. The name is set to the api. 2111 */ 2112 private static class BluetoothCache<Q, R> extends IpcDataCache<Q, R> { BluetoothCache(String api, IpcDataCache.QueryHandler query)2113 BluetoothCache(String api, IpcDataCache.QueryHandler query) { 2114 super(8, IpcDataCache.MODULE_BLUETOOTH, api, api, query); 2115 } 2116 } 2117 ; 2118 2119 /** 2120 * Invalidate a bluetooth cache. This method is just a short-hand wrapper that enforces the 2121 * bluetooth module. 2122 */ invalidateCache(@onNull String api)2123 private static void invalidateCache(@NonNull String api) { 2124 IpcDataCache.invalidateCache(IpcDataCache.MODULE_BLUETOOTH, api); 2125 } 2126 2127 private static final IpcDataCache.QueryHandler< 2128 Pair<IBluetooth, Pair<AttributionSource, BluetoothDevice>>, Integer> 2129 sBluetoothBondQuery = 2130 new IpcDataCache.QueryHandler<>() { 2131 @RequiresLegacyBluetoothPermission 2132 @RequiresBluetoothConnectPermission 2133 @RequiresPermission(BLUETOOTH_CONNECT) 2134 @Override 2135 public Integer apply( 2136 Pair<IBluetooth, Pair<AttributionSource, BluetoothDevice>> 2137 pairQuery) { 2138 IBluetooth service = pairQuery.first; 2139 AttributionSource source = pairQuery.second.first; 2140 BluetoothDevice device = pairQuery.second.second; 2141 if (DBG) { 2142 log("getBondState(" + device + ") uncached"); 2143 } 2144 try { 2145 return service.getBondState(device, source); 2146 } catch (RemoteException e) { 2147 throw e.rethrowAsRuntimeException(); 2148 } 2149 } 2150 }; 2151 2152 private static final String GET_BOND_STATE_API = "BluetoothDevice_getBondState"; 2153 2154 private static final BluetoothCache< 2155 Pair<IBluetooth, Pair<AttributionSource, BluetoothDevice>>, Integer> 2156 sBluetoothBondCache = new BluetoothCache<>(GET_BOND_STATE_API, sBluetoothBondQuery); 2157 2158 /** @hide */ disableBluetoothGetBondStateCache()2159 public void disableBluetoothGetBondStateCache() { 2160 sBluetoothBondCache.disableForCurrentProcess(); 2161 } 2162 2163 /** @hide */ invalidateBluetoothGetBondStateCache()2164 public static void invalidateBluetoothGetBondStateCache() { 2165 invalidateCache(GET_BOND_STATE_API); 2166 } 2167 2168 /** 2169 * Get the bond state of the remote device. 2170 * 2171 * <p>Possible values for the bond state are: {@link #BOND_NONE}, {@link #BOND_BONDING}, {@link 2172 * #BOND_BONDED}. 2173 * 2174 * @return the bond state 2175 */ 2176 @RequiresLegacyBluetoothPermission 2177 @RequiresBluetoothConnectPermission 2178 @RequiresPermission(BLUETOOTH_CONNECT) 2179 @SuppressLint("AndroidFrameworkRequiresPermission") // IpcDataCache prevent lint enforcement getBondState()2180 public int getBondState() { 2181 if (DBG) log("getBondState(" + this + ")"); 2182 final IBluetooth service = getService(); 2183 if (service == null) { 2184 Log.e(TAG, "BT not enabled. Cannot get bond state"); 2185 if (DBG) log(Log.getStackTraceString(new Throwable())); 2186 } else { 2187 try { 2188 return sBluetoothBondCache.query( 2189 new Pair<>(service, new Pair<>(mAttributionSource, BluetoothDevice.this))); 2190 } catch (RuntimeException e) { 2191 if (!(e.getCause() instanceof RemoteException)) { 2192 throw e; 2193 } 2194 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2195 } 2196 } 2197 return BOND_NONE; 2198 } 2199 2200 /** 2201 * Checks whether this bluetooth device is associated with CDM and meets the criteria to skip 2202 * the bluetooth pairing dialog because it has been already consented by the CDM prompt. 2203 * 2204 * @return true if we can bond without the dialog, false otherwise 2205 * @hide 2206 */ 2207 @SystemApi 2208 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) canBondWithoutDialog()2209 public boolean canBondWithoutDialog() { 2210 if (DBG) log("canBondWithoutDialog, device: " + this); 2211 final IBluetooth service = getService(); 2212 if (service == null || !isBluetoothEnabled()) { 2213 Log.e(TAG, "BT not enabled. Cannot check if we can skip pairing dialog"); 2214 if (DBG) log(Log.getStackTraceString(new Throwable())); 2215 } else { 2216 try { 2217 return service.canBondWithoutDialog(this, mAttributionSource); 2218 } catch (RemoteException e) { 2219 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2220 } 2221 } 2222 return false; 2223 } 2224 2225 /** 2226 * Gets the package name of the application that initiate bonding with this device 2227 * 2228 * @return package name of the application, or null of no application initiate bonding with this 2229 * device 2230 * @hide 2231 */ 2232 @SystemApi 2233 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) getPackageNameOfBondingApplication()2234 public @Nullable String getPackageNameOfBondingApplication() { 2235 if (DBG) log("getPackageNameOfBondingApplication()"); 2236 final IBluetooth service = getService(); 2237 if (service == null || !isBluetoothEnabled()) { 2238 Log.w(TAG, "BT not enabled, getPackageNameOfBondingApplication failed"); 2239 if (DBG) log(Log.getStackTraceString(new Throwable())); 2240 } else { 2241 try { 2242 return service.getPackageNameOfBondingApplication(this, mAttributionSource); 2243 } catch (RemoteException e) { 2244 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2245 } 2246 } 2247 return null; 2248 } 2249 2250 /** @hide */ 2251 @Retention(RetentionPolicy.SOURCE) 2252 @IntDef( 2253 value = { 2254 BluetoothStatusCodes.SUCCESS, 2255 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, 2256 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED, 2257 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, 2258 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED 2259 }) 2260 public @interface ConnectionReturnValues {} 2261 2262 /** 2263 * Connects all user enabled and supported bluetooth profiles between the local and remote 2264 * device. If no profiles are user enabled (e.g. first connection), we connect all supported 2265 * profiles. If the device is not already connected, this will page the device before initiating 2266 * profile connections. Connection is asynchronous and you should listen to each profile's 2267 * broadcast intent ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful. 2268 * For example, to verify a2dp is connected, you would listen for {@link 2269 * BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} 2270 * 2271 * @return whether the messages were successfully sent to try to connect all profiles 2272 * @throws IllegalArgumentException if the device address is invalid 2273 * @hide 2274 */ 2275 @SystemApi 2276 @RequiresBluetoothConnectPermission 2277 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED, MODIFY_PHONE_STATE}) connect()2278 public @ConnectionReturnValues int connect() { 2279 if (DBG) log("connect()"); 2280 if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) { 2281 throw new IllegalArgumentException("device cannot have an invalid address"); 2282 } 2283 final IBluetooth service = getService(); 2284 if (service == null || !isBluetoothEnabled()) { 2285 Log.e(TAG, "BT not enabled. Cannot connect to remote device."); 2286 if (DBG) log(Log.getStackTraceString(new Throwable())); 2287 } else { 2288 try { 2289 return service.connectAllEnabledProfiles(this, mAttributionSource); 2290 } catch (RemoteException e) { 2291 Log.e(TAG, "", e); 2292 } 2293 } 2294 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; 2295 } 2296 2297 /** 2298 * Disconnects all connected bluetooth profiles between the local and remote device. 2299 * Disconnection is asynchronous, so you should listen to each profile's broadcast intent 2300 * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example, 2301 * to verify a2dp is disconnected, you would listen for {@link 2302 * BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED}. Once all profiles have disconnected, the ACL 2303 * link should come down and {@link #ACTION_ACL_DISCONNECTED} should be broadcast. 2304 * 2305 * <p>In the rare event that one or more profiles fail to disconnect, call this method again to 2306 * send another request to disconnect each connected profile. 2307 * 2308 * @return whether the messages were successfully sent to try to disconnect all profiles 2309 * @throws IllegalArgumentException if the device address is invalid 2310 * @hide 2311 */ 2312 @SystemApi 2313 @RequiresBluetoothConnectPermission 2314 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) disconnect()2315 public @ConnectionReturnValues int disconnect() { 2316 if (DBG) log("disconnect()"); 2317 if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) { 2318 throw new IllegalArgumentException("device cannot have an invalid address"); 2319 } 2320 final IBluetooth service = getService(); 2321 if (service == null || !isBluetoothEnabled()) { 2322 Log.e(TAG, "BT not enabled. Cannot disconnect to remote device."); 2323 if (DBG) log(Log.getStackTraceString(new Throwable())); 2324 } else { 2325 try { 2326 return service.disconnectAllEnabledProfiles(this, mAttributionSource); 2327 } catch (RemoteException e) { 2328 Log.e(TAG, "", e); 2329 } 2330 } 2331 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; 2332 } 2333 2334 /** 2335 * Returns whether there is an open connection to this device. 2336 * 2337 * @return True if there is at least one open connection to this device. 2338 * @hide 2339 */ 2340 @SystemApi 2341 @RequiresLegacyBluetoothPermission 2342 @RequiresBluetoothConnectPermission 2343 @RequiresPermission(BLUETOOTH_CONNECT) isConnected()2344 public boolean isConnected() { 2345 if (DBG) log("isConnected()"); 2346 final IBluetooth service = getService(); 2347 if (service == null || !isBluetoothEnabled()) { 2348 Log.w(TAG, "Proxy not attached to service"); 2349 if (DBG) log(Log.getStackTraceString(new Throwable())); 2350 } else { 2351 try { 2352 return service.getConnectionState(this, mAttributionSource) 2353 != CONNECTION_STATE_DISCONNECTED; 2354 } catch (RemoteException e) { 2355 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2356 } 2357 } 2358 // BT is not enabled, we cannot be connected. 2359 return false; 2360 } 2361 2362 /** 2363 * Returns the ACL connection handle associated with an open connection to this device on the 2364 * given transport. 2365 * 2366 * <p>This handle is a unique identifier for the connection while it remains active. Refer to 2367 * the Bluetooth Core Specification Version 5.4 Vol 4 Part E Section 5.3.1 Controller Handles 2368 * for details. 2369 * 2370 * @return the ACL handle, or {@link BluetoothDevice#ERROR} if no connection currently exists on 2371 * the given transport. 2372 * @hide 2373 */ 2374 @SystemApi 2375 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) getConnectionHandle(@ransport int transport)2376 public int getConnectionHandle(@Transport int transport) { 2377 if (DBG) { 2378 log("getConnectionHandle()"); 2379 } 2380 final IBluetooth service = getService(); 2381 if (service == null || !isBluetoothEnabled()) { 2382 Log.w(TAG, "Proxy not attached to service"); 2383 if (DBG) { 2384 log(Log.getStackTraceString(new Throwable())); 2385 } 2386 } else { 2387 try { 2388 return service.getConnectionHandle(this, transport, mAttributionSource); 2389 } catch (RemoteException e) { 2390 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2391 } 2392 } 2393 // BT is not enabled, we cannot be connected. 2394 return BluetoothDevice.ERROR; 2395 } 2396 2397 /** 2398 * Returns whether there is an open connection to this device that has been encrypted. 2399 * 2400 * @return True if there is at least one encrypted connection to this device. 2401 * @hide 2402 */ 2403 @SystemApi 2404 @RequiresLegacyBluetoothPermission 2405 @RequiresBluetoothConnectPermission 2406 @RequiresPermission(BLUETOOTH_CONNECT) isEncrypted()2407 public boolean isEncrypted() { 2408 if (DBG) log("isEncrypted()"); 2409 final IBluetooth service = getService(); 2410 if (service == null || !isBluetoothEnabled()) { 2411 Log.w(TAG, "Proxy not attached to service"); 2412 if (DBG) log(Log.getStackTraceString(new Throwable())); 2413 } else { 2414 try { 2415 return service.getConnectionState(this, mAttributionSource) 2416 > CONNECTION_STATE_CONNECTED; 2417 } catch (RemoteException e) { 2418 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2419 } 2420 } 2421 // BT is not enabled, we cannot be encrypted. 2422 return false; 2423 } 2424 2425 /** 2426 * Get the Bluetooth class of the remote device. 2427 * 2428 * @return Bluetooth class object, or null on error 2429 */ 2430 @RequiresLegacyBluetoothPermission 2431 @RequiresBluetoothConnectPermission 2432 @RequiresPermission(BLUETOOTH_CONNECT) getBluetoothClass()2433 public BluetoothClass getBluetoothClass() { 2434 if (DBG) log("getBluetoothClass()"); 2435 final IBluetooth service = getService(); 2436 if (service == null || !isBluetoothEnabled()) { 2437 Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class"); 2438 if (DBG) log(Log.getStackTraceString(new Throwable())); 2439 } else { 2440 try { 2441 int classInt = service.getRemoteClass(this, mAttributionSource); 2442 if (classInt == BluetoothClass.ERROR) return null; 2443 return new BluetoothClass(classInt); 2444 } catch (RemoteException e) { 2445 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2446 } 2447 } 2448 return null; 2449 } 2450 2451 /** 2452 * Returns the supported features (UUIDs) of the remote device. 2453 * 2454 * <p>This method does not start a service discovery procedure to retrieve the UUIDs from the 2455 * remote device. Instead, the local cached copy of the service UUIDs are returned. 2456 * 2457 * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired. 2458 * 2459 * @return the supported features (UUIDs) of the remote device, or null on error 2460 */ 2461 @RequiresLegacyBluetoothPermission 2462 @RequiresBluetoothConnectPermission 2463 @RequiresPermission(BLUETOOTH_CONNECT) getUuids()2464 public ParcelUuid[] getUuids() { 2465 if (DBG) log("getUuids()"); 2466 final IBluetooth service = getService(); 2467 if (service == null || !isBluetoothEnabled()) { 2468 Log.e(TAG, "BT not enabled. Cannot get remote device Uuids"); 2469 if (DBG) log(Log.getStackTraceString(new Throwable())); 2470 } else { 2471 try { 2472 List<ParcelUuid> parcels = service.getRemoteUuids(this, mAttributionSource); 2473 return parcels != null ? parcels.toArray(new ParcelUuid[parcels.size()]) : null; 2474 } catch (RemoteException e) { 2475 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2476 } 2477 } 2478 return null; 2479 } 2480 2481 /** 2482 * Perform a service discovery on the remote device to get the UUIDs supported. 2483 * 2484 * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent, with the UUIDs supported 2485 * by the remote end. If there is an error in getting the SDP records or if the process takes a 2486 * long time, or the device is bonding and we have its UUIDs cached, {@link #ACTION_UUID} intent 2487 * is sent with the UUIDs that is currently present in the cache. Clients should use the {@link 2488 * #getUuids} to get UUIDs if service discovery is not to be performed. If there is an ongoing 2489 * bonding process, service discovery or device inquiry, the request will be queued. 2490 * 2491 * @return False if the check fails, True if the process of initiating an ACL connection to the 2492 * remote device was started or cached UUIDs will be broadcast. 2493 */ 2494 @RequiresLegacyBluetoothPermission 2495 @RequiresBluetoothConnectPermission 2496 @RequiresPermission(BLUETOOTH_CONNECT) 2497 @SuppressLint("AndroidFrameworkRequiresPermission") // See fetchUuidsWithSdp(int) for reason fetchUuidsWithSdp()2498 public boolean fetchUuidsWithSdp() { 2499 return fetchUuidsWithSdp(TRANSPORT_AUTO); 2500 } 2501 2502 /** 2503 * Perform a service discovery on the remote device to get the UUIDs supported with the specific 2504 * transport. 2505 * 2506 * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent, with the UUIDs supported 2507 * by the remote end. If there is an error in getting the SDP or GATT records or if the process 2508 * takes a long time, or the device is bonding and we have its UUIDs cached, {@link 2509 * #ACTION_UUID} intent is sent with the UUIDs that is currently present in the cache. Clients 2510 * should use the {@link #getUuids} to get UUIDs if service discovery is not to be performed. If 2511 * there is an ongoing bonding process, service discovery or device inquiry, the request will be 2512 * queued. 2513 * 2514 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission only when 2515 * {@code transport} is not {@code #TRANSPORT_AUTO}. 2516 * 2517 * <p>The {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission is always enforced. 2518 * 2519 * @param transport - provide type of transport (e.g. LE or Classic). 2520 * @return False if the check fails, True if the process of initiating an ACL connection to the 2521 * remote device was started or cached UUIDs will be broadcast with the specific transport. 2522 * @hide 2523 */ 2524 @SystemApi 2525 @RequiresPermission( 2526 allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}, 2527 conditional = true) fetchUuidsWithSdp(@ransport int transport)2528 public boolean fetchUuidsWithSdp(@Transport int transport) { 2529 if (DBG) log("fetchUuidsWithSdp()"); 2530 final IBluetooth service = getService(); 2531 if (service == null || !isBluetoothEnabled()) { 2532 Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp"); 2533 if (DBG) log(Log.getStackTraceString(new Throwable())); 2534 } else { 2535 try { 2536 return service.fetchRemoteUuids(this, transport, mAttributionSource); 2537 } catch (RemoteException e) { 2538 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2539 } 2540 } 2541 return false; 2542 } 2543 2544 /** 2545 * Perform a service discovery on the remote device to get the SDP records associated with the 2546 * specified UUID. 2547 * 2548 * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent, with the SDP 2549 * records found on the remote end. If there is an error in getting the SDP records or if the 2550 * process takes a long time, {@link #ACTION_SDP_RECORD} intent is sent with an status value in 2551 * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0. Detailed status error codes can be found 2552 * by members of the Bluetooth package in the AbstractionLayer class. 2553 * 2554 * <p>The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}. The object 2555 * type will match one of the SdpXxxRecord types, depending on the UUID searched for. 2556 * 2557 * @return False if the check fails, True if the process of initiating an ACL connection to the 2558 * remote device was started. 2559 */ 2560 /** @hide */ 2561 @RequiresLegacyBluetoothPermission 2562 @RequiresBluetoothConnectPermission 2563 @RequiresPermission(BLUETOOTH_CONNECT) sdpSearch(ParcelUuid uuid)2564 public boolean sdpSearch(ParcelUuid uuid) { 2565 if (DBG) log("sdpSearch()"); 2566 final IBluetooth service = getService(); 2567 if (service == null || !isBluetoothEnabled()) { 2568 Log.e(TAG, "BT not enabled. Cannot query remote device sdp records"); 2569 if (DBG) log(Log.getStackTraceString(new Throwable())); 2570 } else { 2571 try { 2572 return service.sdpSearch(this, uuid, mAttributionSource); 2573 } catch (RemoteException e) { 2574 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2575 } 2576 } 2577 return false; 2578 } 2579 2580 /** 2581 * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} 2582 * 2583 * @return true pin has been set false for error 2584 */ 2585 @RequiresLegacyBluetoothAdminPermission 2586 @RequiresBluetoothConnectPermission 2587 @RequiresPermission(BLUETOOTH_CONNECT) setPin(byte[] pin)2588 public boolean setPin(byte[] pin) { 2589 if (DBG) log("setPin()"); 2590 final IBluetooth service = getService(); 2591 if (service == null || !isBluetoothEnabled()) { 2592 Log.e(TAG, "BT not enabled. Cannot set Remote Device pin"); 2593 if (DBG) log(Log.getStackTraceString(new Throwable())); 2594 } else { 2595 try { 2596 return service.setPin(this, true, pin.length, pin, mAttributionSource); 2597 } catch (RemoteException e) { 2598 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2599 } 2600 } 2601 return false; 2602 } 2603 2604 /** 2605 * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} 2606 * 2607 * @return true pin has been set false for error 2608 * @hide 2609 */ 2610 @SystemApi 2611 @RequiresLegacyBluetoothAdminPermission 2612 @RequiresBluetoothConnectPermission 2613 @RequiresPermission(BLUETOOTH_CONNECT) setPin(@onNull String pin)2614 public boolean setPin(@NonNull String pin) { 2615 byte[] pinBytes = convertPinToBytes(pin); 2616 if (pinBytes == null) { 2617 return false; 2618 } 2619 return setPin(pinBytes); 2620 } 2621 2622 /** 2623 * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing. 2624 * 2625 * @return true confirmation has been sent out false for error 2626 */ 2627 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) setPairingConfirmation(boolean confirm)2628 public boolean setPairingConfirmation(boolean confirm) { 2629 if (DBG) log("setPairingConfirmation()"); 2630 final IBluetooth service = getService(); 2631 if (service == null || !isBluetoothEnabled()) { 2632 Log.e(TAG, "BT not enabled. Cannot set pairing confirmation"); 2633 if (DBG) log(Log.getStackTraceString(new Throwable())); 2634 } else { 2635 try { 2636 return service.setPairingConfirmation(this, confirm, mAttributionSource); 2637 } catch (RemoteException e) { 2638 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2639 } 2640 } 2641 return false; 2642 } 2643 isBluetoothEnabled()2644 boolean isBluetoothEnabled() { 2645 boolean ret = false; 2646 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 2647 if (adapter != null && adapter.isEnabled()) { 2648 ret = true; 2649 } 2650 return ret; 2651 } 2652 2653 /** 2654 * Gets whether the phonebook access is allowed for this bluetooth device 2655 * 2656 * @return Whether the phonebook access is allowed to this device. Can be {@link 2657 * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. 2658 * @hide 2659 */ 2660 @SystemApi 2661 @RequiresLegacyBluetoothPermission 2662 @RequiresBluetoothConnectPermission 2663 @RequiresPermission(BLUETOOTH_CONNECT) getPhonebookAccessPermission()2664 public @AccessPermission int getPhonebookAccessPermission() { 2665 if (DBG) log("getPhonebookAccessPermission()"); 2666 final IBluetooth service = getService(); 2667 if (service == null || !isBluetoothEnabled()) { 2668 Log.w(TAG, "Proxy not attached to service"); 2669 if (DBG) log(Log.getStackTraceString(new Throwable())); 2670 } else { 2671 try { 2672 return service.getPhonebookAccessPermission(this, mAttributionSource); 2673 } catch (RemoteException e) { 2674 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2675 } 2676 } 2677 return ACCESS_UNKNOWN; 2678 } 2679 2680 /** 2681 * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not be routed to the 2682 * {@link BluetoothDevice} if set to {@code true}. 2683 * 2684 * <p>When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice} is 2685 * an active device (for A2DP or HFP), the active device for that profile will be set to null. 2686 * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP active device is 2687 * null, the {@link BluetoothDevice} will be set as the active device for that profile. If the 2688 * {@link BluetoothDevice} is disconnected, it exits silence mode. If the {@link 2689 * BluetoothDevice} is set as the active device for A2DP or HFP, while silence mode is enabled, 2690 * then the device will exit silence mode. If the {@link BluetoothDevice} is in silence mode, 2691 * AVRCP position change event and HFP AG indicators will be disabled. If the {@link 2692 * BluetoothDevice} is not connected with A2DP or HFP, it cannot enter silence mode. 2693 * 2694 * @param silence true to enter silence mode, false to exit 2695 * @return true on success, false on error. 2696 * @throws IllegalStateException if Bluetooth is not turned ON. 2697 * @hide 2698 */ 2699 @SystemApi 2700 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) setSilenceMode(boolean silence)2701 public boolean setSilenceMode(boolean silence) { 2702 if (DBG) log("setSilenceMode()"); 2703 final IBluetooth service = getService(); 2704 if (service == null || !isBluetoothEnabled()) { 2705 throw new IllegalStateException("Bluetooth is not turned ON"); 2706 } else { 2707 try { 2708 return service.setSilenceMode(this, silence, mAttributionSource); 2709 } catch (RemoteException e) { 2710 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2711 } 2712 } 2713 return false; 2714 } 2715 2716 /** 2717 * Check whether the {@link BluetoothDevice} is in silence mode 2718 * 2719 * @return true on device in silence mode, otherwise false. 2720 * @throws IllegalStateException if Bluetooth is not turned ON. 2721 * @hide 2722 */ 2723 @SystemApi 2724 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) isInSilenceMode()2725 public boolean isInSilenceMode() { 2726 if (DBG) log("isInSilenceMode()"); 2727 final IBluetooth service = getService(); 2728 if (service == null || !isBluetoothEnabled()) { 2729 throw new IllegalStateException("Bluetooth is not turned ON"); 2730 } else { 2731 try { 2732 return service.getSilenceMode(this, mAttributionSource); 2733 } catch (RemoteException e) { 2734 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2735 } 2736 } 2737 return false; 2738 } 2739 2740 /** 2741 * Sets whether the phonebook access is allowed to this device. 2742 * 2743 * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link 2744 * #ACCESS_REJECTED}. 2745 * @return Whether the value has been successfully set. 2746 * @hide 2747 */ 2748 @SystemApi 2749 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) setPhonebookAccessPermission(@ccessPermission int value)2750 public boolean setPhonebookAccessPermission(@AccessPermission int value) { 2751 if (DBG) log("setPhonebookAccessPermission()"); 2752 final IBluetooth service = getService(); 2753 if (service == null || !isBluetoothEnabled()) { 2754 Log.w(TAG, "Proxy not attached to service"); 2755 if (DBG) log(Log.getStackTraceString(new Throwable())); 2756 } else { 2757 try { 2758 return service.setPhonebookAccessPermission(this, value, mAttributionSource); 2759 } catch (RemoteException e) { 2760 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2761 } 2762 } 2763 return false; 2764 } 2765 2766 /** 2767 * Gets whether message access is allowed to this bluetooth device 2768 * 2769 * @return Whether the message access is allowed to this device. 2770 * @hide 2771 */ 2772 @SystemApi 2773 @RequiresLegacyBluetoothPermission 2774 @RequiresBluetoothConnectPermission 2775 @RequiresPermission(BLUETOOTH_CONNECT) getMessageAccessPermission()2776 public @AccessPermission int getMessageAccessPermission() { 2777 if (DBG) log("getMessageAccessPermission()"); 2778 final IBluetooth service = getService(); 2779 if (service == null || !isBluetoothEnabled()) { 2780 Log.w(TAG, "Proxy not attached to service"); 2781 if (DBG) log(Log.getStackTraceString(new Throwable())); 2782 } else { 2783 try { 2784 return service.getMessageAccessPermission(this, mAttributionSource); 2785 } catch (RemoteException e) { 2786 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2787 } 2788 } 2789 return ACCESS_UNKNOWN; 2790 } 2791 2792 /** 2793 * Sets whether the message access is allowed to this device. 2794 * 2795 * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded, {@link 2796 * #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if the 2797 * permission is not being granted. 2798 * @return Whether the value has been successfully set. 2799 * @hide 2800 */ 2801 @SystemApi 2802 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) setMessageAccessPermission(@ccessPermission int value)2803 public boolean setMessageAccessPermission(@AccessPermission int value) { 2804 // Validates param value is one of the accepted constants 2805 if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) { 2806 throw new IllegalArgumentException(value + "is not a valid AccessPermission value"); 2807 } 2808 if (DBG) log("setMessageAccessPermission()"); 2809 final IBluetooth service = getService(); 2810 if (service == null || !isBluetoothEnabled()) { 2811 Log.w(TAG, "Proxy not attached to service"); 2812 if (DBG) log(Log.getStackTraceString(new Throwable())); 2813 } else { 2814 try { 2815 return service.setMessageAccessPermission(this, value, mAttributionSource); 2816 } catch (RemoteException e) { 2817 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2818 } 2819 } 2820 return false; 2821 } 2822 2823 /** 2824 * Gets whether sim access is allowed for this bluetooth device 2825 * 2826 * @return Whether the Sim access is allowed to this device. 2827 * @hide 2828 */ 2829 @SystemApi 2830 @RequiresLegacyBluetoothPermission 2831 @RequiresBluetoothConnectPermission 2832 @RequiresPermission(BLUETOOTH_CONNECT) getSimAccessPermission()2833 public @AccessPermission int getSimAccessPermission() { 2834 if (DBG) log("getSimAccessPermission()"); 2835 final IBluetooth service = getService(); 2836 if (service == null || !isBluetoothEnabled()) { 2837 Log.w(TAG, "Proxy not attached to service"); 2838 if (DBG) log(Log.getStackTraceString(new Throwable())); 2839 } else { 2840 try { 2841 return service.getSimAccessPermission(this, mAttributionSource); 2842 } catch (RemoteException e) { 2843 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2844 } 2845 } 2846 return ACCESS_UNKNOWN; 2847 } 2848 2849 /** 2850 * Sets whether the Sim access is allowed to this device. 2851 * 2852 * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded, {@link 2853 * #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if the 2854 * permission is not being granted. 2855 * @return Whether the value has been successfully set. 2856 * @hide 2857 */ 2858 @SystemApi 2859 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) setSimAccessPermission(int value)2860 public boolean setSimAccessPermission(int value) { 2861 if (DBG) log("setSimAccessPermission()"); 2862 final IBluetooth service = getService(); 2863 if (service == null || !isBluetoothEnabled()) { 2864 Log.w(TAG, "Proxy not attached to service"); 2865 if (DBG) log(Log.getStackTraceString(new Throwable())); 2866 } else { 2867 try { 2868 return service.setSimAccessPermission(this, value, mAttributionSource); 2869 } catch (RemoteException e) { 2870 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 2871 } 2872 } 2873 return false; 2874 } 2875 2876 /** 2877 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure outgoing connection to this 2878 * remote device on given channel. 2879 * 2880 * <p>The remote device will be authenticated and communication on this socket will be 2881 * encrypted. 2882 * 2883 * <p>Use this socket only if an authenticated socket link is possible. Authentication refers to 2884 * the authentication of the link key to prevent person-in-the-middle type of attacks. For 2885 * example, for Bluetooth 2.1 devices, if any of the devices does not have an input and output 2886 * capability or just has the ability to display a numeric key, a secure socket connection is 2887 * not possible. In such a case, use {@link createInsecureRfcommSocket}. For more details, refer 2888 * to the Security Model section 5.2 (vol 3) of Bluetooth Core Specification version 2.1 + EDR. 2889 * 2890 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 2891 * 2892 * <p>Valid RFCOMM channels are in range 1 to 30. 2893 * 2894 * @param channel RFCOMM channel to connect to 2895 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2896 * @throws IOException on error, for example Bluetooth not available, or insufficient 2897 * permissions 2898 * @hide 2899 */ 2900 @UnsupportedAppUsage 2901 @RequiresLegacyBluetoothPermission createRfcommSocket(int channel)2902 public BluetoothSocket createRfcommSocket(int channel) throws IOException { 2903 if (!isBluetoothEnabled()) { 2904 Log.e(TAG, "Bluetooth is not enabled"); 2905 throw new IOException(); 2906 } 2907 return new BluetoothSocket(this, BluetoothSocket.TYPE_RFCOMM, true, true, channel, null); 2908 } 2909 2910 /** 2911 * Create an L2cap {@link BluetoothSocket} ready to start a secure outgoing connection to this 2912 * remote device on given channel. 2913 * 2914 * <p>The remote device will be authenticated and communication on this socket will be 2915 * encrypted. 2916 * 2917 * <p>Use this socket only if an authenticated socket link is possible. Authentication refers to 2918 * the authentication of the link key to prevent person-in-the-middle type of attacks. For 2919 * example, for Bluetooth 2.1 devices, if any of the devices does not have an input and output 2920 * capability or just has the ability to display a numeric key, a secure socket connection is 2921 * not possible. In such a case, use {@link createInsecureRfcommSocket}. For more details, refer 2922 * to the Security Model section 5.2 (vol 3) of Bluetooth Core Specification version 2.1 + EDR. 2923 * 2924 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 2925 * 2926 * <p>Valid L2CAP PSM channels are in range 1 to 2^16. 2927 * 2928 * @param channel L2cap PSM/channel to connect to 2929 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2930 * @throws IOException on error, for example Bluetooth not available, or insufficient 2931 * permissions 2932 * @hide 2933 */ 2934 @RequiresLegacyBluetoothPermission createL2capSocket(int channel)2935 public BluetoothSocket createL2capSocket(int channel) throws IOException { 2936 return new BluetoothSocket(this, BluetoothSocket.TYPE_L2CAP, true, true, channel, null); 2937 } 2938 2939 /** 2940 * Create an L2cap {@link BluetoothSocket} ready to start an insecure outgoing connection to 2941 * this remote device on given channel. 2942 * 2943 * <p>The remote device will be not authenticated and communication on this socket will not be 2944 * encrypted. 2945 * 2946 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 2947 * 2948 * <p>Valid L2CAP PSM channels are in range 1 to 2^16. 2949 * 2950 * @param channel L2cap PSM/channel to connect to 2951 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2952 * @throws IOException on error, for example Bluetooth not available, or insufficient 2953 * permissions 2954 * @hide 2955 */ 2956 @RequiresLegacyBluetoothPermission createInsecureL2capSocket(int channel)2957 public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException { 2958 return new BluetoothSocket(this, BluetoothSocket.TYPE_L2CAP, false, false, channel, null); 2959 } 2960 2961 /** 2962 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure outgoing connection to this 2963 * remote device using SDP lookup of uuid. 2964 * 2965 * <p>This is designed to be used with {@link 2966 * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer Bluetooth applications. 2967 * 2968 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. This will also 2969 * perform an SDP lookup of the given uuid to determine which channel to connect to. 2970 * 2971 * <p>The remote device will be authenticated and communication on this socket will be 2972 * encrypted. 2973 * 2974 * <p>Use this socket only if an authenticated socket link is possible. Authentication refers to 2975 * the authentication of the link key to prevent person-in-the-middle type of attacks. For 2976 * example, for Bluetooth 2.1 devices, if any of the devices does not have an input and output 2977 * capability or just has the ability to display a numeric key, a secure socket connection is 2978 * not possible. In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}. For 2979 * more details, refer to the Security Model section 5.2 (vol 3) of Bluetooth Core Specification 2980 * version 2.1 + EDR. 2981 * 2982 * <p>Hint: If you are connecting to a Bluetooth serial board then try using the well-known SPP 2983 * UUID 00001101-0000-1000-8000-00805F9B34FB. However if you are connecting to an Android peer 2984 * then please generate your own unique UUID. 2985 * 2986 * @param uuid service record uuid to lookup RFCOMM channel 2987 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2988 * @throws IOException on error, for example Bluetooth not available, or insufficient 2989 * permissions 2990 */ 2991 @RequiresLegacyBluetoothPermission createRfcommSocketToServiceRecord(UUID uuid)2992 public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException { 2993 if (!isBluetoothEnabled()) { 2994 Log.e(TAG, "Bluetooth is not enabled"); 2995 throw new IOException(); 2996 } 2997 2998 return new BluetoothSocket( 2999 this, BluetoothSocket.TYPE_RFCOMM, true, true, -1, new ParcelUuid(uuid)); 3000 } 3001 3002 /** 3003 * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure outgoing 3004 * connection to this remote device using SDP lookup of uuid. 3005 * 3006 * <p>The communication channel will not have an authenticated link key i.e. it will be subject 3007 * to person-in-the-middle attacks. For Bluetooth 2.1 devices, the link key will be encrypted, 3008 * as encryption is mandatory. For legacy devices (pre Bluetooth 2.1 devices) the link key will 3009 * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an encrypted and 3010 * authenticated communication channel is desired. 3011 * 3012 * <p>This is designed to be used with {@link 3013 * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer Bluetooth 3014 * applications. 3015 * 3016 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. This will also 3017 * perform an SDP lookup of the given uuid to determine which channel to connect to. 3018 * 3019 * <p>The remote device will be authenticated and communication on this socket will be 3020 * encrypted. 3021 * 3022 * <p>Hint: If you are connecting to a Bluetooth serial board then try using the well-known SPP 3023 * UUID 00001101-0000-1000-8000-00805F9B34FB. However if you are connecting to an Android peer 3024 * then please generate your own unique UUID. 3025 * 3026 * @param uuid service record uuid to lookup RFCOMM channel 3027 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 3028 * @throws IOException on error, for example Bluetooth not available, or insufficient 3029 * permissions 3030 */ 3031 @RequiresLegacyBluetoothPermission createInsecureRfcommSocketToServiceRecord(UUID uuid)3032 public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException { 3033 if (!isBluetoothEnabled()) { 3034 Log.e(TAG, "Bluetooth is not enabled"); 3035 throw new IOException(); 3036 } 3037 return new BluetoothSocket( 3038 this, BluetoothSocket.TYPE_RFCOMM, false, false, -1, new ParcelUuid(uuid)); 3039 } 3040 3041 /** 3042 * Construct an insecure RFCOMM socket ready to start an outgoing connection. Call #connect on 3043 * the returned #BluetoothSocket to begin the connection. The remote device will not be 3044 * authenticated and communication on this socket will not be encrypted. 3045 * 3046 * @param port remote port 3047 * @return An RFCOMM BluetoothSocket 3048 * @throws IOException On error, for example Bluetooth not available, or insufficient 3049 * permissions. 3050 * @hide 3051 */ 3052 @UnsupportedAppUsage( 3053 publicAlternatives = 3054 "Use " + "{@link #createInsecureRfcommSocketToServiceRecord} instead.") 3055 @RequiresLegacyBluetoothAdminPermission createInsecureRfcommSocket(int port)3056 public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException { 3057 if (!isBluetoothEnabled()) { 3058 Log.e(TAG, "Bluetooth is not enabled"); 3059 throw new IOException(); 3060 } 3061 return new BluetoothSocket(this, BluetoothSocket.TYPE_RFCOMM, false, false, port, null); 3062 } 3063 3064 /** 3065 * Construct a SCO socket ready to start an outgoing connection. Call #connect on the returned 3066 * #BluetoothSocket to begin the connection. 3067 * 3068 * @return a SCO BluetoothSocket 3069 * @throws IOException on error, for example Bluetooth not available, or insufficient 3070 * permissions. 3071 * @hide 3072 */ 3073 @UnsupportedAppUsage 3074 @RequiresLegacyBluetoothAdminPermission createScoSocket()3075 public BluetoothSocket createScoSocket() throws IOException { 3076 if (!isBluetoothEnabled()) { 3077 Log.e(TAG, "Bluetooth is not enabled"); 3078 throw new IOException(); 3079 } 3080 return new BluetoothSocket(this, BluetoothSocket.TYPE_SCO, true, true, -1, null); 3081 } 3082 3083 /** 3084 * Check that a pin is valid and convert to byte array. 3085 * 3086 * <p>Bluetooth pin's are 1 to 16 bytes of UTF-8 characters. 3087 * 3088 * @param pin pin as java String 3089 * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin. 3090 * @hide 3091 */ 3092 @UnsupportedAppUsage convertPinToBytes(String pin)3093 public static byte[] convertPinToBytes(String pin) { 3094 if (pin == null) { 3095 return null; 3096 } 3097 byte[] pinBytes = pin.getBytes(StandardCharsets.UTF_8); 3098 if (pinBytes.length <= 0 || pinBytes.length > 16) { 3099 return null; 3100 } 3101 return pinBytes; 3102 } 3103 3104 /** 3105 * Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is 3106 * used to deliver results to Caller, such as connection status as well as any further GATT 3107 * client operations. The method returns a BluetoothGatt instance. You can use BluetoothGatt to 3108 * conduct GATT client operations. 3109 * 3110 * @param callback GATT callback handler that will receive asynchronous callbacks. 3111 * @param autoConnect Whether to directly connect to the remote device (false) or to 3112 * automatically connect as soon as the remote device becomes available (true). 3113 * @throws IllegalArgumentException if callback is null 3114 */ 3115 @RequiresBluetoothConnectPermission 3116 @RequiresPermission(BLUETOOTH_CONNECT) connectGatt( Context context, boolean autoConnect, BluetoothGattCallback callback)3117 public BluetoothGatt connectGatt( 3118 Context context, boolean autoConnect, BluetoothGattCallback callback) { 3119 return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO)); 3120 } 3121 3122 /** 3123 * Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is 3124 * used to deliver results to Caller, such as connection status as well as any further GATT 3125 * client operations. The method returns a BluetoothGatt instance. You can use BluetoothGatt to 3126 * conduct GATT client operations. 3127 * 3128 * @param callback GATT callback handler that will receive asynchronous callbacks. 3129 * @param autoConnect Whether to directly connect to the remote device (false) or to 3130 * automatically connect as soon as the remote device becomes available (true). 3131 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 3132 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 3133 * BluetoothDevice#TRANSPORT_LE} 3134 * @throws IllegalArgumentException if callback is null 3135 */ 3136 @RequiresBluetoothConnectPermission 3137 @RequiresPermission(BLUETOOTH_CONNECT) connectGatt( Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)3138 public BluetoothGatt connectGatt( 3139 Context context, boolean autoConnect, BluetoothGattCallback callback, int transport) { 3140 return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK)); 3141 } 3142 3143 /** 3144 * Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is 3145 * used to deliver results to Caller, such as connection status as well as any further GATT 3146 * client operations. The method returns a BluetoothGatt instance. You can use BluetoothGatt to 3147 * conduct GATT client operations. 3148 * 3149 * @param callback GATT callback handler that will receive asynchronous callbacks. 3150 * @param autoConnect Whether to directly connect to the remote device (false) or to 3151 * automatically connect as soon as the remote device becomes available (true). 3152 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 3153 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 3154 * BluetoothDevice#TRANSPORT_LE} 3155 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 3156 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link 3157 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code 3158 * autoConnect} is set to true. 3159 * @throws NullPointerException if callback is null 3160 */ 3161 @RequiresBluetoothConnectPermission 3162 @RequiresPermission(BLUETOOTH_CONNECT) connectGatt( Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy)3163 public BluetoothGatt connectGatt( 3164 Context context, 3165 boolean autoConnect, 3166 BluetoothGattCallback callback, 3167 int transport, 3168 int phy) { 3169 return connectGatt(context, autoConnect, callback, transport, phy, null); 3170 } 3171 3172 /** 3173 * Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is 3174 * used to deliver results to Caller, such as connection status as well as any further GATT 3175 * client operations. The method returns a BluetoothGatt instance. You can use BluetoothGatt to 3176 * conduct GATT client operations. 3177 * 3178 * @param callback GATT callback handler that will receive asynchronous callbacks. 3179 * @param autoConnect Whether to directly connect to the remote device (false) or to 3180 * automatically connect as soon as the remote device becomes available (true). 3181 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 3182 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 3183 * BluetoothDevice#TRANSPORT_LE} 3184 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 3185 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link 3186 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code 3187 * autoConnect} is set to true. 3188 * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on 3189 * an un-specified background thread. 3190 * @throws NullPointerException if callback is null 3191 */ 3192 @RequiresBluetoothConnectPermission 3193 @RequiresPermission(BLUETOOTH_CONNECT) connectGatt( Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler)3194 public BluetoothGatt connectGatt( 3195 Context context, 3196 boolean autoConnect, 3197 BluetoothGattCallback callback, 3198 int transport, 3199 int phy, 3200 Handler handler) { 3201 return connectGatt(context, autoConnect, callback, transport, false, phy, handler); 3202 } 3203 3204 /** 3205 * Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is 3206 * used to deliver results to Caller, such as connection status as well as any further GATT 3207 * client operations. The method returns a BluetoothGatt instance. You can use BluetoothGatt to 3208 * conduct GATT client operations. 3209 * 3210 * @param callback GATT callback handler that will receive asynchronous callbacks. 3211 * @param autoConnect Whether to directly connect to the remote device (false) or to 3212 * automatically connect as soon as the remote device becomes available (true). 3213 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 3214 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 3215 * BluetoothDevice#TRANSPORT_LE} 3216 * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client 3217 * does not hold a GATT connection. It automatically disconnects when no other GATT 3218 * connections are active for the remote device. 3219 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 3220 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link 3221 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code 3222 * autoConnect} is set to true. 3223 * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on 3224 * an un-specified background thread. 3225 * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client 3226 * operations. 3227 * @hide 3228 */ 3229 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 3230 @RequiresBluetoothConnectPermission 3231 @RequiresPermission(BLUETOOTH_CONNECT) connectGatt( Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, boolean opportunistic, int phy, Handler handler)3232 public BluetoothGatt connectGatt( 3233 Context context, 3234 boolean autoConnect, 3235 BluetoothGattCallback callback, 3236 int transport, 3237 boolean opportunistic, 3238 int phy, 3239 Handler handler) { 3240 if (callback == null) { 3241 throw new NullPointerException("callback is null"); 3242 } 3243 3244 // TODO(Bluetooth) check whether platform support BLE 3245 // Do the check here or in GattServer? 3246 IBluetoothGatt iGatt = BluetoothAdapter.getDefaultAdapter().getBluetoothGatt(); 3247 if (iGatt == null) { 3248 // BLE is not supported 3249 return null; 3250 } else if (NULL_MAC_ADDRESS.equals(mAddress)) { 3251 Log.e(TAG, "Unable to connect gatt, invalid address " + mAddress); 3252 return null; 3253 } 3254 BluetoothGatt gatt = 3255 new BluetoothGatt(iGatt, this, transport, opportunistic, phy, mAttributionSource); 3256 gatt.connect(autoConnect, callback, handler); 3257 return gatt; 3258 } 3259 3260 /** 3261 * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can 3262 * be used to start a secure outgoing connection to the remote device with the same dynamic 3263 * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only. 3264 * 3265 * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for 3266 * peer-peer Bluetooth applications. 3267 * 3268 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 3269 * 3270 * <p>Application using this API is responsible for obtaining PSM value from remote device. 3271 * 3272 * <p>The remote device will be authenticated and communication on this socket will be 3273 * encrypted. 3274 * 3275 * <p>Use this socket if an authenticated socket link is possible. Authentication refers to the 3276 * authentication of the link key to prevent person-in-the-middle type of attacks. 3277 * 3278 * @param psm dynamic PSM value from remote device 3279 * @return a CoC #BluetoothSocket ready for an outgoing connection 3280 * @throws IOException on error, for example Bluetooth not available, or insufficient 3281 * permissions 3282 */ 3283 @RequiresLegacyBluetoothPermission createL2capChannel(int psm)3284 public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException { 3285 if (!isBluetoothEnabled()) { 3286 Log.e(TAG, "createL2capChannel: Bluetooth is not enabled"); 3287 throw new IOException(); 3288 } 3289 if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm); 3290 return new BluetoothSocket(this, BluetoothSocket.TYPE_L2CAP_LE, true, true, psm, null); 3291 } 3292 3293 /** 3294 * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can 3295 * be used to start a secure outgoing connection to the remote device with the same dynamic 3296 * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only. 3297 * 3298 * <p>This is designed to be used with {@link 3299 * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications. 3300 * 3301 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 3302 * 3303 * <p>Application using this API is responsible for obtaining PSM value from remote device. 3304 * 3305 * <p>The communication channel may not have an authenticated link key, i.e. it may be subject 3306 * to person-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and 3307 * authenticated communication channel is possible. 3308 * 3309 * @param psm dynamic PSM value from remote device 3310 * @return a CoC #BluetoothSocket ready for an outgoing connection 3311 * @throws IOException on error, for example Bluetooth not available, or insufficient 3312 * permissions 3313 */ 3314 @RequiresLegacyBluetoothPermission createInsecureL2capChannel(int psm)3315 public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException { 3316 if (!isBluetoothEnabled()) { 3317 Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled"); 3318 throw new IOException(); 3319 } 3320 if (DBG) { 3321 Log.d(TAG, "createInsecureL2capChannel: psm=" + psm); 3322 } 3323 return new BluetoothSocket(this, BluetoothSocket.TYPE_L2CAP_LE, false, false, psm, null); 3324 } 3325 3326 /** 3327 * Creates a client socket to connect to a remote Bluetooth server with the specified socket 3328 * settings {@link BluetoothSocketSettings} This API is used to connect to a remote server 3329 * hosted using {@link BluetoothAdapter#listenUsingSocketSettings}. 3330 * 3331 * <ul> 3332 * <li>For `BluetoothSocket.TYPE_RFCOMM`: The RFCOMM UUID must be provided using {@link 3333 * BluetoothSocketSettings#setRfcommUuid()}. 3334 * <li>For `BluetoothSocket.TYPE_LE`: The L2cap protocol/service multiplexer (PSM) value must 3335 * be provided using {@link BluetoothSocketSettings#setL2capPsm()}. 3336 * </ul> 3337 * 3338 * <p>Application using this API is responsible for obtaining protocol/service multiplexer (psm) 3339 * value from remote device. 3340 * 3341 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 3342 * 3343 * @param settings Bluetooth socket settings {@link BluetoothSocketSettings}. 3344 * @return a {@link BluetoothSocket} ready for an outgoing connection. 3345 * @throws IllegalArgumentException if BluetoothSocket#TYPE_RFCOMM socket with no UUID is passed 3346 * as input or if BluetoothSocket#TYPE_LE with invalid PSM is passed. 3347 * @throws IOException on error, for example Bluetooth not available. 3348 */ 3349 @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API) createUsingSocketSettings( @onNull BluetoothSocketSettings settings)3350 public @NonNull BluetoothSocket createUsingSocketSettings( 3351 @NonNull BluetoothSocketSettings settings) throws IOException { 3352 if (!isBluetoothEnabled()) { 3353 Log.e(TAG, "createUsingSocketSettings: Bluetooth is not enabled"); 3354 throw new IOException(); 3355 } 3356 if (DBG) { 3357 Log.d(TAG, "createUsingSocketSettings: =" + settings.getL2capPsm()); 3358 } 3359 ParcelUuid uuid = null; 3360 int psm = settings.getL2capPsm(); 3361 if (settings.getSocketType() == BluetoothSocket.TYPE_RFCOMM) { 3362 if (settings.getRfcommUuid() == null) { 3363 throw new IllegalArgumentException("null uuid"); 3364 } 3365 uuid = new ParcelUuid(settings.getRfcommUuid()); 3366 } else if (settings.getSocketType() == BluetoothSocket.TYPE_LE) { 3367 if (psm < 128 || psm > 255) { 3368 throw new IllegalArgumentException("Invalid PSM/Channel value: " + psm); 3369 } 3370 } 3371 if (settings.getDataPath() == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) { 3372 return new BluetoothSocket( 3373 this, 3374 settings.getSocketType(), 3375 settings.isAuthenticationRequired(), 3376 settings.isEncryptionRequired(), 3377 psm, 3378 uuid); 3379 } else { 3380 return new BluetoothSocket( 3381 this, 3382 settings.getSocketType(), 3383 settings.isAuthenticationRequired(), 3384 settings.isEncryptionRequired(), 3385 psm, 3386 uuid, 3387 false, 3388 false, 3389 settings.getDataPath(), 3390 settings.getSocketName(), 3391 settings.getHubId(), 3392 settings.getEndpointId(), 3393 settings.getRequestedMaximumPacketSize()); 3394 } 3395 } 3396 3397 /** 3398 * Set a keyed metadata of this {@link BluetoothDevice} to a {@link String} value. Only bonded 3399 * devices's metadata will be persisted across Bluetooth restart. Metadata will be removed when 3400 * the device's bond state is moved to {@link #BOND_NONE}. 3401 * 3402 * @param key must be within the list of BluetoothDevice.METADATA_* 3403 * @param value a byte array data to set for key. Must be less than {@link 3404 * BluetoothAdapter#METADATA_MAX_LENGTH} characters in length 3405 * @return true on success, false on error 3406 * @hide 3407 */ 3408 @SystemApi 3409 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) setMetadata(@etadataKey int key, @NonNull byte[] value)3410 public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) { 3411 if (DBG) log("setMetadata()"); 3412 final IBluetooth service = getService(); 3413 if (service == null || !isBluetoothEnabled()) { 3414 Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata"); 3415 if (DBG) log(Log.getStackTraceString(new Throwable())); 3416 } else if (value.length > METADATA_MAX_LENGTH) { 3417 throw new IllegalArgumentException( 3418 "value length is " + value.length + ", should not over " + METADATA_MAX_LENGTH); 3419 } else { 3420 try { 3421 return service.setMetadata(this, key, value, mAttributionSource); 3422 } catch (RemoteException e) { 3423 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 3424 } 3425 } 3426 return false; 3427 } 3428 3429 /** 3430 * Get a keyed metadata for this {@link BluetoothDevice} as {@link String} 3431 * 3432 * @param key must be within the list of BluetoothDevice.METADATA_* 3433 * @return Metadata of the key as byte array, null on error or not found 3434 * @hide 3435 */ 3436 @SystemApi 3437 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) getMetadata(@etadataKey int key)3438 public @Nullable byte[] getMetadata(@MetadataKey int key) { 3439 if (DBG) log("getMetadata()"); 3440 final IBluetooth service = getService(); 3441 if (service == null || !isBluetoothEnabled()) { 3442 Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata"); 3443 if (DBG) log(Log.getStackTraceString(new Throwable())); 3444 } else { 3445 try { 3446 return service.getMetadata(this, key, mAttributionSource); 3447 } catch (RemoteException e) { 3448 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 3449 } 3450 } 3451 return null; 3452 } 3453 3454 /** 3455 * Get the maximum metadata key ID. 3456 * 3457 * @return the last supported metadata key 3458 * @hide 3459 */ getMaxMetadataKey()3460 public static @MetadataKey int getMaxMetadataKey() { 3461 return METADATA_MAX_KEY; 3462 } 3463 3464 /** @hide */ 3465 @Retention(RetentionPolicy.SOURCE) 3466 @IntDef( 3467 prefix = {"FEATURE_"}, 3468 value = { 3469 BluetoothStatusCodes.FEATURE_NOT_CONFIGURED, 3470 BluetoothStatusCodes.FEATURE_SUPPORTED, 3471 BluetoothStatusCodes.FEATURE_NOT_SUPPORTED, 3472 }) 3473 public @interface AudioPolicyRemoteSupport {} 3474 3475 /** @hide */ 3476 @Retention(RetentionPolicy.SOURCE) 3477 @IntDef( 3478 value = { 3479 BluetoothStatusCodes.SUCCESS, 3480 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, 3481 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED, 3482 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED, 3483 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, 3484 BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED, 3485 }) 3486 public @interface AudioPolicyReturnValues {} 3487 3488 /** 3489 * Returns whether the audio policy feature is supported by both the local and the remote 3490 * device. This is configured during initiating the connection between the devices through one 3491 * of the transport protocols (e.g. HFP Vendor specific protocol). So if the API is invoked 3492 * before this initial configuration is completed, it returns {@link 3493 * BluetoothStatusCodes#FEATURE_NOT_CONFIGURED} to indicate the remote device has not yet 3494 * relayed this information. After the internal configuration, the support status will be set to 3495 * either {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} or {@link 3496 * BluetoothStatusCodes#FEATURE_SUPPORTED}. The rest of the APIs related to this feature in both 3497 * {@link BluetoothDevice} and {@link BluetoothSinkAudioPolicy} should be invoked only after 3498 * getting a {@link BluetoothStatusCodes#FEATURE_SUPPORTED} response from this API. 3499 * 3500 * <p>Note that this API is intended to be used by a client device to send these requests to the 3501 * server represented by this BluetoothDevice object. 3502 * 3503 * @return if call audio policy feature is supported by both local and remote device or not 3504 * @hide 3505 */ 3506 @SystemApi 3507 @RequiresBluetoothConnectPermission 3508 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) isRequestAudioPolicyAsSinkSupported()3509 public @AudioPolicyRemoteSupport int isRequestAudioPolicyAsSinkSupported() { 3510 if (DBG) log("isRequestAudioPolicyAsSinkSupported()"); 3511 final IBluetooth service = getService(); 3512 if (service == null || !isBluetoothEnabled()) { 3513 Log.e(TAG, "BT not enabled. Cannot retrieve audio policy support status."); 3514 if (DBG) log(Log.getStackTraceString(new Throwable())); 3515 } else { 3516 try { 3517 return service.isRequestAudioPolicyAsSinkSupported(this, mAttributionSource); 3518 } catch (RemoteException e) { 3519 Log.e(TAG, "", e); 3520 } 3521 } 3522 return BluetoothStatusCodes.FEATURE_NOT_CONFIGURED; 3523 } 3524 3525 /** 3526 * Sets call audio preferences and sends them to the remote device. 3527 * 3528 * <p>Note that the caller should check if the feature is supported by invoking {@link 3529 * BluetoothDevice#isRequestAudioPolicyAsSinkSupported} first. 3530 * 3531 * <p>This API will throw an exception if the feature is not supported but still invoked. 3532 * 3533 * <p>Note that this API is intended to be used by a client device to send these requests to the 3534 * server represented by this BluetoothDevice object. 3535 * 3536 * @param policies call audio policy preferences 3537 * @return whether audio policy was requested successfully or not 3538 * @hide 3539 */ 3540 @SystemApi 3541 @RequiresBluetoothConnectPermission 3542 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) requestAudioPolicyAsSink( @onNull BluetoothSinkAudioPolicy policies)3543 public @AudioPolicyReturnValues int requestAudioPolicyAsSink( 3544 @NonNull BluetoothSinkAudioPolicy policies) { 3545 if (DBG) log("requestAudioPolicyAsSink"); 3546 final IBluetooth service = getService(); 3547 if (service == null || !isBluetoothEnabled()) { 3548 Log.e(TAG, "Bluetooth is not enabled. Cannot set Audio Policy."); 3549 if (DBG) log(Log.getStackTraceString(new Throwable())); 3550 } else { 3551 try { 3552 return service.requestAudioPolicyAsSink(this, policies, mAttributionSource); 3553 } catch (RemoteException e) { 3554 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 3555 } 3556 } 3557 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; 3558 } 3559 3560 /** 3561 * Gets the call audio preferences for the remote device. 3562 * 3563 * <p>Note that the caller should check if the feature is supported by invoking {@link 3564 * BluetoothDevice#isRequestAudioPolicyAsSinkSupported} first. 3565 * 3566 * <p>This API will throw an exception if the feature is not supported but still invoked. 3567 * 3568 * <p>This API will return null if 1. The bluetooth service is not started yet, 2. It is invoked 3569 * for a device which is not bonded, or 3. The used transport, for example, HFP Client profile 3570 * is not enabled or connected yet. 3571 * 3572 * <p>Note that this API is intended to be used by a client device to send these requests to the 3573 * server represented by this BluetoothDevice object. 3574 * 3575 * @return call audio policy as {@link BluetoothSinkAudioPolicy} object 3576 * @hide 3577 */ 3578 @SystemApi 3579 @RequiresBluetoothConnectPermission 3580 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) getRequestedAudioPolicyAsSink()3581 public @Nullable BluetoothSinkAudioPolicy getRequestedAudioPolicyAsSink() { 3582 if (DBG) log("getRequestedAudioPolicyAsSink"); 3583 final IBluetooth service = getService(); 3584 if (service == null || !isBluetoothEnabled()) { 3585 Log.e(TAG, "Bluetooth is not enabled. Cannot get Audio Policy."); 3586 if (DBG) log(Log.getStackTraceString(new Throwable())); 3587 } else { 3588 try { 3589 return service.getRequestedAudioPolicyAsSink(this, mAttributionSource); 3590 } catch (RemoteException e) { 3591 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 3592 } 3593 } 3594 return null; 3595 } 3596 3597 /** 3598 * Enable or disable audio low latency for this {@link BluetoothDevice}. 3599 * 3600 * @param allowed true if low latency is allowed, false if low latency is disallowed. 3601 * @return true if the value is successfully set, false if there is a error when setting the 3602 * value. 3603 * @hide 3604 */ 3605 @SystemApi 3606 @RequiresBluetoothConnectPermission 3607 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) setLowLatencyAudioAllowed(boolean allowed)3608 public boolean setLowLatencyAudioAllowed(boolean allowed) { 3609 if (DBG) log("setLowLatencyAudioAllowed(" + allowed + ")"); 3610 final IBluetooth service = getService(); 3611 if (service == null || !isBluetoothEnabled()) { 3612 Log.e(TAG, "Bluetooth is not enabled. Cannot allow low latency"); 3613 if (DBG) log(Log.getStackTraceString(new Throwable())); 3614 } else { 3615 try { 3616 return service.allowLowLatencyAudio(allowed, this); 3617 } catch (RemoteException e) { 3618 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 3619 } 3620 } 3621 return false; 3622 } 3623 3624 /** @hide */ 3625 @IntDef( 3626 value = { 3627 BluetoothStatusCodes.SUCCESS, 3628 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, 3629 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED, 3630 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, 3631 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED 3632 }) 3633 @Retention(RetentionPolicy.SOURCE) 3634 public @interface SetActiveAudioDevicePolicyReturnValues {} 3635 3636 /** 3637 * Active audio device policy for this device 3638 * 3639 * @hide 3640 */ 3641 @IntDef( 3642 prefix = "ACTIVE_AUDIO_DEVICE_POLICY_", 3643 value = { 3644 ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT, 3645 ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_ACTIVE_UPON_CONNECTION, 3646 ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_INACTIVE_UPON_CONNECTION 3647 }) 3648 @Retention(RetentionPolicy.SOURCE) 3649 public @interface ActiveAudioDevicePolicy {} 3650 3651 /** 3652 * Set the active audio device policy for this {@link BluetoothDevice} to indicate what {@link 3653 * ActiveAudioDevicePolicy} is applied upon device connection. 3654 * 3655 * <p>This API allows application to set the audio device profiles active policy upon 3656 * connection, only bonded device's policy will be persisted across Bluetooth restart. Policy 3657 * setting will be removed when the device's bond state is moved to {@link #BOND_NONE}. 3658 * 3659 * @param activeAudioDevicePolicy is the active audio device policy to set for this device 3660 * @return whether the policy was set properly 3661 * @throws IllegalArgumentException if this BluetoothDevice object has an invalid address 3662 * @hide 3663 */ 3664 @SystemApi 3665 @RequiresBluetoothConnectPermission 3666 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) setActiveAudioDevicePolicy( @ctiveAudioDevicePolicy int activeAudioDevicePolicy)3667 public @SetActiveAudioDevicePolicyReturnValues int setActiveAudioDevicePolicy( 3668 @ActiveAudioDevicePolicy int activeAudioDevicePolicy) { 3669 if (DBG) log("setActiveAudioDevicePolicy(" + activeAudioDevicePolicy + ")"); 3670 if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) { 3671 throw new IllegalArgumentException("device cannot have an invalid address"); 3672 } 3673 3674 final IBluetooth service = getService(); 3675 if (service == null || !isBluetoothEnabled()) { 3676 Log.e(TAG, "Bluetooth is not enabled. Cannot set active audio device policy."); 3677 if (DBG) log(Log.getStackTraceString(new Throwable())); 3678 } else { 3679 try { 3680 return service.setActiveAudioDevicePolicy( 3681 this, activeAudioDevicePolicy, mAttributionSource); 3682 } catch (RemoteException e) { 3683 Log.e(TAG, "", e); 3684 } 3685 } 3686 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; 3687 } 3688 3689 /** 3690 * Get the active audio device policy for this {@link BluetoothDevice}. 3691 * 3692 * @return active audio device policy of the device 3693 * @hide 3694 */ 3695 @SystemApi 3696 @RequiresBluetoothConnectPermission 3697 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) getActiveAudioDevicePolicy()3698 public @ActiveAudioDevicePolicy int getActiveAudioDevicePolicy() { 3699 if (DBG) log("getActiveAudioDevicePolicy"); 3700 final IBluetooth service = getService(); 3701 if (service == null || !isBluetoothEnabled()) { 3702 Log.e(TAG, "Bluetooth is not enabled. Cannot get active audio device policy."); 3703 if (DBG) log(Log.getStackTraceString(new Throwable())); 3704 } else { 3705 try { 3706 return service.getActiveAudioDevicePolicy(this, mAttributionSource); 3707 } catch (RemoteException e) { 3708 Log.e(TAG, "", e); 3709 } 3710 } 3711 return ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT; 3712 } 3713 3714 /** @hide */ 3715 @IntDef( 3716 value = { 3717 BluetoothStatusCodes.SUCCESS, 3718 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, 3719 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, 3720 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED 3721 }) 3722 @Retention(RetentionPolicy.SOURCE) 3723 public @interface SetMicrophonePreferredForCallsReturnValues {} 3724 3725 /** 3726 * Sets whether this {@link BluetoothDevice} should be the preferred microphone for calls. 3727 * 3728 * <p>This API is for Bluetooth audio devices and only sets a preference. The caller is 3729 * responsible for changing the audio input routing to reflect the preference. 3730 * 3731 * @param enabled {@code true} to set the device as the preferred microphone for calls, {@code 3732 * false} otherwise. 3733 * @return Whether the preferred microphone for calls was set properly. 3734 * @throws IllegalArgumentException if the {@link BluetoothDevice} object has an invalid 3735 * address. 3736 * @hide 3737 */ 3738 @FlaggedApi(Flags.FLAG_METADATA_API_MICROPHONE_FOR_CALL_ENABLED) 3739 @SystemApi 3740 @RequiresBluetoothConnectPermission 3741 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) setMicrophonePreferredForCalls( boolean enabled)3742 public @SetMicrophonePreferredForCallsReturnValues int setMicrophonePreferredForCalls( 3743 boolean enabled) { 3744 if (DBG) log("setMicrophonePreferredForCalls(" + enabled + ")"); 3745 if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) { 3746 throw new IllegalArgumentException("device cannot have an invalid address"); 3747 } 3748 3749 final IBluetooth service = getService(); 3750 if (service == null || !isBluetoothEnabled()) { 3751 Log.e(TAG, "Bluetooth is not enabled. Cannot set microphone for call enabled state."); 3752 if (DBG) log(Log.getStackTraceString(new Throwable())); 3753 } else { 3754 try { 3755 return service.setMicrophonePreferredForCalls(this, enabled, mAttributionSource); 3756 } catch (RemoteException e) { 3757 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 3758 } 3759 } 3760 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; 3761 } 3762 3763 /** 3764 * Gets whether this {@link BluetoothDevice} should be the preferred microphone for calls. 3765 * 3766 * <p>This API returns the configured preference for whether this device should be the preferred 3767 * microphone for calls and return {@code true} by default in case of error. It does not reflect 3768 * the current audio routing. 3769 * 3770 * @return {@code true} if the device is the preferred microphone for calls, {@code false} 3771 * otherwise. 3772 * @hide 3773 */ 3774 @FlaggedApi(Flags.FLAG_METADATA_API_MICROPHONE_FOR_CALL_ENABLED) 3775 @SystemApi 3776 @RequiresBluetoothConnectPermission 3777 @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED}) isMicrophonePreferredForCalls()3778 public boolean isMicrophonePreferredForCalls() { 3779 if (DBG) log("isMicrophoneForCallEnabled"); 3780 final IBluetooth service = getService(); 3781 if (service == null || !isBluetoothEnabled()) { 3782 Log.e(TAG, "Bluetooth is not enabled. Cannot get microphone for call enabled state."); 3783 if (DBG) log(Log.getStackTraceString(new Throwable())); 3784 } else { 3785 try { 3786 return service.isMicrophonePreferredForCalls(this, mAttributionSource); 3787 } catch (RemoteException e) { 3788 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 3789 } 3790 } 3791 return true; 3792 } 3793 3794 /** 3795 * Get the number of times {@link ACTION_KEY_MISSING} intent is thrown for this device since 3796 * last successful encrypted connection 3797 * 3798 * @return number of times {@link ACTION_KEY_MISSING} intent is thrown for this device since 3799 * last successful encrypted connection 3800 * 3801 * @hide 3802 */ 3803 @RequiresPermission(BLUETOOTH_CONNECT) getKeyMissingCount()3804 public int getKeyMissingCount() { 3805 final IBluetooth service = getService(); 3806 if (service == null || !isBluetoothEnabled()) { 3807 Log.e(TAG, "Bluetooth is not enabled. Cannot get key missing counter."); 3808 if (DBG) log(Log.getStackTraceString(new Throwable())); 3809 } else { 3810 try { 3811 return service.getKeyMissingCount(this, mAttributionSource); 3812 } catch (RemoteException e) { 3813 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); 3814 } 3815 } 3816 return -1; 3817 } 3818 log(String msg)3819 private static void log(String msg) { 3820 Log.d(TAG, msg); 3821 } 3822 3823 /** A data class for Bluetooth address and address type. */ 3824 @FlaggedApi(Flags.FLAG_IDENTITY_ADDRESS_TYPE_API) 3825 public static final class BluetoothAddress implements Parcelable { 3826 private final @Nullable String mAddress; 3827 private final @AddressType int mAddressType; 3828 BluetoothAddress(@ullable String address, @AddressType int addressType)3829 public BluetoothAddress(@Nullable String address, @AddressType int addressType) { 3830 mAddress = address; 3831 mAddressType = addressType; 3832 } 3833 3834 /** 3835 * Returns the address of this {@link BluetoothAddress}. 3836 * 3837 * <p>For example, "00:11:22:AA:BB:CC". 3838 * 3839 * @return Bluetooth address as string 3840 */ 3841 @Nullable getAddress()3842 public String getAddress() { 3843 return mAddress; 3844 } 3845 3846 /** 3847 * Returns the address type of this {@link BluetoothAddress}, one of {@link 3848 * #ADDRESS_TYPE_PUBLIC}, {@link #ADDRESS_TYPE_RANDOM}, or {@link #ADDRESS_TYPE_UNKNOWN}. 3849 * 3850 * @return Bluetooth address type 3851 */ 3852 @AddressType getAddressType()3853 public int getAddressType() { 3854 return mAddressType; 3855 } 3856 3857 @Override describeContents()3858 public int describeContents() { 3859 return 0; 3860 } 3861 3862 @Override writeToParcel(@onNull Parcel out, int flags)3863 public void writeToParcel(@NonNull Parcel out, int flags) { 3864 BluetoothUtils.writeStringToParcel(out, mAddress); 3865 out.writeInt(mAddressType); 3866 } 3867 BluetoothAddress(@onNull Parcel in)3868 private BluetoothAddress(@NonNull Parcel in) { 3869 this(in.readString(), in.readInt()); 3870 } 3871 3872 /** {@link Parcelable.Creator} interface implementation. */ 3873 public static final @NonNull Parcelable.Creator<BluetoothAddress> CREATOR = 3874 new Parcelable.Creator<BluetoothAddress>() { 3875 public @NonNull BluetoothAddress createFromParcel(Parcel in) { 3876 return new BluetoothAddress(in); 3877 } 3878 3879 public @NonNull BluetoothAddress[] newArray(int size) { 3880 return new BluetoothAddress[size]; 3881 } 3882 }; 3883 } 3884 } 3885