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.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SdkConstant; 24 import android.annotation.SdkConstant.SdkConstantType; 25 import android.annotation.SuppressLint; 26 import android.annotation.SystemApi; 27 import android.app.PropertyInvalidatedCache; 28 import android.bluetooth.annotations.RequiresBluetoothConnectPermission; 29 import android.bluetooth.annotations.RequiresBluetoothLocationPermission; 30 import android.bluetooth.annotations.RequiresBluetoothScanPermission; 31 import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; 32 import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; 33 import android.companion.AssociationRequest; 34 import android.compat.annotation.UnsupportedAppUsage; 35 import android.content.Attributable; 36 import android.content.AttributionSource; 37 import android.content.Context; 38 import android.os.Build; 39 import android.os.Handler; 40 import android.os.Parcel; 41 import android.os.ParcelUuid; 42 import android.os.Parcelable; 43 import android.os.Process; 44 import android.os.RemoteException; 45 import android.util.Log; 46 47 import java.io.IOException; 48 import java.io.UnsupportedEncodingException; 49 import java.lang.annotation.Retention; 50 import java.lang.annotation.RetentionPolicy; 51 import java.util.UUID; 52 53 /** 54 * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you 55 * create a connection with the respective device or query information about 56 * it, such as the name, address, class, and bonding state. 57 * 58 * <p>This class is really just a thin wrapper for a Bluetooth hardware 59 * address. Objects of this class are immutable. Operations on this class 60 * are performed on the remote Bluetooth hardware address, using the 61 * {@link BluetoothAdapter} that was used to create this {@link 62 * BluetoothDevice}. 63 * 64 * <p>To get a {@link BluetoothDevice}, use 65 * {@link BluetoothAdapter#getRemoteDevice(String) 66 * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device 67 * of a known MAC address (which you can get through device discovery with 68 * {@link BluetoothAdapter}) or get one from the set of bonded devices 69 * returned by {@link BluetoothAdapter#getBondedDevices() 70 * BluetoothAdapter.getBondedDevices()}. You can then open a 71 * {@link BluetoothSocket} for communication with the remote device, using 72 * {@link #createRfcommSocketToServiceRecord(UUID)} over Bluetooth BR/EDR or using 73 * {@link #createL2capChannel(int)} over Bluetooth LE. 74 * 75 * <div class="special reference"> 76 * <h3>Developer Guides</h3> 77 * <p> 78 * For more information about using Bluetooth, read the <a href= 79 * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer 80 * guide. 81 * </p> 82 * </div> 83 * 84 * {@see BluetoothAdapter} 85 * {@see BluetoothSocket} 86 */ 87 public final class BluetoothDevice implements Parcelable, Attributable { 88 private static final String TAG = "BluetoothDevice"; 89 private static final boolean DBG = false; 90 91 /** 92 * Connection state bitmask as returned by getConnectionState. 93 */ 94 private static final int CONNECTION_STATE_DISCONNECTED = 0; 95 private static final int CONNECTION_STATE_CONNECTED = 1; 96 private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2; 97 private static final int CONNECTION_STATE_ENCRYPTED_LE = 4; 98 99 /** 100 * Sentinel error value for this class. Guaranteed to not equal any other 101 * integer constant in this class. Provided as a convenience for functions 102 * that require a sentinel error value, for example: 103 * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 104 * BluetoothDevice.ERROR)</code> 105 */ 106 public static final int ERROR = Integer.MIN_VALUE; 107 108 /** 109 * Broadcast Action: Remote device discovered. 110 * <p>Sent when a remote device is found during discovery. 111 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 112 * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or 113 * {@link #EXTRA_RSSI} if they are available. 114 */ 115 // TODO: Change API to not broadcast RSSI if not available (incoming connection) 116 @RequiresLegacyBluetoothPermission 117 @RequiresBluetoothScanPermission 118 @RequiresBluetoothLocationPermission 119 @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) 120 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 121 public static final String ACTION_FOUND = 122 "android.bluetooth.device.action.FOUND"; 123 124 /** 125 * Broadcast Action: Bluetooth class of a remote device has changed. 126 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 127 * #EXTRA_CLASS}. 128 * {@see BluetoothClass} 129 */ 130 @RequiresLegacyBluetoothPermission 131 @RequiresBluetoothConnectPermission 132 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 133 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 134 public static final String ACTION_CLASS_CHANGED = 135 "android.bluetooth.device.action.CLASS_CHANGED"; 136 137 /** 138 * Broadcast Action: Indicates a low level (ACL) connection has been 139 * established with a remote device. 140 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 141 * <p>ACL connections are managed automatically by the Android Bluetooth 142 * stack. 143 */ 144 @RequiresLegacyBluetoothPermission 145 @RequiresBluetoothConnectPermission 146 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 147 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 148 public static final String ACTION_ACL_CONNECTED = 149 "android.bluetooth.device.action.ACL_CONNECTED"; 150 151 /** 152 * Broadcast Action: Indicates that a low level (ACL) disconnection has 153 * been requested for a remote device, and it will soon be disconnected. 154 * <p>This is useful for graceful disconnection. Applications should use 155 * this intent as a hint to immediately terminate higher level connections 156 * (RFCOMM, L2CAP, or profile connections) to the remote device. 157 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 158 */ 159 @RequiresLegacyBluetoothPermission 160 @RequiresBluetoothConnectPermission 161 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 162 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 163 public static final String ACTION_ACL_DISCONNECT_REQUESTED = 164 "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED"; 165 166 /** 167 * Broadcast Action: Indicates a low level (ACL) disconnection from a 168 * remote device. 169 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 170 * <p>ACL connections are managed automatically by the Android Bluetooth 171 * stack. 172 */ 173 @RequiresLegacyBluetoothPermission 174 @RequiresBluetoothConnectPermission 175 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 176 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 177 public static final String ACTION_ACL_DISCONNECTED = 178 "android.bluetooth.device.action.ACL_DISCONNECTED"; 179 180 /** 181 * Broadcast Action: Indicates the friendly name of a remote device has 182 * been retrieved for the first time, or changed since the last retrieval. 183 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 184 * #EXTRA_NAME}. 185 */ 186 @RequiresLegacyBluetoothPermission 187 @RequiresBluetoothConnectPermission 188 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 189 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 190 public static final String ACTION_NAME_CHANGED = 191 "android.bluetooth.device.action.NAME_CHANGED"; 192 193 /** 194 * Broadcast Action: Indicates the alias of a remote device has been 195 * changed. 196 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 197 */ 198 @SuppressLint("ActionValue") 199 @RequiresLegacyBluetoothPermission 200 @RequiresBluetoothConnectPermission 201 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 202 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 203 public static final String ACTION_ALIAS_CHANGED = 204 "android.bluetooth.device.action.ALIAS_CHANGED"; 205 206 /** 207 * Broadcast Action: Indicates a change in the bond state of a remote 208 * device. For example, if a device is bonded (paired). 209 * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link 210 * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}. 211 */ 212 // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also 213 // contain a hidden extra field EXTRA_REASON with the result code. 214 @RequiresLegacyBluetoothPermission 215 @RequiresBluetoothConnectPermission 216 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 217 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 218 public static final String ACTION_BOND_STATE_CHANGED = 219 "android.bluetooth.device.action.BOND_STATE_CHANGED"; 220 221 /** 222 * Broadcast Action: Indicates the battery level of a remote device has 223 * been retrieved for the first time, or changed since the last retrieval 224 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 225 * #EXTRA_BATTERY_LEVEL}. 226 * 227 * @hide 228 */ 229 @RequiresLegacyBluetoothPermission 230 @RequiresBluetoothConnectPermission 231 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 232 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 233 public static final String ACTION_BATTERY_LEVEL_CHANGED = 234 "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED"; 235 236 /** 237 * Used as an Integer extra field in {@link #ACTION_BATTERY_LEVEL_CHANGED} 238 * intent. It contains the most recently retrieved battery level information 239 * ranging from 0% to 100% for a remote device, {@link #BATTERY_LEVEL_UNKNOWN} 240 * when the valid is unknown or there is an error 241 * 242 * @hide 243 */ 244 public static final String EXTRA_BATTERY_LEVEL = 245 "android.bluetooth.device.extra.BATTERY_LEVEL"; 246 247 /** 248 * Used as the unknown value for {@link #EXTRA_BATTERY_LEVEL} and {@link #getBatteryLevel()} 249 * 250 * @hide 251 */ 252 public static final int BATTERY_LEVEL_UNKNOWN = -1; 253 254 /** 255 * Used as an error value for {@link #getBatteryLevel()} to represent bluetooth is off 256 * 257 * @hide 258 */ 259 public static final int BATTERY_LEVEL_BLUETOOTH_OFF = -100; 260 261 /** 262 * Used as a Parcelable {@link BluetoothDevice} extra field in every intent 263 * broadcast by this class. It contains the {@link BluetoothDevice} that 264 * the intent applies to. 265 */ 266 public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE"; 267 268 /** 269 * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link 270 * #ACTION_FOUND} intents. It contains the friendly Bluetooth name. 271 */ 272 public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME"; 273 274 /** 275 * Used as an optional short extra field in {@link #ACTION_FOUND} intents. 276 * Contains the RSSI value of the remote device as reported by the 277 * Bluetooth hardware. 278 */ 279 public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI"; 280 281 /** 282 * Used as a Parcelable {@link BluetoothClass} extra field in {@link 283 * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents. 284 */ 285 public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS"; 286 287 /** 288 * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. 289 * Contains the bond state of the remote device. 290 * <p>Possible values are: 291 * {@link #BOND_NONE}, 292 * {@link #BOND_BONDING}, 293 * {@link #BOND_BONDED}. 294 */ 295 public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE"; 296 /** 297 * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. 298 * Contains the previous bond state of the remote device. 299 * <p>Possible values are: 300 * {@link #BOND_NONE}, 301 * {@link #BOND_BONDING}, 302 * {@link #BOND_BONDED}. 303 */ 304 public static final String EXTRA_PREVIOUS_BOND_STATE = 305 "android.bluetooth.device.extra.PREVIOUS_BOND_STATE"; 306 /** 307 * Indicates the remote device is not bonded (paired). 308 * <p>There is no shared link key with the remote device, so communication 309 * (if it is allowed at all) will be unauthenticated and unencrypted. 310 */ 311 public static final int BOND_NONE = 10; 312 /** 313 * Indicates bonding (pairing) is in progress with the remote device. 314 */ 315 public static final int BOND_BONDING = 11; 316 /** 317 * Indicates the remote device is bonded (paired). 318 * <p>A shared link keys exists locally for the remote device, so 319 * communication can be authenticated and encrypted. 320 * <p><i>Being bonded (paired) with a remote device does not necessarily 321 * mean the device is currently connected. It just means that the pending 322 * procedure was completed at some earlier time, and the link key is still 323 * stored locally, ready to use on the next connection. 324 * </i> 325 */ 326 public static final int BOND_BONDED = 12; 327 328 /** 329 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} 330 * intents for unbond reason. 331 * 332 * @hide 333 */ 334 @UnsupportedAppUsage 335 public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON"; 336 337 /** 338 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} 339 * intents to indicate pairing method used. Possible values are: 340 * {@link #PAIRING_VARIANT_PIN}, 341 * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION}, 342 */ 343 public static final String EXTRA_PAIRING_VARIANT = 344 "android.bluetooth.device.extra.PAIRING_VARIANT"; 345 346 /** 347 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} 348 * intents as the value of passkey. 349 */ 350 public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY"; 351 352 /** 353 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} 354 * intents as the value of passkey. 355 * @hide 356 */ 357 public static final String EXTRA_PAIRING_INITIATOR = 358 "android.bluetooth.device.extra.PAIRING_INITIATOR"; 359 360 /** 361 * Bluetooth pairing initiator, Foreground App 362 * @hide 363 */ 364 public static final int EXTRA_PAIRING_INITIATOR_FOREGROUND = 1; 365 366 /** 367 * Bluetooth pairing initiator, Background 368 * @hide 369 */ 370 public static final int EXTRA_PAIRING_INITIATOR_BACKGROUND = 2; 371 372 /** 373 * Bluetooth device type, Unknown 374 */ 375 public static final int DEVICE_TYPE_UNKNOWN = 0; 376 377 /** 378 * Bluetooth device type, Classic - BR/EDR devices 379 */ 380 public static final int DEVICE_TYPE_CLASSIC = 1; 381 382 /** 383 * Bluetooth device type, Low Energy - LE-only 384 */ 385 public static final int DEVICE_TYPE_LE = 2; 386 387 /** 388 * Bluetooth device type, Dual Mode - BR/EDR/LE 389 */ 390 public static final int DEVICE_TYPE_DUAL = 3; 391 392 393 /** @hide */ 394 @RequiresBluetoothConnectPermission 395 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 396 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 397 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 398 public static final String ACTION_SDP_RECORD = 399 "android.bluetooth.device.action.SDP_RECORD"; 400 401 /** @hide */ 402 @IntDef(prefix = "METADATA_", value = { 403 METADATA_MANUFACTURER_NAME, 404 METADATA_MODEL_NAME, 405 METADATA_SOFTWARE_VERSION, 406 METADATA_HARDWARE_VERSION, 407 METADATA_COMPANION_APP, 408 METADATA_MAIN_ICON, 409 METADATA_IS_UNTETHERED_HEADSET, 410 METADATA_UNTETHERED_LEFT_ICON, 411 METADATA_UNTETHERED_RIGHT_ICON, 412 METADATA_UNTETHERED_CASE_ICON, 413 METADATA_UNTETHERED_LEFT_BATTERY, 414 METADATA_UNTETHERED_RIGHT_BATTERY, 415 METADATA_UNTETHERED_CASE_BATTERY, 416 METADATA_UNTETHERED_LEFT_CHARGING, 417 METADATA_UNTETHERED_RIGHT_CHARGING, 418 METADATA_UNTETHERED_CASE_CHARGING, 419 METADATA_ENHANCED_SETTINGS_UI_URI, 420 METADATA_DEVICE_TYPE, 421 METADATA_MAIN_BATTERY, 422 METADATA_MAIN_CHARGING, 423 METADATA_MAIN_LOW_BATTERY_THRESHOLD, 424 METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD, 425 METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD, 426 METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD}) 427 @Retention(RetentionPolicy.SOURCE) 428 public @interface MetadataKey{} 429 430 /** 431 * Maximum length of a metadata entry, this is to avoid exploding Bluetooth 432 * disk usage 433 * @hide 434 */ 435 @SystemApi 436 public static final int METADATA_MAX_LENGTH = 2048; 437 438 /** 439 * Manufacturer name of this Bluetooth device 440 * Data type should be {@String} as {@link Byte} array. 441 * @hide 442 */ 443 @SystemApi 444 public static final int METADATA_MANUFACTURER_NAME = 0; 445 446 /** 447 * Model name of this Bluetooth device 448 * Data type should be {@String} as {@link Byte} array. 449 * @hide 450 */ 451 @SystemApi 452 public static final int METADATA_MODEL_NAME = 1; 453 454 /** 455 * Software version of this Bluetooth device 456 * Data type should be {@String} as {@link Byte} array. 457 * @hide 458 */ 459 @SystemApi 460 public static final int METADATA_SOFTWARE_VERSION = 2; 461 462 /** 463 * Hardware version of this Bluetooth device 464 * Data type should be {@String} as {@link Byte} array. 465 * @hide 466 */ 467 @SystemApi 468 public static final int METADATA_HARDWARE_VERSION = 3; 469 470 /** 471 * Package name of the companion app, if any 472 * Data type should be {@String} as {@link Byte} array. 473 * @hide 474 */ 475 @SystemApi 476 public static final int METADATA_COMPANION_APP = 4; 477 478 /** 479 * URI to the main icon shown on the settings UI 480 * Data type should be {@link Byte} array. 481 * @hide 482 */ 483 @SystemApi 484 public static final int METADATA_MAIN_ICON = 5; 485 486 /** 487 * Whether this device is an untethered headset with left, right and case 488 * Data type should be {@String} as {@link Byte} array. 489 * @hide 490 */ 491 @SystemApi 492 public static final int METADATA_IS_UNTETHERED_HEADSET = 6; 493 494 /** 495 * URI to icon of the left headset 496 * Data type should be {@link Byte} array. 497 * @hide 498 */ 499 @SystemApi 500 public static final int METADATA_UNTETHERED_LEFT_ICON = 7; 501 502 /** 503 * URI to icon of the right headset 504 * Data type should be {@link Byte} array. 505 * @hide 506 */ 507 @SystemApi 508 public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; 509 510 /** 511 * URI to icon of the headset charging case 512 * Data type should be {@link Byte} array. 513 * @hide 514 */ 515 @SystemApi 516 public static final int METADATA_UNTETHERED_CASE_ICON = 9; 517 518 /** 519 * Battery level of left headset 520 * Data type should be {@String} 0-100 as {@link Byte} array, otherwise 521 * as invalid. 522 * @hide 523 */ 524 @SystemApi 525 public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; 526 527 /** 528 * Battery level of rigth headset 529 * Data type should be {@String} 0-100 as {@link Byte} array, otherwise 530 * as invalid. 531 * @hide 532 */ 533 @SystemApi 534 public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; 535 536 /** 537 * Battery level of the headset charging case 538 * Data type should be {@String} 0-100 as {@link Byte} array, otherwise 539 * as invalid. 540 * @hide 541 */ 542 @SystemApi 543 public static final int METADATA_UNTETHERED_CASE_BATTERY = 12; 544 545 /** 546 * Whether the left headset is charging 547 * Data type should be {@String} as {@link Byte} array. 548 * @hide 549 */ 550 @SystemApi 551 public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; 552 553 /** 554 * Whether the right headset is charging 555 * Data type should be {@String} as {@link Byte} array. 556 * @hide 557 */ 558 @SystemApi 559 public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; 560 561 /** 562 * Whether the headset charging case is charging 563 * Data type should be {@String} as {@link Byte} array. 564 * @hide 565 */ 566 @SystemApi 567 public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; 568 569 /** 570 * URI to the enhanced settings UI slice 571 * Data type should be {@String} as {@link Byte} array, null means 572 * the UI does not exist. 573 * @hide 574 */ 575 @SystemApi 576 public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; 577 578 /** 579 * Type of the Bluetooth device, must be within the list of 580 * BluetoothDevice.DEVICE_TYPE_* 581 * Data type should be {@String} as {@link Byte} array. 582 * @hide 583 */ 584 @SystemApi 585 public static final int METADATA_DEVICE_TYPE = 17; 586 587 /** 588 * Battery level of the Bluetooth device, use when the Bluetooth device 589 * does not support HFP battery indicator. 590 * Data type should be {@String} as {@link Byte} array. 591 * @hide 592 */ 593 @SystemApi 594 public static final int METADATA_MAIN_BATTERY = 18; 595 596 /** 597 * Whether the device is charging. 598 * Data type should be {@String} as {@link Byte} array. 599 * @hide 600 */ 601 @SystemApi 602 public static final int METADATA_MAIN_CHARGING = 19; 603 604 /** 605 * The battery threshold of the Bluetooth device to show low battery icon. 606 * Data type should be {@String} as {@link Byte} array. 607 * @hide 608 */ 609 @SystemApi 610 public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20; 611 612 /** 613 * The battery threshold of the left headset to show low battery icon. 614 * Data type should be {@String} as {@link Byte} array. 615 * @hide 616 */ 617 @SystemApi 618 public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21; 619 620 /** 621 * The battery threshold of the right headset to show low battery icon. 622 * Data type should be {@String} as {@link Byte} array. 623 * @hide 624 */ 625 @SystemApi 626 public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22; 627 628 /** 629 * The battery threshold of the case to show low battery icon. 630 * Data type should be {@String} as {@link Byte} array. 631 * @hide 632 */ 633 @SystemApi 634 public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23; 635 636 /** 637 * Device type which is used in METADATA_DEVICE_TYPE 638 * Indicates this Bluetooth device is a standard Bluetooth accessory or 639 * not listed in METADATA_DEVICE_TYPE_*. 640 * @hide 641 */ 642 @SystemApi 643 public static final String DEVICE_TYPE_DEFAULT = "Default"; 644 645 /** 646 * Device type which is used in METADATA_DEVICE_TYPE 647 * Indicates this Bluetooth device is a watch. 648 * @hide 649 */ 650 @SystemApi 651 public static final String DEVICE_TYPE_WATCH = "Watch"; 652 653 /** 654 * Device type which is used in METADATA_DEVICE_TYPE 655 * Indicates this Bluetooth device is an untethered headset. 656 * @hide 657 */ 658 @SystemApi 659 public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset"; 660 661 /** 662 * Broadcast Action: This intent is used to broadcast the {@link UUID} 663 * wrapped as a {@link android.os.ParcelUuid} of the remote device after it 664 * has been fetched. This intent is sent only when the UUIDs of the remote 665 * device are requested to be fetched using Service Discovery Protocol 666 * <p> Always contains the extra field {@link #EXTRA_DEVICE} 667 * <p> Always contains the extra field {@link #EXTRA_UUID} 668 */ 669 @RequiresLegacyBluetoothAdminPermission 670 @RequiresBluetoothConnectPermission 671 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 672 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 673 public static final String ACTION_UUID = 674 "android.bluetooth.device.action.UUID"; 675 676 /** @hide */ 677 @RequiresBluetoothConnectPermission 678 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 679 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 680 public static final String ACTION_MAS_INSTANCE = 681 "android.bluetooth.device.action.MAS_INSTANCE"; 682 683 /** 684 * Broadcast Action: Indicates a failure to retrieve the name of a remote 685 * device. 686 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 687 * 688 * @hide 689 */ 690 //TODO: is this actually useful? 691 @RequiresLegacyBluetoothPermission 692 @RequiresBluetoothConnectPermission 693 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 694 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 695 public static final String ACTION_NAME_FAILED = 696 "android.bluetooth.device.action.NAME_FAILED"; 697 698 /** 699 * Broadcast Action: This intent is used to broadcast PAIRING REQUEST 700 */ 701 @RequiresLegacyBluetoothAdminPermission 702 @RequiresBluetoothConnectPermission 703 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 704 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 705 public static final String ACTION_PAIRING_REQUEST = 706 "android.bluetooth.device.action.PAIRING_REQUEST"; 707 /** @hide */ 708 @RequiresBluetoothConnectPermission 709 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 710 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 711 @UnsupportedAppUsage 712 public static final String ACTION_PAIRING_CANCEL = 713 "android.bluetooth.device.action.PAIRING_CANCEL"; 714 715 /** @hide */ 716 @RequiresBluetoothConnectPermission 717 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 718 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 719 public static final String ACTION_CONNECTION_ACCESS_REQUEST = 720 "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST"; 721 722 /** @hide */ 723 @RequiresBluetoothConnectPermission 724 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 725 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 726 public static final String ACTION_CONNECTION_ACCESS_REPLY = 727 "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY"; 728 729 /** @hide */ 730 @RequiresBluetoothConnectPermission 731 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 732 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 733 public static final String ACTION_CONNECTION_ACCESS_CANCEL = 734 "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL"; 735 736 /** 737 * Intent to broadcast silence mode changed. 738 * Alway contains the extra field {@link #EXTRA_DEVICE} 739 * 740 * @hide 741 */ 742 @RequiresBluetoothConnectPermission 743 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 744 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 745 @SystemApi 746 public static final String ACTION_SILENCE_MODE_CHANGED = 747 "android.bluetooth.device.action.SILENCE_MODE_CHANGED"; 748 749 /** 750 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent. 751 * 752 * @hide 753 */ 754 public static final String EXTRA_ACCESS_REQUEST_TYPE = 755 "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE"; 756 757 /** @hide */ 758 public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1; 759 760 /** @hide */ 761 public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2; 762 763 /** @hide */ 764 public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3; 765 766 /** @hide */ 767 public static final int REQUEST_TYPE_SIM_ACCESS = 4; 768 769 /** 770 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, 771 * Contains package name to return reply intent to. 772 * 773 * @hide 774 */ 775 public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME"; 776 777 /** 778 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, 779 * Contains class name to return reply intent to. 780 * 781 * @hide 782 */ 783 public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME"; 784 785 /** 786 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent. 787 * 788 * @hide 789 */ 790 public static final String EXTRA_CONNECTION_ACCESS_RESULT = 791 "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT"; 792 793 /** @hide */ 794 public static final int CONNECTION_ACCESS_YES = 1; 795 796 /** @hide */ 797 public static final int CONNECTION_ACCESS_NO = 2; 798 799 /** 800 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents, 801 * Contains boolean to indicate if the allowed response is once-for-all so that 802 * next request will be granted without asking user again. 803 * 804 * @hide 805 */ 806 public static final String EXTRA_ALWAYS_ALLOWED = 807 "android.bluetooth.device.extra.ALWAYS_ALLOWED"; 808 809 /** 810 * A bond attempt succeeded 811 * 812 * @hide 813 */ 814 public static final int BOND_SUCCESS = 0; 815 816 /** 817 * A bond attempt failed because pins did not match, or remote device did 818 * not respond to pin request in time 819 * 820 * @hide 821 */ 822 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 823 public static final int UNBOND_REASON_AUTH_FAILED = 1; 824 825 /** 826 * A bond attempt failed because the other side explicitly rejected 827 * bonding 828 * 829 * @hide 830 */ 831 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 832 public static final int UNBOND_REASON_AUTH_REJECTED = 2; 833 834 /** 835 * A bond attempt failed because we canceled the bonding process 836 * 837 * @hide 838 */ 839 public static final int UNBOND_REASON_AUTH_CANCELED = 3; 840 841 /** 842 * A bond attempt failed because we could not contact the remote device 843 * 844 * @hide 845 */ 846 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 847 public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4; 848 849 /** 850 * A bond attempt failed because a discovery is in progress 851 * 852 * @hide 853 */ 854 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 855 public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5; 856 857 /** 858 * A bond attempt failed because of authentication timeout 859 * 860 * @hide 861 */ 862 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 863 public static final int UNBOND_REASON_AUTH_TIMEOUT = 6; 864 865 /** 866 * A bond attempt failed because of repeated attempts 867 * 868 * @hide 869 */ 870 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 871 public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7; 872 873 /** 874 * A bond attempt failed because we received an Authentication Cancel 875 * by remote end 876 * 877 * @hide 878 */ 879 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 880 public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8; 881 882 /** 883 * An existing bond was explicitly revoked 884 * 885 * @hide 886 */ 887 public static final int UNBOND_REASON_REMOVED = 9; 888 889 /** 890 * The user will be prompted to enter a pin or 891 * an app will enter a pin for user. 892 */ 893 public static final int PAIRING_VARIANT_PIN = 0; 894 895 /** 896 * The user will be prompted to enter a passkey 897 * 898 * @hide 899 */ 900 public static final int PAIRING_VARIANT_PASSKEY = 1; 901 902 /** 903 * The user will be prompted to confirm the passkey displayed on the screen or 904 * an app will confirm the passkey for the user. 905 */ 906 public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2; 907 908 /** 909 * The user will be prompted to accept or deny the incoming pairing request 910 * 911 * @hide 912 */ 913 public static final int PAIRING_VARIANT_CONSENT = 3; 914 915 /** 916 * The user will be prompted to enter the passkey displayed on remote device 917 * This is used for Bluetooth 2.1 pairing. 918 * 919 * @hide 920 */ 921 public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4; 922 923 /** 924 * The user will be prompted to enter the PIN displayed on remote device. 925 * This is used for Bluetooth 2.0 pairing. 926 * 927 * @hide 928 */ 929 public static final int PAIRING_VARIANT_DISPLAY_PIN = 5; 930 931 /** 932 * The user will be prompted to accept or deny the OOB pairing request 933 * 934 * @hide 935 */ 936 public static final int PAIRING_VARIANT_OOB_CONSENT = 6; 937 938 /** 939 * The user will be prompted to enter a 16 digit pin or 940 * an app will enter a 16 digit pin for user. 941 * 942 * @hide 943 */ 944 public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7; 945 946 /** 947 * Used as an extra field in {@link #ACTION_UUID} intents, 948 * Contains the {@link android.os.ParcelUuid}s of the remote device which 949 * is a parcelable version of {@link UUID}. 950 */ 951 public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID"; 952 953 /** @hide */ 954 public static final String EXTRA_SDP_RECORD = 955 "android.bluetooth.device.extra.SDP_RECORD"; 956 957 /** @hide */ 958 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 959 public static final String EXTRA_SDP_SEARCH_STATUS = 960 "android.bluetooth.device.extra.SDP_SEARCH_STATUS"; 961 962 /** @hide */ 963 @IntDef(prefix = "ACCESS_", value = {ACCESS_UNKNOWN, 964 ACCESS_ALLOWED, ACCESS_REJECTED}) 965 @Retention(RetentionPolicy.SOURCE) 966 public @interface AccessPermission{} 967 968 /** 969 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, 970 * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 971 * 972 * @hide 973 */ 974 @SystemApi 975 public static final int ACCESS_UNKNOWN = 0; 976 977 /** 978 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, 979 * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 980 * 981 * @hide 982 */ 983 @SystemApi 984 public static final int ACCESS_ALLOWED = 1; 985 986 /** 987 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, 988 * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 989 * 990 * @hide 991 */ 992 @SystemApi 993 public static final int ACCESS_REJECTED = 2; 994 995 /** @hide */ 996 @Retention(RetentionPolicy.SOURCE) 997 @IntDef( 998 prefix = { "TRANSPORT_" }, 999 value = { 1000 /** Allow host to automatically select a transport (dual-mode only) */ 1001 TRANSPORT_AUTO, 1002 /** Use Classic or BR/EDR transport.*/ 1003 TRANSPORT_BREDR, 1004 /** Use Low Energy transport.*/ 1005 TRANSPORT_LE, 1006 } 1007 ) 1008 public @interface Transport {} 1009 1010 /** 1011 * No preference of physical transport for GATT connections to remote dual-mode devices 1012 */ 1013 public static final int TRANSPORT_AUTO = 0; 1014 1015 /** 1016 * Prefer BR/EDR transport for GATT connections to remote dual-mode devices 1017 */ 1018 public static final int TRANSPORT_BREDR = 1; 1019 1020 /** 1021 * Prefer LE transport for GATT connections to remote dual-mode devices 1022 */ 1023 public static final int TRANSPORT_LE = 2; 1024 1025 /** 1026 * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or 1027 * connection. 1028 */ 1029 public static final int PHY_LE_1M = 1; 1030 1031 /** 1032 * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or 1033 * connection. 1034 */ 1035 public static final int PHY_LE_2M = 2; 1036 1037 /** 1038 * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning 1039 * or connection. 1040 */ 1041 public static final int PHY_LE_CODED = 3; 1042 1043 /** 1044 * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available 1045 * options in a bitmask. 1046 */ 1047 public static final int PHY_LE_1M_MASK = 1; 1048 1049 /** 1050 * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available 1051 * options in a bitmask. 1052 */ 1053 public static final int PHY_LE_2M_MASK = 2; 1054 1055 /** 1056 * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many 1057 * available options in a bitmask. 1058 */ 1059 public static final int PHY_LE_CODED_MASK = 4; 1060 1061 /** 1062 * No preferred coding when transmitting on the LE Coded PHY. 1063 */ 1064 public static final int PHY_OPTION_NO_PREFERRED = 0; 1065 1066 /** 1067 * Prefer the S=2 coding to be used when transmitting on the LE Coded PHY. 1068 */ 1069 public static final int PHY_OPTION_S2 = 1; 1070 1071 /** 1072 * Prefer the S=8 coding to be used when transmitting on the LE Coded PHY. 1073 */ 1074 public static final int PHY_OPTION_S8 = 2; 1075 1076 1077 /** @hide */ 1078 public static final String EXTRA_MAS_INSTANCE = 1079 "android.bluetooth.device.extra.MAS_INSTANCE"; 1080 1081 /** @hide */ 1082 @Retention(RetentionPolicy.SOURCE) 1083 @IntDef( 1084 prefix = { "ADDRESS_TYPE_" }, 1085 value = { 1086 /** Hardware MAC Address */ 1087 ADDRESS_TYPE_PUBLIC, 1088 /** Address is either resolvable, non-resolvable or static.*/ 1089 ADDRESS_TYPE_RANDOM, 1090 } 1091 ) 1092 public @interface AddressType {} 1093 1094 /** Hardware MAC Address of the device */ 1095 public static final int ADDRESS_TYPE_PUBLIC = 0; 1096 /** Address is either resolvable, non-resolvable or static. */ 1097 public static final int ADDRESS_TYPE_RANDOM = 1; 1098 1099 /** 1100 * Lazy initialization. Guaranteed final after first object constructed, or 1101 * getService() called. 1102 * TODO: Unify implementation of sService amongst BluetoothFoo API's 1103 */ 1104 private static volatile IBluetooth sService; 1105 1106 private final String mAddress; 1107 @AddressType private final int mAddressType; 1108 1109 private AttributionSource mAttributionSource; 1110 1111 /*package*/ 1112 @UnsupportedAppUsage getService()1113 static IBluetooth getService() { 1114 synchronized (BluetoothDevice.class) { 1115 if (sService == null) { 1116 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1117 sService = adapter.getBluetoothService(sStateChangeCallback); 1118 } 1119 } 1120 return sService; 1121 } 1122 1123 static IBluetoothManagerCallback sStateChangeCallback = new IBluetoothManagerCallback.Stub() { 1124 1125 public void onBluetoothServiceUp(IBluetooth bluetoothService) 1126 throws RemoteException { 1127 synchronized (BluetoothDevice.class) { 1128 if (sService == null) { 1129 sService = bluetoothService; 1130 } 1131 } 1132 } 1133 1134 public void onBluetoothServiceDown() 1135 throws RemoteException { 1136 synchronized (BluetoothDevice.class) { 1137 sService = null; 1138 } 1139 } 1140 1141 public void onBrEdrDown() { 1142 if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state"); 1143 } 1144 1145 public void onOobData(@Transport int transport, OobData oobData) { 1146 if (DBG) Log.d(TAG, "onOobData: got data"); 1147 } 1148 }; 1149 1150 /** 1151 * Create a new BluetoothDevice 1152 * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB", 1153 * and is validated in this constructor. 1154 * 1155 * @param address valid Bluetooth MAC address 1156 * @param attributionSource attribution for permission-protected calls 1157 * @throws RuntimeException Bluetooth is not available on this platform 1158 * @throws IllegalArgumentException address is invalid 1159 * @hide 1160 */ 1161 @UnsupportedAppUsage BluetoothDevice(String address)1162 /*package*/ BluetoothDevice(String address) { 1163 getService(); // ensures sService is initialized 1164 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 1165 throw new IllegalArgumentException(address + " is not a valid Bluetooth address"); 1166 } 1167 1168 mAddress = address; 1169 mAddressType = ADDRESS_TYPE_PUBLIC; 1170 mAttributionSource = BluetoothManager.resolveAttributionSource(null); 1171 } 1172 1173 /** {@hide} */ setAttributionSource(@onNull AttributionSource attributionSource)1174 public void setAttributionSource(@NonNull AttributionSource attributionSource) { 1175 mAttributionSource = attributionSource; 1176 } 1177 1178 /** {@hide} */ prepareToEnterProcess(@onNull AttributionSource attributionSource)1179 public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) { 1180 setAttributionSource(attributionSource); 1181 } 1182 1183 @Override equals(@ullable Object o)1184 public boolean equals(@Nullable Object o) { 1185 if (o instanceof BluetoothDevice) { 1186 return mAddress.equals(((BluetoothDevice) o).getAddress()); 1187 } 1188 return false; 1189 } 1190 1191 @Override hashCode()1192 public int hashCode() { 1193 return mAddress.hashCode(); 1194 } 1195 1196 /** 1197 * Returns a string representation of this BluetoothDevice. 1198 * <p>Currently this is the Bluetooth hardware address, for example 1199 * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress} 1200 * if you explicitly require the Bluetooth hardware address in case the 1201 * {@link #toString} representation changes in the future. 1202 * 1203 * @return string representation of this BluetoothDevice 1204 */ 1205 @Override toString()1206 public String toString() { 1207 return mAddress; 1208 } 1209 1210 @Override describeContents()1211 public int describeContents() { 1212 return 0; 1213 } 1214 1215 public static final @android.annotation.NonNull Parcelable.Creator<BluetoothDevice> CREATOR = 1216 new Parcelable.Creator<BluetoothDevice>() { 1217 public BluetoothDevice createFromParcel(Parcel in) { 1218 return new BluetoothDevice(in.readString()); 1219 } 1220 1221 public BluetoothDevice[] newArray(int size) { 1222 return new BluetoothDevice[size]; 1223 } 1224 }; 1225 1226 @Override writeToParcel(Parcel out, int flags)1227 public void writeToParcel(Parcel out, int flags) { 1228 out.writeString(mAddress); 1229 } 1230 1231 /** 1232 * Returns the hardware address of this BluetoothDevice. 1233 * <p> For example, "00:11:22:AA:BB:CC". 1234 * 1235 * @return Bluetooth hardware address as string 1236 */ getAddress()1237 public String getAddress() { 1238 if (DBG) Log.d(TAG, "mAddress: " + mAddress); 1239 return mAddress; 1240 } 1241 1242 /** 1243 * Returns the anonymized hardware address of this BluetoothDevice. The first three octets 1244 * will be suppressed for anonymization. 1245 * <p> For example, "XX:XX:XX:AA:BB:CC". 1246 * 1247 * @return Anonymized bluetooth hardware address as string 1248 * @hide 1249 */ getAnonymizedAddress()1250 public String getAnonymizedAddress() { 1251 return "XX:XX:XX" + getAddress().substring(8); 1252 } 1253 1254 /** 1255 * Get the friendly Bluetooth name of the remote device. 1256 * 1257 * <p>The local adapter will automatically retrieve remote names when 1258 * performing a device scan, and will cache them. This method just returns 1259 * the name for this device from the cache. 1260 * 1261 * @return the Bluetooth name, or null if there was a problem. 1262 */ 1263 @RequiresLegacyBluetoothPermission 1264 @RequiresBluetoothConnectPermission 1265 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getName()1266 public String getName() { 1267 final IBluetooth service = sService; 1268 if (service == null) { 1269 Log.e(TAG, "BT not enabled. Cannot get Remote Device name"); 1270 return null; 1271 } 1272 try { 1273 String name = service.getRemoteName(this, mAttributionSource); 1274 if (name != null) { 1275 // remove whitespace characters from the name 1276 return name 1277 .replace('\t', ' ') 1278 .replace('\n', ' ') 1279 .replace('\r', ' '); 1280 } 1281 return null; 1282 } catch (RemoteException e) { 1283 Log.e(TAG, "", e); 1284 } 1285 return null; 1286 } 1287 1288 /** 1289 * Get the Bluetooth device type of the remote device. 1290 * 1291 * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} {@link 1292 * #DEVICE_TYPE_DUAL}. {@link #DEVICE_TYPE_UNKNOWN} if it's not available 1293 */ 1294 @RequiresLegacyBluetoothPermission 1295 @RequiresBluetoothConnectPermission 1296 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getType()1297 public int getType() { 1298 final IBluetooth service = sService; 1299 if (service == null) { 1300 Log.e(TAG, "BT not enabled. Cannot get Remote Device type"); 1301 return DEVICE_TYPE_UNKNOWN; 1302 } 1303 try { 1304 return service.getRemoteType(this, mAttributionSource); 1305 } catch (RemoteException e) { 1306 Log.e(TAG, "", e); 1307 } 1308 return DEVICE_TYPE_UNKNOWN; 1309 } 1310 1311 /** 1312 * Get the locally modifiable name (alias) of the remote Bluetooth device. 1313 * 1314 * @return the Bluetooth alias, the friendly device name if no alias, or 1315 * null if there was a problem 1316 */ 1317 @Nullable 1318 @RequiresLegacyBluetoothPermission 1319 @RequiresBluetoothConnectPermission 1320 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getAlias()1321 public String getAlias() { 1322 final IBluetooth service = sService; 1323 if (service == null) { 1324 Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias"); 1325 return null; 1326 } 1327 try { 1328 String alias = service.getRemoteAliasWithAttribution(this, mAttributionSource); 1329 if (alias == null) { 1330 return getName(); 1331 } 1332 return alias; 1333 } catch (RemoteException e) { 1334 Log.e(TAG, "", e); 1335 } 1336 return null; 1337 } 1338 1339 /** @hide */ 1340 @Retention(RetentionPolicy.SOURCE) 1341 @IntDef(value = { 1342 BluetoothStatusCodes.SUCCESS, 1343 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, 1344 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED, 1345 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, 1346 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED 1347 }) 1348 public @interface SetAliasReturnValues{} 1349 1350 /** 1351 * Sets the locally modifiable name (alias) of the remote Bluetooth device. This method 1352 * overwrites the previously stored alias. The new alias is saved in local 1353 * storage so that the change is preserved over power cycles. 1354 * 1355 * <p>This method requires the calling app to be associated with Companion Device Manager (see 1356 * {@link android.companion.CompanionDeviceManager#associate(AssociationRequest, 1357 * android.companion.CompanionDeviceManager.Callback, Handler)}) and have the 1358 * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission. Alternatively, if the 1359 * caller has the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission, they can 1360 * bypass the Companion Device Manager association requirement as well as other permission 1361 * requirements. 1362 * 1363 * @param alias is the new locally modifiable name for the remote Bluetooth device which must 1364 * be the empty string. If null, we clear the alias. 1365 * @return whether the alias was successfully changed 1366 * @throws IllegalArgumentException if the alias is the empty string 1367 */ 1368 @RequiresLegacyBluetoothPermission 1369 @RequiresBluetoothConnectPermission 1370 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) setAlias(@ullable String alias)1371 public @SetAliasReturnValues int setAlias(@Nullable String alias) { 1372 if (alias != null && alias.isEmpty()) { 1373 throw new IllegalArgumentException("alias cannot be the empty string"); 1374 } 1375 final IBluetooth service = sService; 1376 if (service == null) { 1377 Log.e(TAG, "BT not enabled. Cannot set Remote Device name"); 1378 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; 1379 } 1380 try { 1381 return service.setRemoteAlias(this, alias, mAttributionSource); 1382 } catch (RemoteException e) { 1383 Log.e(TAG, "", e); 1384 throw e.rethrowFromSystemServer(); 1385 } 1386 } 1387 1388 /** 1389 * Get the most recent identified battery level of this Bluetooth device 1390 * 1391 * @return Battery level in percents from 0 to 100, {@link #BATTERY_LEVEL_BLUETOOTH_OFF} if 1392 * Bluetooth is disabled or {@link #BATTERY_LEVEL_UNKNOWN} if device is disconnected, or does 1393 * not have any battery reporting service, or return value is invalid 1394 * @hide 1395 */ 1396 @UnsupportedAppUsage 1397 @RequiresLegacyBluetoothPermission 1398 @RequiresBluetoothConnectPermission 1399 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getBatteryLevel()1400 public int getBatteryLevel() { 1401 final IBluetooth service = sService; 1402 if (service == null) { 1403 Log.e(TAG, "Bluetooth disabled. Cannot get remote device battery level"); 1404 return BATTERY_LEVEL_BLUETOOTH_OFF; 1405 } 1406 try { 1407 return service.getBatteryLevel(this, mAttributionSource); 1408 } catch (RemoteException e) { 1409 Log.e(TAG, "", e); 1410 } 1411 return BATTERY_LEVEL_UNKNOWN; 1412 } 1413 1414 /** 1415 * Start the bonding (pairing) process with the remote device. 1416 * <p>This is an asynchronous call, it will return immediately. Register 1417 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 1418 * the bonding process completes, and its result. 1419 * <p>Android system services will handle the necessary user interactions 1420 * to confirm and complete the bonding process. 1421 * 1422 * @return false on immediate error, true if bonding will begin 1423 */ 1424 @RequiresLegacyBluetoothAdminPermission 1425 @RequiresBluetoothConnectPermission 1426 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) createBond()1427 public boolean createBond() { 1428 return createBond(TRANSPORT_AUTO); 1429 } 1430 1431 /** 1432 * Start the bonding (pairing) process with the remote device using the 1433 * specified transport. 1434 * 1435 * <p>This is an asynchronous call, it will return immediately. Register 1436 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 1437 * the bonding process completes, and its result. 1438 * <p>Android system services will handle the necessary user interactions 1439 * to confirm and complete the bonding process. 1440 * 1441 * @param transport The transport to use for the pairing procedure. 1442 * @return false on immediate error, true if bonding will begin 1443 * @throws IllegalArgumentException if an invalid transport was specified 1444 * @hide 1445 */ 1446 @UnsupportedAppUsage 1447 @RequiresLegacyBluetoothAdminPermission 1448 @RequiresBluetoothConnectPermission 1449 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) createBond(int transport)1450 public boolean createBond(int transport) { 1451 return createBondInternal(transport, null, null); 1452 } 1453 1454 /** 1455 * Start the bonding (pairing) process with the remote device using the 1456 * Out Of Band mechanism. 1457 * 1458 * <p>This is an asynchronous call, it will return immediately. Register 1459 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 1460 * the bonding process completes, and its result. 1461 * 1462 * <p>Android system services will handle the necessary user interactions 1463 * to confirm and complete the bonding process. 1464 * 1465 * <p>There are two possible versions of OOB Data. This data can come in as 1466 * P192 or P256. This is a reference to the cryptography used to generate the key. 1467 * The caller may pass one or both. If both types of data are passed, then the 1468 * P256 data will be preferred, and thus used. 1469 * 1470 * @param transport - Transport to use 1471 * @param remoteP192Data - Out Of Band data (P192) or null 1472 * @param remoteP256Data - Out Of Band data (P256) or null 1473 * @return false on immediate error, true if bonding will begin 1474 * @hide 1475 */ 1476 @SystemApi 1477 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) createBondOutOfBand(int transport, @Nullable OobData remoteP192Data, @Nullable OobData remoteP256Data)1478 public boolean createBondOutOfBand(int transport, @Nullable OobData remoteP192Data, 1479 @Nullable OobData remoteP256Data) { 1480 if (remoteP192Data == null && remoteP256Data == null) { 1481 throw new IllegalArgumentException( 1482 "One or both arguments for the OOB data types are required to not be null." 1483 + " Please use createBond() instead if you do not have OOB data to pass."); 1484 } 1485 return createBondInternal(transport, remoteP192Data, remoteP256Data); 1486 } 1487 1488 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) createBondInternal(int transport, @Nullable OobData remoteP192Data, @Nullable OobData remoteP256Data)1489 private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data, 1490 @Nullable OobData remoteP256Data) { 1491 final IBluetooth service = sService; 1492 if (service == null) { 1493 Log.w(TAG, "BT not enabled, createBondOutOfBand failed"); 1494 return false; 1495 } 1496 try { 1497 return service.createBond( 1498 this, transport, remoteP192Data, remoteP256Data, mAttributionSource); 1499 } catch (RemoteException e) { 1500 Log.e(TAG, "", e); 1501 } 1502 return false; 1503 } 1504 1505 /** 1506 * Gets whether bonding was initiated locally 1507 * 1508 * @return true if bonding is initiated locally, false otherwise 1509 * 1510 * @hide 1511 */ 1512 @UnsupportedAppUsage 1513 @RequiresLegacyBluetoothPermission 1514 @RequiresBluetoothConnectPermission 1515 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) isBondingInitiatedLocally()1516 public boolean isBondingInitiatedLocally() { 1517 final IBluetooth service = sService; 1518 if (service == null) { 1519 Log.w(TAG, "BT not enabled, isBondingInitiatedLocally failed"); 1520 return false; 1521 } 1522 try { 1523 return service.isBondingInitiatedLocally(this, mAttributionSource); 1524 } catch (RemoteException e) { 1525 Log.e(TAG, "", e); 1526 } 1527 return false; 1528 } 1529 1530 /** 1531 * Cancel an in-progress bonding request started with {@link #createBond}. 1532 * 1533 * @return true on success, false on error 1534 * @hide 1535 */ 1536 @SystemApi 1537 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) cancelBondProcess()1538 public boolean cancelBondProcess() { 1539 final IBluetooth service = sService; 1540 if (service == null) { 1541 Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond"); 1542 return false; 1543 } 1544 try { 1545 Log.i(TAG, "cancelBondProcess() for device " + getAddress() 1546 + " called by pid: " + Process.myPid() 1547 + " tid: " + Process.myTid()); 1548 return service.cancelBondProcess(this, mAttributionSource); 1549 } catch (RemoteException e) { 1550 Log.e(TAG, "", e); 1551 } 1552 return false; 1553 } 1554 1555 /** 1556 * Remove bond (pairing) with the remote device. 1557 * <p>Delete the link key associated with the remote device, and 1558 * immediately terminate connections to that device that require 1559 * authentication and encryption. 1560 * 1561 * @return true on success, false on error 1562 * @hide 1563 */ 1564 @SystemApi 1565 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) removeBond()1566 public boolean removeBond() { 1567 final IBluetooth service = sService; 1568 if (service == null) { 1569 Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond"); 1570 return false; 1571 } 1572 try { 1573 Log.i(TAG, "removeBond() for device " + getAddress() 1574 + " called by pid: " + Process.myPid() 1575 + " tid: " + Process.myTid()); 1576 return service.removeBond(this, mAttributionSource); 1577 } catch (RemoteException e) { 1578 Log.e(TAG, "", e); 1579 } 1580 return false; 1581 } 1582 1583 private static final String BLUETOOTH_BONDING_CACHE_PROPERTY = 1584 "cache_key.bluetooth.get_bond_state"; 1585 private final PropertyInvalidatedCache<BluetoothDevice, Integer> mBluetoothBondCache = 1586 new PropertyInvalidatedCache<BluetoothDevice, Integer>( 1587 8, BLUETOOTH_BONDING_CACHE_PROPERTY) { 1588 @Override 1589 @SuppressLint("AndroidFrameworkRequiresPermission") 1590 protected Integer recompute(BluetoothDevice query) { 1591 try { 1592 return sService.getBondState(query, mAttributionSource); 1593 } catch (RemoteException e) { 1594 throw e.rethrowAsRuntimeException(); 1595 } 1596 } 1597 }; 1598 1599 /** @hide */ disableBluetoothGetBondStateCache()1600 public void disableBluetoothGetBondStateCache() { 1601 mBluetoothBondCache.disableLocal(); 1602 } 1603 1604 /** @hide */ invalidateBluetoothGetBondStateCache()1605 public static void invalidateBluetoothGetBondStateCache() { 1606 PropertyInvalidatedCache.invalidateCache(BLUETOOTH_BONDING_CACHE_PROPERTY); 1607 } 1608 1609 /** 1610 * Get the bond state of the remote device. 1611 * <p>Possible values for the bond state are: 1612 * {@link #BOND_NONE}, 1613 * {@link #BOND_BONDING}, 1614 * {@link #BOND_BONDED}. 1615 * 1616 * @return the bond state 1617 */ 1618 @RequiresLegacyBluetoothPermission 1619 @RequiresBluetoothConnectPermission 1620 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 1621 @SuppressLint("AndroidFrameworkRequiresPermission") getBondState()1622 public int getBondState() { 1623 final IBluetooth service = sService; 1624 if (service == null) { 1625 Log.e(TAG, "BT not enabled. Cannot get bond state"); 1626 return BOND_NONE; 1627 } 1628 try { 1629 return mBluetoothBondCache.query(this); 1630 } catch (RuntimeException e) { 1631 if (e.getCause() instanceof RemoteException) { 1632 Log.e(TAG, "", e); 1633 } else { 1634 throw e; 1635 } 1636 } 1637 return BOND_NONE; 1638 } 1639 1640 /** 1641 * Checks whether this bluetooth device is associated with CDM and meets the criteria to skip 1642 * the bluetooth pairing dialog because it has been already consented by the CDM prompt. 1643 * 1644 * @return true if we can bond without the dialog, false otherwise 1645 * 1646 * @hide 1647 */ 1648 @SystemApi 1649 @RequiresPermission(allOf = { 1650 android.Manifest.permission.BLUETOOTH_CONNECT, 1651 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 1652 }) canBondWithoutDialog()1653 public boolean canBondWithoutDialog() { 1654 final IBluetooth service = sService; 1655 if (service == null) { 1656 Log.e(TAG, "BT not enabled. Cannot check if we can skip pairing dialog"); 1657 return false; 1658 } 1659 try { 1660 if (DBG) Log.d(TAG, "canBondWithoutDialog, device: " + this); 1661 return service.canBondWithoutDialog(this, mAttributionSource); 1662 } catch (RemoteException e) { 1663 Log.e(TAG, "", e); 1664 } 1665 return false; 1666 } 1667 1668 /** 1669 * Returns whether there is an open connection to this device. 1670 * 1671 * @return True if there is at least one open connection to this device. 1672 * @hide 1673 */ 1674 @SystemApi 1675 @RequiresLegacyBluetoothPermission 1676 @RequiresBluetoothConnectPermission 1677 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) isConnected()1678 public boolean isConnected() { 1679 final IBluetooth service = sService; 1680 if (service == null) { 1681 // BT is not enabled, we cannot be connected. 1682 return false; 1683 } 1684 try { 1685 return service.getConnectionStateWithAttribution(this, mAttributionSource) 1686 != CONNECTION_STATE_DISCONNECTED; 1687 } catch (RemoteException e) { 1688 Log.e(TAG, "", e); 1689 return false; 1690 } 1691 } 1692 1693 /** 1694 * Returns whether there is an open connection to this device 1695 * that has been encrypted. 1696 * 1697 * @return True if there is at least one encrypted connection to this device. 1698 * @hide 1699 */ 1700 @SystemApi 1701 @RequiresLegacyBluetoothPermission 1702 @RequiresBluetoothConnectPermission 1703 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) isEncrypted()1704 public boolean isEncrypted() { 1705 final IBluetooth service = sService; 1706 if (service == null) { 1707 // BT is not enabled, we cannot be connected. 1708 return false; 1709 } 1710 try { 1711 return service.getConnectionStateWithAttribution(this, mAttributionSource) 1712 > CONNECTION_STATE_CONNECTED; 1713 } catch (RemoteException e) { 1714 Log.e(TAG, "", e); 1715 return false; 1716 } 1717 } 1718 1719 /** 1720 * Get the Bluetooth class of the remote device. 1721 * 1722 * @return Bluetooth class object, or null on error 1723 */ 1724 @RequiresLegacyBluetoothPermission 1725 @RequiresBluetoothConnectPermission 1726 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getBluetoothClass()1727 public BluetoothClass getBluetoothClass() { 1728 final IBluetooth service = sService; 1729 if (service == null) { 1730 Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class"); 1731 return null; 1732 } 1733 try { 1734 int classInt = service.getRemoteClass(this, mAttributionSource); 1735 if (classInt == BluetoothClass.ERROR) return null; 1736 return new BluetoothClass(classInt); 1737 } catch (RemoteException e) { 1738 Log.e(TAG, "", e); 1739 } 1740 return null; 1741 } 1742 1743 /** 1744 * Returns the supported features (UUIDs) of the remote device. 1745 * 1746 * <p>This method does not start a service discovery procedure to retrieve the UUIDs 1747 * from the remote device. Instead, the local cached copy of the service 1748 * UUIDs are returned. 1749 * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired. 1750 * 1751 * @return the supported features (UUIDs) of the remote device, or null on error 1752 */ 1753 @RequiresLegacyBluetoothPermission 1754 @RequiresBluetoothConnectPermission 1755 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getUuids()1756 public ParcelUuid[] getUuids() { 1757 final IBluetooth service = sService; 1758 if (service == null || !isBluetoothEnabled()) { 1759 Log.e(TAG, "BT not enabled. Cannot get remote device Uuids"); 1760 return null; 1761 } 1762 try { 1763 return service.getRemoteUuids(this, mAttributionSource); 1764 } catch (RemoteException e) { 1765 Log.e(TAG, "", e); 1766 } 1767 return null; 1768 } 1769 1770 /** 1771 * Perform a service discovery on the remote device to get the UUIDs supported. 1772 * 1773 * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent, 1774 * with the UUIDs supported by the remote end. If there is an error 1775 * in getting the SDP records or if the process takes a long time, or the device is bonding and 1776 * we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the UUIDs that is 1777 * currently present in the cache. Clients should use the {@link #getUuids} to get UUIDs 1778 * if service discovery is not to be performed. If there is an ongoing bonding process, 1779 * service discovery or device inquiry, the request will be queued. 1780 * 1781 * @return False if the check fails, True if the process of initiating an ACL connection 1782 * to the remote device was started or cached UUIDs will be broadcast. 1783 */ 1784 @RequiresLegacyBluetoothPermission 1785 @RequiresBluetoothConnectPermission 1786 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) fetchUuidsWithSdp()1787 public boolean fetchUuidsWithSdp() { 1788 final IBluetooth service = sService; 1789 if (service == null || !isBluetoothEnabled()) { 1790 Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp"); 1791 return false; 1792 } 1793 try { 1794 return service.fetchRemoteUuidsWithAttribution(this, mAttributionSource); 1795 } catch (RemoteException e) { 1796 Log.e(TAG, "", e); 1797 } 1798 return false; 1799 } 1800 1801 /** 1802 * Perform a service discovery on the remote device to get the SDP records associated 1803 * with the specified UUID. 1804 * 1805 * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent, 1806 * with the SDP records found on the remote end. If there is an error 1807 * in getting the SDP records or if the process takes a long time, 1808 * {@link #ACTION_SDP_RECORD} intent is sent with an status value in 1809 * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0. 1810 * Detailed status error codes can be found by members of the Bluetooth package in 1811 * the AbstractionLayer class. 1812 * <p>The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}. 1813 * The object type will match one of the SdpXxxRecord types, depending on the UUID searched 1814 * for. 1815 * 1816 * @return False if the check fails, True if the process 1817 * of initiating an ACL connection to the remote device 1818 * was started. 1819 */ 1820 /** @hide */ 1821 @RequiresLegacyBluetoothPermission 1822 @RequiresBluetoothConnectPermission 1823 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) sdpSearch(ParcelUuid uuid)1824 public boolean sdpSearch(ParcelUuid uuid) { 1825 final IBluetooth service = sService; 1826 if (service == null) { 1827 Log.e(TAG, "BT not enabled. Cannot query remote device sdp records"); 1828 return false; 1829 } 1830 try { 1831 return service.sdpSearch(this, uuid, mAttributionSource); 1832 } catch (RemoteException e) { 1833 Log.e(TAG, "", e); 1834 } 1835 return false; 1836 } 1837 1838 /** 1839 * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} 1840 * 1841 * @return true pin has been set false for error 1842 */ 1843 @RequiresLegacyBluetoothAdminPermission 1844 @RequiresBluetoothConnectPermission 1845 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) setPin(byte[] pin)1846 public boolean setPin(byte[] pin) { 1847 final IBluetooth service = sService; 1848 if (service == null) { 1849 Log.e(TAG, "BT not enabled. Cannot set Remote Device pin"); 1850 return false; 1851 } 1852 try { 1853 return service.setPin(this, true, pin.length, pin, mAttributionSource); 1854 } catch (RemoteException e) { 1855 Log.e(TAG, "", e); 1856 } 1857 return false; 1858 } 1859 1860 /** 1861 * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} 1862 * 1863 * @return true pin has been set false for error 1864 * @hide 1865 */ 1866 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1867 @RequiresLegacyBluetoothAdminPermission 1868 @RequiresBluetoothConnectPermission 1869 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) setPin(@onNull String pin)1870 public boolean setPin(@NonNull String pin) { 1871 byte[] pinBytes = convertPinToBytes(pin); 1872 if (pinBytes == null) { 1873 return false; 1874 } 1875 return setPin(pinBytes); 1876 } 1877 1878 /** 1879 * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing. 1880 * 1881 * @return true confirmation has been sent out false for error 1882 */ 1883 @RequiresPermission(allOf = { 1884 android.Manifest.permission.BLUETOOTH_CONNECT, 1885 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 1886 }) setPairingConfirmation(boolean confirm)1887 public boolean setPairingConfirmation(boolean confirm) { 1888 final IBluetooth service = sService; 1889 if (service == null) { 1890 Log.e(TAG, "BT not enabled. Cannot set pairing confirmation"); 1891 return false; 1892 } 1893 try { 1894 return service.setPairingConfirmation(this, confirm, mAttributionSource); 1895 } catch (RemoteException e) { 1896 Log.e(TAG, "", e); 1897 } 1898 return false; 1899 } 1900 1901 /** 1902 * Cancels pairing to this device 1903 * 1904 * @return true if pairing cancelled successfully, false otherwise 1905 * 1906 * @hide 1907 */ 1908 @UnsupportedAppUsage 1909 @RequiresLegacyBluetoothAdminPermission 1910 @RequiresBluetoothConnectPermission 1911 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) cancelPairing()1912 public boolean cancelPairing() { 1913 final IBluetooth service = sService; 1914 if (service == null) { 1915 Log.e(TAG, "BT not enabled. Cannot cancel pairing"); 1916 return false; 1917 } 1918 try { 1919 return service.cancelBondProcess(this, mAttributionSource); 1920 } catch (RemoteException e) { 1921 Log.e(TAG, "", e); 1922 } 1923 return false; 1924 } 1925 isBluetoothEnabled()1926 boolean isBluetoothEnabled() { 1927 boolean ret = false; 1928 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1929 if (adapter != null && adapter.isEnabled()) { 1930 ret = true; 1931 } 1932 return ret; 1933 } 1934 1935 /** 1936 * Gets whether the phonebook access is allowed for this bluetooth device 1937 * 1938 * @return Whether the phonebook access is allowed to this device. Can be {@link 1939 * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. 1940 * @hide 1941 */ 1942 @UnsupportedAppUsage 1943 @RequiresLegacyBluetoothPermission 1944 @RequiresBluetoothConnectPermission 1945 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getPhonebookAccessPermission()1946 public @AccessPermission int getPhonebookAccessPermission() { 1947 final IBluetooth service = sService; 1948 if (service == null) { 1949 return ACCESS_UNKNOWN; 1950 } 1951 try { 1952 return service.getPhonebookAccessPermission(this, mAttributionSource); 1953 } catch (RemoteException e) { 1954 Log.e(TAG, "", e); 1955 } 1956 return ACCESS_UNKNOWN; 1957 } 1958 1959 /** 1960 * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not 1961 * be routed to the {@link BluetoothDevice} if set to {@code true}. 1962 * 1963 * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice} 1964 * is an active device (for A2DP or HFP), the active device for that profile 1965 * will be set to null. 1966 * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP 1967 * active device is null, the {@link BluetoothDevice} will be set as the 1968 * active device for that profile. 1969 * If the {@link BluetoothDevice} is disconnected, it exits silence mode. 1970 * If the {@link BluetoothDevice} is set as the active device for A2DP or 1971 * HFP, while silence mode is enabled, then the device will exit silence mode. 1972 * If the {@link BluetoothDevice} is in silence mode, AVRCP position change 1973 * event and HFP AG indicators will be disabled. 1974 * If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot 1975 * enter silence mode. 1976 * 1977 * @param silence true to enter silence mode, false to exit 1978 * @return true on success, false on error. 1979 * @throws IllegalStateException if Bluetooth is not turned ON. 1980 * @hide 1981 */ 1982 @SystemApi 1983 @RequiresPermission(allOf = { 1984 android.Manifest.permission.BLUETOOTH_CONNECT, 1985 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 1986 }) setSilenceMode(boolean silence)1987 public boolean setSilenceMode(boolean silence) { 1988 final IBluetooth service = sService; 1989 if (service == null) { 1990 throw new IllegalStateException("Bluetooth is not turned ON"); 1991 } 1992 try { 1993 return service.setSilenceMode(this, silence, mAttributionSource); 1994 } catch (RemoteException e) { 1995 Log.e(TAG, "setSilenceMode fail", e); 1996 return false; 1997 } 1998 } 1999 2000 /** 2001 * Check whether the {@link BluetoothDevice} is in silence mode 2002 * 2003 * @return true on device in silence mode, otherwise false. 2004 * @throws IllegalStateException if Bluetooth is not turned ON. 2005 * @hide 2006 */ 2007 @SystemApi 2008 @RequiresPermission(allOf = { 2009 android.Manifest.permission.BLUETOOTH_CONNECT, 2010 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2011 }) isInSilenceMode()2012 public boolean isInSilenceMode() { 2013 final IBluetooth service = sService; 2014 if (service == null) { 2015 throw new IllegalStateException("Bluetooth is not turned ON"); 2016 } 2017 try { 2018 return service.getSilenceMode(this, mAttributionSource); 2019 } catch (RemoteException e) { 2020 Log.e(TAG, "isInSilenceMode fail", e); 2021 return false; 2022 } 2023 } 2024 2025 /** 2026 * Sets whether the phonebook access is allowed to this device. 2027 * 2028 * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link 2029 * #ACCESS_REJECTED}. 2030 * @return Whether the value has been successfully set. 2031 * @hide 2032 */ 2033 @SystemApi 2034 @RequiresPermission(allOf = { 2035 android.Manifest.permission.BLUETOOTH_CONNECT, 2036 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2037 }) setPhonebookAccessPermission(@ccessPermission int value)2038 public boolean setPhonebookAccessPermission(@AccessPermission int value) { 2039 final IBluetooth service = sService; 2040 if (service == null) { 2041 return false; 2042 } 2043 try { 2044 return service.setPhonebookAccessPermission(this, value, mAttributionSource); 2045 } catch (RemoteException e) { 2046 Log.e(TAG, "", e); 2047 } 2048 return false; 2049 } 2050 2051 /** 2052 * Gets whether message access is allowed to this bluetooth device 2053 * 2054 * @return Whether the message access is allowed to this device. 2055 * @hide 2056 */ 2057 @UnsupportedAppUsage 2058 @RequiresLegacyBluetoothPermission 2059 @RequiresBluetoothConnectPermission 2060 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getMessageAccessPermission()2061 public @AccessPermission int getMessageAccessPermission() { 2062 final IBluetooth service = sService; 2063 if (service == null) { 2064 return ACCESS_UNKNOWN; 2065 } 2066 try { 2067 return service.getMessageAccessPermission(this, mAttributionSource); 2068 } catch (RemoteException e) { 2069 Log.e(TAG, "", e); 2070 } 2071 return ACCESS_UNKNOWN; 2072 } 2073 2074 /** 2075 * Sets whether the message access is allowed to this device. 2076 * 2077 * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded, 2078 * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if 2079 * the permission is not being granted. 2080 * @return Whether the value has been successfully set. 2081 * @hide 2082 */ 2083 @SystemApi 2084 @RequiresPermission(allOf = { 2085 android.Manifest.permission.BLUETOOTH_CONNECT, 2086 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2087 }) setMessageAccessPermission(@ccessPermission int value)2088 public boolean setMessageAccessPermission(@AccessPermission int value) { 2089 // Validates param value is one of the accepted constants 2090 if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) { 2091 throw new IllegalArgumentException(value + "is not a valid AccessPermission value"); 2092 } 2093 final IBluetooth service = sService; 2094 if (service == null) { 2095 return false; 2096 } 2097 try { 2098 return service.setMessageAccessPermission(this, value, mAttributionSource); 2099 } catch (RemoteException e) { 2100 Log.e(TAG, "", e); 2101 } 2102 return false; 2103 } 2104 2105 /** 2106 * Gets whether sim access is allowed for this bluetooth device 2107 * 2108 * @return Whether the Sim access is allowed to this device. 2109 * @hide 2110 */ 2111 @SystemApi 2112 @RequiresLegacyBluetoothPermission 2113 @RequiresBluetoothConnectPermission 2114 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getSimAccessPermission()2115 public @AccessPermission int getSimAccessPermission() { 2116 final IBluetooth service = sService; 2117 if (service == null) { 2118 return ACCESS_UNKNOWN; 2119 } 2120 try { 2121 return service.getSimAccessPermission(this, mAttributionSource); 2122 } catch (RemoteException e) { 2123 Log.e(TAG, "", e); 2124 } 2125 return ACCESS_UNKNOWN; 2126 } 2127 2128 /** 2129 * Sets whether the Sim access is allowed to this device. 2130 * 2131 * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded, 2132 * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if 2133 * the permission is not being granted. 2134 * @return Whether the value has been successfully set. 2135 * @hide 2136 */ 2137 @SystemApi 2138 @RequiresPermission(allOf = { 2139 android.Manifest.permission.BLUETOOTH_CONNECT, 2140 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2141 }) setSimAccessPermission(int value)2142 public boolean setSimAccessPermission(int value) { 2143 final IBluetooth service = sService; 2144 if (service == null) { 2145 return false; 2146 } 2147 try { 2148 return service.setSimAccessPermission(this, value, mAttributionSource); 2149 } catch (RemoteException e) { 2150 Log.e(TAG, "", e); 2151 } 2152 return false; 2153 } 2154 2155 /** 2156 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 2157 * outgoing connection to this remote device on given channel. 2158 * <p>The remote device will be authenticated and communication on this 2159 * socket will be encrypted. 2160 * <p> Use this socket only if an authenticated socket link is possible. 2161 * Authentication refers to the authentication of the link key to 2162 * prevent person-in-the-middle type of attacks. 2163 * For example, for Bluetooth 2.1 devices, if any of the devices does not 2164 * have an input and output capability or just has the ability to 2165 * display a numeric key, a secure socket connection is not possible. 2166 * In such a case, use {@link createInsecureRfcommSocket}. 2167 * For more details, refer to the Security Model section 5.2 (vol 3) of 2168 * Bluetooth Core Specification version 2.1 + EDR. 2169 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 2170 * connection. 2171 * <p>Valid RFCOMM channels are in range 1 to 30. 2172 * 2173 * @param channel RFCOMM channel to connect to 2174 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2175 * @throws IOException on error, for example Bluetooth not available, or insufficient 2176 * permissions 2177 * @hide 2178 */ 2179 @UnsupportedAppUsage 2180 @RequiresLegacyBluetoothPermission 2181 @RequiresBluetoothConnectPermission 2182 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2183 @SuppressLint("AndroidFrameworkRequiresPermission") createRfcommSocket(int channel)2184 public BluetoothSocket createRfcommSocket(int channel) throws IOException { 2185 if (!isBluetoothEnabled()) { 2186 Log.e(TAG, "Bluetooth is not enabled"); 2187 throw new IOException(); 2188 } 2189 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel, 2190 null); 2191 } 2192 2193 /** 2194 * Create an L2cap {@link BluetoothSocket} ready to start a secure 2195 * outgoing connection to this remote device on given channel. 2196 * <p>The remote device will be authenticated and communication on this 2197 * socket will be encrypted. 2198 * <p> Use this socket only if an authenticated socket link is possible. 2199 * Authentication refers to the authentication of the link key to 2200 * prevent person-in-the-middle type of attacks. 2201 * For example, for Bluetooth 2.1 devices, if any of the devices does not 2202 * have an input and output capability or just has the ability to 2203 * display a numeric key, a secure socket connection is not possible. 2204 * In such a case, use {@link createInsecureRfcommSocket}. 2205 * For more details, refer to the Security Model section 5.2 (vol 3) of 2206 * Bluetooth Core Specification version 2.1 + EDR. 2207 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 2208 * connection. 2209 * <p>Valid L2CAP PSM channels are in range 1 to 2^16. 2210 * 2211 * @param channel L2cap PSM/channel to connect to 2212 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2213 * @throws IOException on error, for example Bluetooth not available, or insufficient 2214 * permissions 2215 * @hide 2216 */ 2217 @RequiresLegacyBluetoothPermission 2218 @RequiresBluetoothConnectPermission 2219 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2220 @SuppressLint("AndroidFrameworkRequiresPermission") createL2capSocket(int channel)2221 public BluetoothSocket createL2capSocket(int channel) throws IOException { 2222 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel, 2223 null); 2224 } 2225 2226 /** 2227 * Create an L2cap {@link BluetoothSocket} ready to start an insecure 2228 * outgoing connection to this remote device on given channel. 2229 * <p>The remote device will be not authenticated and communication on this 2230 * socket will not be encrypted. 2231 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 2232 * connection. 2233 * <p>Valid L2CAP PSM channels are in range 1 to 2^16. 2234 * 2235 * @param channel L2cap PSM/channel to connect to 2236 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2237 * @throws IOException on error, for example Bluetooth not available, or insufficient 2238 * permissions 2239 * @hide 2240 */ 2241 @RequiresLegacyBluetoothPermission 2242 @RequiresBluetoothConnectPermission 2243 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2244 @SuppressLint("AndroidFrameworkRequiresPermission") createInsecureL2capSocket(int channel)2245 public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException { 2246 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel, 2247 null); 2248 } 2249 2250 /** 2251 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 2252 * outgoing connection to this remote device using SDP lookup of uuid. 2253 * <p>This is designed to be used with {@link 2254 * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer 2255 * Bluetooth applications. 2256 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 2257 * connection. This will also perform an SDP lookup of the given uuid to 2258 * determine which channel to connect to. 2259 * <p>The remote device will be authenticated and communication on this 2260 * socket will be encrypted. 2261 * <p> Use this socket only if an authenticated socket link is possible. 2262 * Authentication refers to the authentication of the link key to 2263 * prevent person-in-the-middle type of attacks. 2264 * For example, for Bluetooth 2.1 devices, if any of the devices does not 2265 * have an input and output capability or just has the ability to 2266 * display a numeric key, a secure socket connection is not possible. 2267 * In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}. 2268 * For more details, refer to the Security Model section 5.2 (vol 3) of 2269 * Bluetooth Core Specification version 2.1 + EDR. 2270 * <p>Hint: If you are connecting to a Bluetooth serial board then try 2271 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 2272 * However if you are connecting to an Android peer then please generate 2273 * your own unique UUID. 2274 * 2275 * @param uuid service record uuid to lookup RFCOMM channel 2276 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2277 * @throws IOException on error, for example Bluetooth not available, or insufficient 2278 * permissions 2279 */ 2280 @RequiresLegacyBluetoothPermission 2281 @RequiresBluetoothConnectPermission 2282 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2283 @SuppressLint("AndroidFrameworkRequiresPermission") createRfcommSocketToServiceRecord(UUID uuid)2284 public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException { 2285 if (!isBluetoothEnabled()) { 2286 Log.e(TAG, "Bluetooth is not enabled"); 2287 throw new IOException(); 2288 } 2289 2290 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1, 2291 new ParcelUuid(uuid)); 2292 } 2293 2294 /** 2295 * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure 2296 * outgoing connection to this remote device using SDP lookup of uuid. 2297 * <p> The communication channel will not have an authenticated link key 2298 * i.e it will be subject to person-in-the-middle attacks. For Bluetooth 2.1 2299 * devices, the link key will be encrypted, as encryption is mandatory. 2300 * For legacy devices (pre Bluetooth 2.1 devices) the link key will 2301 * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an 2302 * encrypted and authenticated communication channel is desired. 2303 * <p>This is designed to be used with {@link 2304 * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer 2305 * Bluetooth applications. 2306 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 2307 * connection. This will also perform an SDP lookup of the given uuid to 2308 * determine which channel to connect to. 2309 * <p>The remote device will be authenticated and communication on this 2310 * socket will be encrypted. 2311 * <p>Hint: If you are connecting to a Bluetooth serial board then try 2312 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 2313 * However if you are connecting to an Android peer then please generate 2314 * your own unique UUID. 2315 * 2316 * @param uuid service record uuid to lookup RFCOMM channel 2317 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2318 * @throws IOException on error, for example Bluetooth not available, or insufficient 2319 * permissions 2320 */ 2321 @RequiresLegacyBluetoothPermission 2322 @RequiresBluetoothConnectPermission 2323 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2324 @SuppressLint("AndroidFrameworkRequiresPermission") createInsecureRfcommSocketToServiceRecord(UUID uuid)2325 public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException { 2326 if (!isBluetoothEnabled()) { 2327 Log.e(TAG, "Bluetooth is not enabled"); 2328 throw new IOException(); 2329 } 2330 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1, 2331 new ParcelUuid(uuid)); 2332 } 2333 2334 /** 2335 * Construct an insecure RFCOMM socket ready to start an outgoing 2336 * connection. 2337 * Call #connect on the returned #BluetoothSocket to begin the connection. 2338 * The remote device will not be authenticated and communication on this 2339 * socket will not be encrypted. 2340 * 2341 * @param port remote port 2342 * @return An RFCOMM BluetoothSocket 2343 * @throws IOException On error, for example Bluetooth not available, or insufficient 2344 * permissions. 2345 * @hide 2346 */ 2347 @UnsupportedAppUsage(publicAlternatives = "Use " 2348 + "{@link #createInsecureRfcommSocketToServiceRecord} instead.") 2349 @RequiresLegacyBluetoothAdminPermission 2350 @RequiresBluetoothConnectPermission 2351 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2352 @SuppressLint("AndroidFrameworkRequiresPermission") createInsecureRfcommSocket(int port)2353 public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException { 2354 if (!isBluetoothEnabled()) { 2355 Log.e(TAG, "Bluetooth is not enabled"); 2356 throw new IOException(); 2357 } 2358 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port, 2359 null); 2360 } 2361 2362 /** 2363 * Construct a SCO socket ready to start an outgoing connection. 2364 * Call #connect on the returned #BluetoothSocket to begin the connection. 2365 * 2366 * @return a SCO BluetoothSocket 2367 * @throws IOException on error, for example Bluetooth not available, or insufficient 2368 * permissions. 2369 * @hide 2370 */ 2371 @UnsupportedAppUsage 2372 @RequiresLegacyBluetoothAdminPermission 2373 @RequiresBluetoothConnectPermission 2374 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2375 @SuppressLint("AndroidFrameworkRequiresPermission") createScoSocket()2376 public BluetoothSocket createScoSocket() throws IOException { 2377 if (!isBluetoothEnabled()) { 2378 Log.e(TAG, "Bluetooth is not enabled"); 2379 throw new IOException(); 2380 } 2381 return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null); 2382 } 2383 2384 /** 2385 * Check that a pin is valid and convert to byte array. 2386 * 2387 * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters. 2388 * 2389 * @param pin pin as java String 2390 * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin. 2391 * @hide 2392 */ 2393 @UnsupportedAppUsage convertPinToBytes(String pin)2394 public static byte[] convertPinToBytes(String pin) { 2395 if (pin == null) { 2396 return null; 2397 } 2398 byte[] pinBytes; 2399 try { 2400 pinBytes = pin.getBytes("UTF-8"); 2401 } catch (UnsupportedEncodingException uee) { 2402 Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen 2403 return null; 2404 } 2405 if (pinBytes.length <= 0 || pinBytes.length > 16) { 2406 return null; 2407 } 2408 return pinBytes; 2409 } 2410 2411 /** 2412 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 2413 * The callback is used to deliver results to Caller, such as connection status as well 2414 * as any further GATT client operations. 2415 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 2416 * GATT client operations. 2417 * 2418 * @param callback GATT callback handler that will receive asynchronous callbacks. 2419 * @param autoConnect Whether to directly connect to the remote device (false) or to 2420 * automatically connect as soon as the remote device becomes available (true). 2421 * @throws IllegalArgumentException if callback is null 2422 */ 2423 @RequiresBluetoothConnectPermission 2424 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)2425 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 2426 BluetoothGattCallback callback) { 2427 return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO)); 2428 } 2429 2430 /** 2431 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 2432 * The callback is used to deliver results to Caller, such as connection status as well 2433 * as any further GATT client operations. 2434 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 2435 * GATT client operations. 2436 * 2437 * @param callback GATT callback handler that will receive asynchronous callbacks. 2438 * @param autoConnect Whether to directly connect to the remote device (false) or to 2439 * automatically connect as soon as the remote device becomes available (true). 2440 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 2441 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 2442 * BluetoothDevice#TRANSPORT_LE} 2443 * @throws IllegalArgumentException if callback is null 2444 */ 2445 @RequiresBluetoothConnectPermission 2446 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)2447 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 2448 BluetoothGattCallback callback, int transport) { 2449 return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK)); 2450 } 2451 2452 /** 2453 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 2454 * The callback is used to deliver results to Caller, such as connection status as well 2455 * as any further GATT client operations. 2456 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 2457 * GATT client operations. 2458 * 2459 * @param callback GATT callback handler that will receive asynchronous callbacks. 2460 * @param autoConnect Whether to directly connect to the remote device (false) or to 2461 * automatically connect as soon as the remote device becomes available (true). 2462 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 2463 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 2464 * BluetoothDevice#TRANSPORT_LE} 2465 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 2466 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link 2467 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} 2468 * is set to true. 2469 * @throws NullPointerException if callback is null 2470 */ 2471 @RequiresBluetoothConnectPermission 2472 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy)2473 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 2474 BluetoothGattCallback callback, int transport, int phy) { 2475 return connectGatt(context, autoConnect, callback, transport, phy, null); 2476 } 2477 2478 /** 2479 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 2480 * The callback is used to deliver results to Caller, such as connection status as well 2481 * as any further GATT client operations. 2482 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 2483 * GATT client operations. 2484 * 2485 * @param callback GATT callback handler that will receive asynchronous callbacks. 2486 * @param autoConnect Whether to directly connect to the remote device (false) or to 2487 * automatically connect as soon as the remote device becomes available (true). 2488 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 2489 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 2490 * BluetoothDevice#TRANSPORT_LE} 2491 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 2492 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link 2493 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} 2494 * is set to true. 2495 * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on 2496 * an un-specified background thread. 2497 * @throws NullPointerException if callback is null 2498 */ 2499 @RequiresBluetoothConnectPermission 2500 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler)2501 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 2502 BluetoothGattCallback callback, int transport, int phy, 2503 Handler handler) { 2504 return connectGatt(context, autoConnect, callback, transport, false, phy, handler); 2505 } 2506 2507 /** 2508 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 2509 * The callback is used to deliver results to Caller, such as connection status as well 2510 * as any further GATT client operations. 2511 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 2512 * GATT client operations. 2513 * 2514 * @param callback GATT callback handler that will receive asynchronous callbacks. 2515 * @param autoConnect Whether to directly connect to the remote device (false) or to 2516 * automatically connect as soon as the remote device becomes available (true). 2517 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 2518 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 2519 * BluetoothDevice#TRANSPORT_LE} 2520 * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client 2521 * does not hold a GATT connection. It automatically disconnects when no other GATT connections 2522 * are active for the remote device. 2523 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 2524 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link 2525 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} 2526 * is set to true. 2527 * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on 2528 * an un-specified background thread. 2529 * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client 2530 * operations. 2531 * @hide 2532 */ 2533 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2534 @RequiresBluetoothConnectPermission 2535 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, boolean opportunistic, int phy, Handler handler)2536 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 2537 BluetoothGattCallback callback, int transport, 2538 boolean opportunistic, int phy, Handler handler) { 2539 if (callback == null) { 2540 throw new NullPointerException("callback is null"); 2541 } 2542 2543 // TODO(Bluetooth) check whether platform support BLE 2544 // Do the check here or in GattServer? 2545 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 2546 IBluetoothManager managerService = adapter.getBluetoothManager(); 2547 try { 2548 IBluetoothGatt iGatt = managerService.getBluetoothGatt(); 2549 if (iGatt == null) { 2550 // BLE is not supported 2551 return null; 2552 } 2553 BluetoothGatt gatt = new BluetoothGatt( 2554 iGatt, this, transport, opportunistic, phy, mAttributionSource); 2555 gatt.connect(autoConnect, callback, handler); 2556 return gatt; 2557 } catch (RemoteException e) { 2558 Log.e(TAG, "", e); 2559 } 2560 return null; 2561 } 2562 2563 /** 2564 * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can 2565 * be used to start a secure outgoing connection to the remote device with the same dynamic 2566 * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only. 2567 * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for 2568 * peer-peer Bluetooth applications. 2569 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 2570 * <p>Application using this API is responsible for obtaining PSM value from remote device. 2571 * <p>The remote device will be authenticated and communication on this socket will be 2572 * encrypted. 2573 * <p> Use this socket if an authenticated socket link is possible. Authentication refers 2574 * to the authentication of the link key to prevent person-in-the-middle type of attacks. 2575 * 2576 * @param psm dynamic PSM value from remote device 2577 * @return a CoC #BluetoothSocket ready for an outgoing connection 2578 * @throws IOException on error, for example Bluetooth not available, or insufficient 2579 * permissions 2580 */ 2581 @RequiresLegacyBluetoothPermission 2582 @RequiresBluetoothConnectPermission 2583 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2584 @SuppressLint("AndroidFrameworkRequiresPermission") createL2capChannel(int psm)2585 public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException { 2586 if (!isBluetoothEnabled()) { 2587 Log.e(TAG, "createL2capChannel: Bluetooth is not enabled"); 2588 throw new IOException(); 2589 } 2590 if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm); 2591 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm, 2592 null); 2593 } 2594 2595 /** 2596 * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can 2597 * be used to start a secure outgoing connection to the remote device with the same dynamic 2598 * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only. 2599 * <p>This is designed to be used with {@link 2600 * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications. 2601 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 2602 * <p>Application using this API is responsible for obtaining PSM value from remote device. 2603 * <p> The communication channel may not have an authenticated link key, i.e. it may be subject 2604 * to person-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and 2605 * authenticated communication channel is possible. 2606 * 2607 * @param psm dynamic PSM value from remote device 2608 * @return a CoC #BluetoothSocket ready for an outgoing connection 2609 * @throws IOException on error, for example Bluetooth not available, or insufficient 2610 * permissions 2611 */ 2612 @RequiresLegacyBluetoothPermission 2613 @RequiresBluetoothConnectPermission 2614 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2615 @SuppressLint("AndroidFrameworkRequiresPermission") createInsecureL2capChannel(int psm)2616 public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException { 2617 if (!isBluetoothEnabled()) { 2618 Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled"); 2619 throw new IOException(); 2620 } 2621 if (DBG) { 2622 Log.d(TAG, "createInsecureL2capChannel: psm=" + psm); 2623 } 2624 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm, 2625 null); 2626 } 2627 2628 /** 2629 * Set a keyed metadata of this {@link BluetoothDevice} to a 2630 * {@link String} value. 2631 * Only bonded devices's metadata will be persisted across Bluetooth 2632 * restart. 2633 * Metadata will be removed when the device's bond state is moved to 2634 * {@link #BOND_NONE}. 2635 * 2636 * @param key must be within the list of BluetoothDevice.METADATA_* 2637 * @param value a byte array data to set for key. Must be less than 2638 * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length 2639 * @return true on success, false on error 2640 * @hide 2641 */ 2642 @SystemApi 2643 @RequiresPermission(allOf = { 2644 android.Manifest.permission.BLUETOOTH_CONNECT, 2645 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2646 }) setMetadata(@etadataKey int key, @NonNull byte[] value)2647 public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) { 2648 final IBluetooth service = sService; 2649 if (service == null) { 2650 Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata"); 2651 return false; 2652 } 2653 if (value.length > METADATA_MAX_LENGTH) { 2654 throw new IllegalArgumentException("value length is " + value.length 2655 + ", should not over " + METADATA_MAX_LENGTH); 2656 } 2657 try { 2658 return service.setMetadata(this, key, value, mAttributionSource); 2659 } catch (RemoteException e) { 2660 Log.e(TAG, "setMetadata fail", e); 2661 return false; 2662 } 2663 } 2664 2665 /** 2666 * Get a keyed metadata for this {@link BluetoothDevice} as {@link String} 2667 * 2668 * @param key must be within the list of BluetoothDevice.METADATA_* 2669 * @return Metadata of the key as byte array, null on error or not found 2670 * @hide 2671 */ 2672 @SystemApi 2673 @Nullable 2674 @RequiresPermission(allOf = { 2675 android.Manifest.permission.BLUETOOTH_CONNECT, 2676 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2677 }) getMetadata(@etadataKey int key)2678 public byte[] getMetadata(@MetadataKey int key) { 2679 final IBluetooth service = sService; 2680 if (service == null) { 2681 Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata"); 2682 return null; 2683 } 2684 try { 2685 return service.getMetadata(this, key, mAttributionSource); 2686 } catch (RemoteException e) { 2687 Log.e(TAG, "getMetadata fail", e); 2688 return null; 2689 } 2690 } 2691 2692 /** 2693 * Get the maxinum metadata key ID. 2694 * 2695 * @return the last supported metadata key 2696 * @hide 2697 */ getMaxMetadataKey()2698 public static @MetadataKey int getMaxMetadataKey() { 2699 return METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD; 2700 } 2701 } 2702