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