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 .replace('\t', ' ') 1334 .replace('\n', ' ') 1335 .replace('\r', ' '); 1336 } catch (RemoteException e) { 1337 Log.e(TAG, "", e); 1338 } 1339 return null; 1340 } 1341 1342 /** @hide */ 1343 @Retention(RetentionPolicy.SOURCE) 1344 @IntDef(value = { 1345 BluetoothStatusCodes.SUCCESS, 1346 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, 1347 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED, 1348 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, 1349 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED 1350 }) 1351 public @interface SetAliasReturnValues{} 1352 1353 /** 1354 * Sets the locally modifiable name (alias) of the remote Bluetooth device. This method 1355 * overwrites the previously stored alias. The new alias is saved in local 1356 * storage so that the change is preserved over power cycles. 1357 * 1358 * <p>This method requires the calling app to be associated with Companion Device Manager (see 1359 * {@link android.companion.CompanionDeviceManager#associate(AssociationRequest, 1360 * android.companion.CompanionDeviceManager.Callback, Handler)}) and have the 1361 * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission. Alternatively, if the 1362 * caller has the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission, they can 1363 * bypass the Companion Device Manager association requirement as well as other permission 1364 * requirements. 1365 * 1366 * @param alias is the new locally modifiable name for the remote Bluetooth device which must 1367 * be the empty string. If null, we clear the alias. 1368 * @return whether the alias was successfully changed 1369 * @throws IllegalArgumentException if the alias is the empty string 1370 */ 1371 @RequiresLegacyBluetoothPermission 1372 @RequiresBluetoothConnectPermission 1373 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) setAlias(@ullable String alias)1374 public @SetAliasReturnValues int setAlias(@Nullable String alias) { 1375 if (alias != null && alias.isEmpty()) { 1376 throw new IllegalArgumentException("alias cannot be the empty string"); 1377 } 1378 final IBluetooth service = sService; 1379 if (service == null) { 1380 Log.e(TAG, "BT not enabled. Cannot set Remote Device name"); 1381 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; 1382 } 1383 try { 1384 return service.setRemoteAlias(this, alias, mAttributionSource); 1385 } catch (RemoteException e) { 1386 Log.e(TAG, "", e); 1387 throw e.rethrowFromSystemServer(); 1388 } 1389 } 1390 1391 /** 1392 * Get the most recent identified battery level of this Bluetooth device 1393 * 1394 * @return Battery level in percents from 0 to 100, {@link #BATTERY_LEVEL_BLUETOOTH_OFF} if 1395 * Bluetooth is disabled or {@link #BATTERY_LEVEL_UNKNOWN} if device is disconnected, or does 1396 * not have any battery reporting service, or return value is invalid 1397 * @hide 1398 */ 1399 @UnsupportedAppUsage 1400 @RequiresLegacyBluetoothPermission 1401 @RequiresBluetoothConnectPermission 1402 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getBatteryLevel()1403 public int getBatteryLevel() { 1404 final IBluetooth service = sService; 1405 if (service == null) { 1406 Log.e(TAG, "Bluetooth disabled. Cannot get remote device battery level"); 1407 return BATTERY_LEVEL_BLUETOOTH_OFF; 1408 } 1409 try { 1410 return service.getBatteryLevel(this, mAttributionSource); 1411 } catch (RemoteException e) { 1412 Log.e(TAG, "", e); 1413 } 1414 return BATTERY_LEVEL_UNKNOWN; 1415 } 1416 1417 /** 1418 * Start the bonding (pairing) process with the remote device. 1419 * <p>This is an asynchronous call, it will return immediately. Register 1420 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 1421 * the bonding process completes, and its result. 1422 * <p>Android system services will handle the necessary user interactions 1423 * to confirm and complete the bonding process. 1424 * 1425 * @return false on immediate error, true if bonding will begin 1426 */ 1427 @RequiresLegacyBluetoothAdminPermission 1428 @RequiresBluetoothConnectPermission 1429 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) createBond()1430 public boolean createBond() { 1431 return createBond(TRANSPORT_AUTO); 1432 } 1433 1434 /** 1435 * Start the bonding (pairing) process with the remote device using the 1436 * specified transport. 1437 * 1438 * <p>This is an asynchronous call, it will return immediately. Register 1439 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 1440 * the bonding process completes, and its result. 1441 * <p>Android system services will handle the necessary user interactions 1442 * to confirm and complete the bonding process. 1443 * 1444 * @param transport The transport to use for the pairing procedure. 1445 * @return false on immediate error, true if bonding will begin 1446 * @throws IllegalArgumentException if an invalid transport was specified 1447 * @hide 1448 */ 1449 @UnsupportedAppUsage 1450 @RequiresLegacyBluetoothAdminPermission 1451 @RequiresBluetoothConnectPermission 1452 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) createBond(int transport)1453 public boolean createBond(int transport) { 1454 return createBondInternal(transport, null, null); 1455 } 1456 1457 /** 1458 * Start the bonding (pairing) process with the remote device using the 1459 * Out Of Band mechanism. 1460 * 1461 * <p>This is an asynchronous call, it will return immediately. Register 1462 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 1463 * the bonding process completes, and its result. 1464 * 1465 * <p>Android system services will handle the necessary user interactions 1466 * to confirm and complete the bonding process. 1467 * 1468 * <p>There are two possible versions of OOB Data. This data can come in as 1469 * P192 or P256. This is a reference to the cryptography used to generate the key. 1470 * The caller may pass one or both. If both types of data are passed, then the 1471 * P256 data will be preferred, and thus used. 1472 * 1473 * @param transport - Transport to use 1474 * @param remoteP192Data - Out Of Band data (P192) or null 1475 * @param remoteP256Data - Out Of Band data (P256) or null 1476 * @return false on immediate error, true if bonding will begin 1477 * @hide 1478 */ 1479 @SystemApi 1480 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) createBondOutOfBand(int transport, @Nullable OobData remoteP192Data, @Nullable OobData remoteP256Data)1481 public boolean createBondOutOfBand(int transport, @Nullable OobData remoteP192Data, 1482 @Nullable OobData remoteP256Data) { 1483 if (remoteP192Data == null && remoteP256Data == null) { 1484 throw new IllegalArgumentException( 1485 "One or both arguments for the OOB data types are required to not be null." 1486 + " Please use createBond() instead if you do not have OOB data to pass."); 1487 } 1488 return createBondInternal(transport, remoteP192Data, remoteP256Data); 1489 } 1490 1491 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) createBondInternal(int transport, @Nullable OobData remoteP192Data, @Nullable OobData remoteP256Data)1492 private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data, 1493 @Nullable OobData remoteP256Data) { 1494 final IBluetooth service = sService; 1495 if (service == null) { 1496 Log.w(TAG, "BT not enabled, createBondOutOfBand failed"); 1497 return false; 1498 } 1499 try { 1500 return service.createBond( 1501 this, transport, remoteP192Data, remoteP256Data, mAttributionSource); 1502 } catch (RemoteException e) { 1503 Log.e(TAG, "", e); 1504 } 1505 return false; 1506 } 1507 1508 /** 1509 * Gets whether bonding was initiated locally 1510 * 1511 * @return true if bonding is initiated locally, false otherwise 1512 * 1513 * @hide 1514 */ 1515 @UnsupportedAppUsage 1516 @RequiresLegacyBluetoothPermission 1517 @RequiresBluetoothConnectPermission 1518 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) isBondingInitiatedLocally()1519 public boolean isBondingInitiatedLocally() { 1520 final IBluetooth service = sService; 1521 if (service == null) { 1522 Log.w(TAG, "BT not enabled, isBondingInitiatedLocally failed"); 1523 return false; 1524 } 1525 try { 1526 return service.isBondingInitiatedLocally(this, mAttributionSource); 1527 } catch (RemoteException e) { 1528 Log.e(TAG, "", e); 1529 } 1530 return false; 1531 } 1532 1533 /** 1534 * Cancel an in-progress bonding request started with {@link #createBond}. 1535 * 1536 * @return true on success, false on error 1537 * @hide 1538 */ 1539 @SystemApi 1540 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) cancelBondProcess()1541 public boolean cancelBondProcess() { 1542 final IBluetooth service = sService; 1543 if (service == null) { 1544 Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond"); 1545 return false; 1546 } 1547 try { 1548 Log.i(TAG, "cancelBondProcess() for device " + getAddress() 1549 + " called by pid: " + Process.myPid() 1550 + " tid: " + Process.myTid()); 1551 return service.cancelBondProcess(this, mAttributionSource); 1552 } catch (RemoteException e) { 1553 Log.e(TAG, "", e); 1554 } 1555 return false; 1556 } 1557 1558 /** 1559 * Remove bond (pairing) with the remote device. 1560 * <p>Delete the link key associated with the remote device, and 1561 * immediately terminate connections to that device that require 1562 * authentication and encryption. 1563 * 1564 * @return true on success, false on error 1565 * @hide 1566 */ 1567 @SystemApi 1568 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) removeBond()1569 public boolean removeBond() { 1570 final IBluetooth service = sService; 1571 if (service == null) { 1572 Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond"); 1573 return false; 1574 } 1575 try { 1576 Log.i(TAG, "removeBond() for device " + getAddress() 1577 + " called by pid: " + Process.myPid() 1578 + " tid: " + Process.myTid()); 1579 return service.removeBond(this, mAttributionSource); 1580 } catch (RemoteException e) { 1581 Log.e(TAG, "", e); 1582 } 1583 return false; 1584 } 1585 1586 private static final String BLUETOOTH_BONDING_CACHE_PROPERTY = 1587 "cache_key.bluetooth.get_bond_state"; 1588 private final PropertyInvalidatedCache<BluetoothDevice, Integer> mBluetoothBondCache = 1589 new PropertyInvalidatedCache<BluetoothDevice, Integer>( 1590 8, BLUETOOTH_BONDING_CACHE_PROPERTY) { 1591 @Override 1592 @SuppressLint("AndroidFrameworkRequiresPermission") 1593 protected Integer recompute(BluetoothDevice query) { 1594 try { 1595 return sService.getBondState(query, mAttributionSource); 1596 } catch (RemoteException e) { 1597 throw e.rethrowAsRuntimeException(); 1598 } 1599 } 1600 }; 1601 1602 /** @hide */ disableBluetoothGetBondStateCache()1603 public void disableBluetoothGetBondStateCache() { 1604 mBluetoothBondCache.disableLocal(); 1605 } 1606 1607 /** @hide */ invalidateBluetoothGetBondStateCache()1608 public static void invalidateBluetoothGetBondStateCache() { 1609 PropertyInvalidatedCache.invalidateCache(BLUETOOTH_BONDING_CACHE_PROPERTY); 1610 } 1611 1612 /** 1613 * Get the bond state of the remote device. 1614 * <p>Possible values for the bond state are: 1615 * {@link #BOND_NONE}, 1616 * {@link #BOND_BONDING}, 1617 * {@link #BOND_BONDED}. 1618 * 1619 * @return the bond state 1620 */ 1621 @RequiresLegacyBluetoothPermission 1622 @RequiresBluetoothConnectPermission 1623 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 1624 @SuppressLint("AndroidFrameworkRequiresPermission") getBondState()1625 public int getBondState() { 1626 final IBluetooth service = sService; 1627 if (service == null) { 1628 Log.e(TAG, "BT not enabled. Cannot get bond state"); 1629 return BOND_NONE; 1630 } 1631 try { 1632 return mBluetoothBondCache.query(this); 1633 } catch (RuntimeException e) { 1634 if (e.getCause() instanceof RemoteException) { 1635 Log.e(TAG, "", e); 1636 } else { 1637 throw e; 1638 } 1639 } 1640 return BOND_NONE; 1641 } 1642 1643 /** 1644 * Checks whether this bluetooth device is associated with CDM and meets the criteria to skip 1645 * the bluetooth pairing dialog because it has been already consented by the CDM prompt. 1646 * 1647 * @return true if we can bond without the dialog, false otherwise 1648 * 1649 * @hide 1650 */ 1651 @SystemApi 1652 @RequiresPermission(allOf = { 1653 android.Manifest.permission.BLUETOOTH_CONNECT, 1654 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 1655 }) canBondWithoutDialog()1656 public boolean canBondWithoutDialog() { 1657 final IBluetooth service = sService; 1658 if (service == null) { 1659 Log.e(TAG, "BT not enabled. Cannot check if we can skip pairing dialog"); 1660 return false; 1661 } 1662 try { 1663 if (DBG) Log.d(TAG, "canBondWithoutDialog, device: " + this); 1664 return service.canBondWithoutDialog(this, mAttributionSource); 1665 } catch (RemoteException e) { 1666 Log.e(TAG, "", e); 1667 } 1668 return false; 1669 } 1670 1671 /** 1672 * Returns whether there is an open connection to this device. 1673 * 1674 * @return True if there is at least one open connection to this device. 1675 * @hide 1676 */ 1677 @SystemApi 1678 @RequiresLegacyBluetoothPermission 1679 @RequiresBluetoothConnectPermission 1680 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) isConnected()1681 public boolean isConnected() { 1682 final IBluetooth service = sService; 1683 if (service == null) { 1684 // BT is not enabled, we cannot be connected. 1685 return false; 1686 } 1687 try { 1688 return service.getConnectionStateWithAttribution(this, mAttributionSource) 1689 != CONNECTION_STATE_DISCONNECTED; 1690 } catch (RemoteException e) { 1691 Log.e(TAG, "", e); 1692 return false; 1693 } 1694 } 1695 1696 /** 1697 * Returns whether there is an open connection to this device 1698 * that has been encrypted. 1699 * 1700 * @return True if there is at least one encrypted connection to this device. 1701 * @hide 1702 */ 1703 @SystemApi 1704 @RequiresLegacyBluetoothPermission 1705 @RequiresBluetoothConnectPermission 1706 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) isEncrypted()1707 public boolean isEncrypted() { 1708 final IBluetooth service = sService; 1709 if (service == null) { 1710 // BT is not enabled, we cannot be connected. 1711 return false; 1712 } 1713 try { 1714 return service.getConnectionStateWithAttribution(this, mAttributionSource) 1715 > CONNECTION_STATE_CONNECTED; 1716 } catch (RemoteException e) { 1717 Log.e(TAG, "", e); 1718 return false; 1719 } 1720 } 1721 1722 /** 1723 * Get the Bluetooth class of the remote device. 1724 * 1725 * @return Bluetooth class object, or null on error 1726 */ 1727 @RequiresLegacyBluetoothPermission 1728 @RequiresBluetoothConnectPermission 1729 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getBluetoothClass()1730 public BluetoothClass getBluetoothClass() { 1731 final IBluetooth service = sService; 1732 if (service == null) { 1733 Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class"); 1734 return null; 1735 } 1736 try { 1737 int classInt = service.getRemoteClass(this, mAttributionSource); 1738 if (classInt == BluetoothClass.ERROR) return null; 1739 return new BluetoothClass(classInt); 1740 } catch (RemoteException e) { 1741 Log.e(TAG, "", e); 1742 } 1743 return null; 1744 } 1745 1746 /** 1747 * Returns the supported features (UUIDs) of the remote device. 1748 * 1749 * <p>This method does not start a service discovery procedure to retrieve the UUIDs 1750 * from the remote device. Instead, the local cached copy of the service 1751 * UUIDs are returned. 1752 * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired. 1753 * 1754 * @return the supported features (UUIDs) of the remote device, or null on error 1755 */ 1756 @RequiresLegacyBluetoothPermission 1757 @RequiresBluetoothConnectPermission 1758 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getUuids()1759 public ParcelUuid[] getUuids() { 1760 final IBluetooth service = sService; 1761 if (service == null || !isBluetoothEnabled()) { 1762 Log.e(TAG, "BT not enabled. Cannot get remote device Uuids"); 1763 return null; 1764 } 1765 try { 1766 return service.getRemoteUuids(this, mAttributionSource); 1767 } catch (RemoteException e) { 1768 Log.e(TAG, "", e); 1769 } 1770 return null; 1771 } 1772 1773 /** 1774 * Perform a service discovery on the remote device to get the UUIDs supported. 1775 * 1776 * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent, 1777 * with the UUIDs supported by the remote end. If there is an error 1778 * in getting the SDP records or if the process takes a long time, or the device is bonding and 1779 * we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the UUIDs that is 1780 * currently present in the cache. Clients should use the {@link #getUuids} to get UUIDs 1781 * if service discovery is not to be performed. If there is an ongoing bonding process, 1782 * service discovery or device inquiry, the request will be queued. 1783 * 1784 * @return False if the check fails, True if the process of initiating an ACL connection 1785 * to the remote device was started or cached UUIDs will be broadcast. 1786 */ 1787 @RequiresLegacyBluetoothPermission 1788 @RequiresBluetoothConnectPermission 1789 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) fetchUuidsWithSdp()1790 public boolean fetchUuidsWithSdp() { 1791 final IBluetooth service = sService; 1792 if (service == null || !isBluetoothEnabled()) { 1793 Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp"); 1794 return false; 1795 } 1796 try { 1797 return service.fetchRemoteUuidsWithAttribution(this, mAttributionSource); 1798 } catch (RemoteException e) { 1799 Log.e(TAG, "", e); 1800 } 1801 return false; 1802 } 1803 1804 /** 1805 * Perform a service discovery on the remote device to get the SDP records associated 1806 * with the specified UUID. 1807 * 1808 * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent, 1809 * with the SDP records found on the remote end. If there is an error 1810 * in getting the SDP records or if the process takes a long time, 1811 * {@link #ACTION_SDP_RECORD} intent is sent with an status value in 1812 * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0. 1813 * Detailed status error codes can be found by members of the Bluetooth package in 1814 * the AbstractionLayer class. 1815 * <p>The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}. 1816 * The object type will match one of the SdpXxxRecord types, depending on the UUID searched 1817 * for. 1818 * 1819 * @return False if the check fails, True if the process 1820 * of initiating an ACL connection to the remote device 1821 * was started. 1822 */ 1823 /** @hide */ 1824 @RequiresLegacyBluetoothPermission 1825 @RequiresBluetoothConnectPermission 1826 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) sdpSearch(ParcelUuid uuid)1827 public boolean sdpSearch(ParcelUuid uuid) { 1828 final IBluetooth service = sService; 1829 if (service == null) { 1830 Log.e(TAG, "BT not enabled. Cannot query remote device sdp records"); 1831 return false; 1832 } 1833 try { 1834 return service.sdpSearch(this, uuid, mAttributionSource); 1835 } catch (RemoteException e) { 1836 Log.e(TAG, "", e); 1837 } 1838 return false; 1839 } 1840 1841 /** 1842 * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} 1843 * 1844 * @return true pin has been set false for error 1845 */ 1846 @RequiresLegacyBluetoothAdminPermission 1847 @RequiresBluetoothConnectPermission 1848 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) setPin(byte[] pin)1849 public boolean setPin(byte[] pin) { 1850 final IBluetooth service = sService; 1851 if (service == null) { 1852 Log.e(TAG, "BT not enabled. Cannot set Remote Device pin"); 1853 return false; 1854 } 1855 try { 1856 return service.setPin(this, true, pin.length, pin, mAttributionSource); 1857 } catch (RemoteException e) { 1858 Log.e(TAG, "", e); 1859 } 1860 return false; 1861 } 1862 1863 /** 1864 * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} 1865 * 1866 * @return true pin has been set false for error 1867 * @hide 1868 */ 1869 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1870 @RequiresLegacyBluetoothAdminPermission 1871 @RequiresBluetoothConnectPermission 1872 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) setPin(@onNull String pin)1873 public boolean setPin(@NonNull String pin) { 1874 byte[] pinBytes = convertPinToBytes(pin); 1875 if (pinBytes == null) { 1876 return false; 1877 } 1878 return setPin(pinBytes); 1879 } 1880 1881 /** 1882 * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing. 1883 * 1884 * @return true confirmation has been sent out false for error 1885 */ 1886 @RequiresPermission(allOf = { 1887 android.Manifest.permission.BLUETOOTH_CONNECT, 1888 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 1889 }) setPairingConfirmation(boolean confirm)1890 public boolean setPairingConfirmation(boolean confirm) { 1891 final IBluetooth service = sService; 1892 if (service == null) { 1893 Log.e(TAG, "BT not enabled. Cannot set pairing confirmation"); 1894 return false; 1895 } 1896 try { 1897 return service.setPairingConfirmation(this, confirm, mAttributionSource); 1898 } catch (RemoteException e) { 1899 Log.e(TAG, "", e); 1900 } 1901 return false; 1902 } 1903 1904 /** 1905 * Cancels pairing to this device 1906 * 1907 * @return true if pairing cancelled successfully, false otherwise 1908 * 1909 * @hide 1910 */ 1911 @UnsupportedAppUsage 1912 @RequiresLegacyBluetoothAdminPermission 1913 @RequiresBluetoothConnectPermission 1914 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) cancelPairing()1915 public boolean cancelPairing() { 1916 final IBluetooth service = sService; 1917 if (service == null) { 1918 Log.e(TAG, "BT not enabled. Cannot cancel pairing"); 1919 return false; 1920 } 1921 try { 1922 return service.cancelBondProcess(this, mAttributionSource); 1923 } catch (RemoteException e) { 1924 Log.e(TAG, "", e); 1925 } 1926 return false; 1927 } 1928 isBluetoothEnabled()1929 boolean isBluetoothEnabled() { 1930 boolean ret = false; 1931 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1932 if (adapter != null && adapter.isEnabled()) { 1933 ret = true; 1934 } 1935 return ret; 1936 } 1937 1938 /** 1939 * Gets whether the phonebook access is allowed for this bluetooth device 1940 * 1941 * @return Whether the phonebook access is allowed to this device. Can be {@link 1942 * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. 1943 * @hide 1944 */ 1945 @UnsupportedAppUsage 1946 @RequiresLegacyBluetoothPermission 1947 @RequiresBluetoothConnectPermission 1948 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getPhonebookAccessPermission()1949 public @AccessPermission int getPhonebookAccessPermission() { 1950 final IBluetooth service = sService; 1951 if (service == null) { 1952 return ACCESS_UNKNOWN; 1953 } 1954 try { 1955 return service.getPhonebookAccessPermission(this, mAttributionSource); 1956 } catch (RemoteException e) { 1957 Log.e(TAG, "", e); 1958 } 1959 return ACCESS_UNKNOWN; 1960 } 1961 1962 /** 1963 * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not 1964 * be routed to the {@link BluetoothDevice} if set to {@code true}. 1965 * 1966 * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice} 1967 * is an active device (for A2DP or HFP), the active device for that profile 1968 * will be set to null. 1969 * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP 1970 * active device is null, the {@link BluetoothDevice} will be set as the 1971 * active device for that profile. 1972 * If the {@link BluetoothDevice} is disconnected, it exits silence mode. 1973 * If the {@link BluetoothDevice} is set as the active device for A2DP or 1974 * HFP, while silence mode is enabled, then the device will exit silence mode. 1975 * If the {@link BluetoothDevice} is in silence mode, AVRCP position change 1976 * event and HFP AG indicators will be disabled. 1977 * If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot 1978 * enter silence mode. 1979 * 1980 * @param silence true to enter silence mode, false to exit 1981 * @return true on success, false on error. 1982 * @throws IllegalStateException if Bluetooth is not turned ON. 1983 * @hide 1984 */ 1985 @SystemApi 1986 @RequiresPermission(allOf = { 1987 android.Manifest.permission.BLUETOOTH_CONNECT, 1988 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 1989 }) setSilenceMode(boolean silence)1990 public boolean setSilenceMode(boolean silence) { 1991 final IBluetooth service = sService; 1992 if (service == null) { 1993 throw new IllegalStateException("Bluetooth is not turned ON"); 1994 } 1995 try { 1996 return service.setSilenceMode(this, silence, mAttributionSource); 1997 } catch (RemoteException e) { 1998 Log.e(TAG, "setSilenceMode fail", e); 1999 return false; 2000 } 2001 } 2002 2003 /** 2004 * Check whether the {@link BluetoothDevice} is in silence mode 2005 * 2006 * @return true on device in silence mode, otherwise false. 2007 * @throws IllegalStateException if Bluetooth is not turned ON. 2008 * @hide 2009 */ 2010 @SystemApi 2011 @RequiresPermission(allOf = { 2012 android.Manifest.permission.BLUETOOTH_CONNECT, 2013 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2014 }) isInSilenceMode()2015 public boolean isInSilenceMode() { 2016 final IBluetooth service = sService; 2017 if (service == null) { 2018 throw new IllegalStateException("Bluetooth is not turned ON"); 2019 } 2020 try { 2021 return service.getSilenceMode(this, mAttributionSource); 2022 } catch (RemoteException e) { 2023 Log.e(TAG, "isInSilenceMode fail", e); 2024 return false; 2025 } 2026 } 2027 2028 /** 2029 * Sets whether the phonebook access is allowed to this device. 2030 * 2031 * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link 2032 * #ACCESS_REJECTED}. 2033 * @return Whether the value has been successfully set. 2034 * @hide 2035 */ 2036 @SystemApi 2037 @RequiresPermission(allOf = { 2038 android.Manifest.permission.BLUETOOTH_CONNECT, 2039 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2040 }) setPhonebookAccessPermission(@ccessPermission int value)2041 public boolean setPhonebookAccessPermission(@AccessPermission int value) { 2042 final IBluetooth service = sService; 2043 if (service == null) { 2044 return false; 2045 } 2046 try { 2047 return service.setPhonebookAccessPermission(this, value, mAttributionSource); 2048 } catch (RemoteException e) { 2049 Log.e(TAG, "", e); 2050 } 2051 return false; 2052 } 2053 2054 /** 2055 * Gets whether message access is allowed to this bluetooth device 2056 * 2057 * @return Whether the message access is allowed to this device. 2058 * @hide 2059 */ 2060 @UnsupportedAppUsage 2061 @RequiresLegacyBluetoothPermission 2062 @RequiresBluetoothConnectPermission 2063 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getMessageAccessPermission()2064 public @AccessPermission int getMessageAccessPermission() { 2065 final IBluetooth service = sService; 2066 if (service == null) { 2067 return ACCESS_UNKNOWN; 2068 } 2069 try { 2070 return service.getMessageAccessPermission(this, mAttributionSource); 2071 } catch (RemoteException e) { 2072 Log.e(TAG, "", e); 2073 } 2074 return ACCESS_UNKNOWN; 2075 } 2076 2077 /** 2078 * Sets whether the message access is allowed to this device. 2079 * 2080 * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded, 2081 * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if 2082 * the permission is not being granted. 2083 * @return Whether the value has been successfully set. 2084 * @hide 2085 */ 2086 @SystemApi 2087 @RequiresPermission(allOf = { 2088 android.Manifest.permission.BLUETOOTH_CONNECT, 2089 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2090 }) setMessageAccessPermission(@ccessPermission int value)2091 public boolean setMessageAccessPermission(@AccessPermission int value) { 2092 // Validates param value is one of the accepted constants 2093 if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) { 2094 throw new IllegalArgumentException(value + "is not a valid AccessPermission value"); 2095 } 2096 final IBluetooth service = sService; 2097 if (service == null) { 2098 return false; 2099 } 2100 try { 2101 return service.setMessageAccessPermission(this, value, mAttributionSource); 2102 } catch (RemoteException e) { 2103 Log.e(TAG, "", e); 2104 } 2105 return false; 2106 } 2107 2108 /** 2109 * Gets whether sim access is allowed for this bluetooth device 2110 * 2111 * @return Whether the Sim access is allowed to this device. 2112 * @hide 2113 */ 2114 @SystemApi 2115 @RequiresLegacyBluetoothPermission 2116 @RequiresBluetoothConnectPermission 2117 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getSimAccessPermission()2118 public @AccessPermission int getSimAccessPermission() { 2119 final IBluetooth service = sService; 2120 if (service == null) { 2121 return ACCESS_UNKNOWN; 2122 } 2123 try { 2124 return service.getSimAccessPermission(this, mAttributionSource); 2125 } catch (RemoteException e) { 2126 Log.e(TAG, "", e); 2127 } 2128 return ACCESS_UNKNOWN; 2129 } 2130 2131 /** 2132 * Sets whether the Sim access is allowed to this device. 2133 * 2134 * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded, 2135 * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if 2136 * the permission is not being granted. 2137 * @return Whether the value has been successfully set. 2138 * @hide 2139 */ 2140 @SystemApi 2141 @RequiresPermission(allOf = { 2142 android.Manifest.permission.BLUETOOTH_CONNECT, 2143 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2144 }) setSimAccessPermission(int value)2145 public boolean setSimAccessPermission(int value) { 2146 final IBluetooth service = sService; 2147 if (service == null) { 2148 return false; 2149 } 2150 try { 2151 return service.setSimAccessPermission(this, value, mAttributionSource); 2152 } catch (RemoteException e) { 2153 Log.e(TAG, "", e); 2154 } 2155 return false; 2156 } 2157 2158 /** 2159 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 2160 * outgoing connection to this remote device on given channel. 2161 * <p>The remote device will be authenticated and communication on this 2162 * socket will be encrypted. 2163 * <p> Use this socket only if an authenticated socket link is possible. 2164 * Authentication refers to the authentication of the link key to 2165 * prevent person-in-the-middle type of attacks. 2166 * For example, for Bluetooth 2.1 devices, if any of the devices does not 2167 * have an input and output capability or just has the ability to 2168 * display a numeric key, a secure socket connection is not possible. 2169 * In such a case, use {@link createInsecureRfcommSocket}. 2170 * For more details, refer to the Security Model section 5.2 (vol 3) of 2171 * Bluetooth Core Specification version 2.1 + EDR. 2172 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 2173 * connection. 2174 * <p>Valid RFCOMM channels are in range 1 to 30. 2175 * 2176 * @param channel RFCOMM channel to connect to 2177 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2178 * @throws IOException on error, for example Bluetooth not available, or insufficient 2179 * permissions 2180 * @hide 2181 */ 2182 @UnsupportedAppUsage 2183 @RequiresLegacyBluetoothPermission 2184 @RequiresBluetoothConnectPermission 2185 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2186 @SuppressLint("AndroidFrameworkRequiresPermission") createRfcommSocket(int channel)2187 public BluetoothSocket createRfcommSocket(int channel) throws IOException { 2188 if (!isBluetoothEnabled()) { 2189 Log.e(TAG, "Bluetooth is not enabled"); 2190 throw new IOException(); 2191 } 2192 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel, 2193 null); 2194 } 2195 2196 /** 2197 * Create an L2cap {@link BluetoothSocket} ready to start a secure 2198 * outgoing connection to this remote device on given channel. 2199 * <p>The remote device will be authenticated and communication on this 2200 * socket will be encrypted. 2201 * <p> Use this socket only if an authenticated socket link is possible. 2202 * Authentication refers to the authentication of the link key to 2203 * prevent person-in-the-middle type of attacks. 2204 * For example, for Bluetooth 2.1 devices, if any of the devices does not 2205 * have an input and output capability or just has the ability to 2206 * display a numeric key, a secure socket connection is not possible. 2207 * In such a case, use {@link createInsecureRfcommSocket}. 2208 * For more details, refer to the Security Model section 5.2 (vol 3) of 2209 * Bluetooth Core Specification version 2.1 + EDR. 2210 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 2211 * connection. 2212 * <p>Valid L2CAP PSM channels are in range 1 to 2^16. 2213 * 2214 * @param channel L2cap PSM/channel to connect to 2215 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2216 * @throws IOException on error, for example Bluetooth not available, or insufficient 2217 * permissions 2218 * @hide 2219 */ 2220 @RequiresLegacyBluetoothPermission 2221 @RequiresBluetoothConnectPermission 2222 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2223 @SuppressLint("AndroidFrameworkRequiresPermission") createL2capSocket(int channel)2224 public BluetoothSocket createL2capSocket(int channel) throws IOException { 2225 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel, 2226 null); 2227 } 2228 2229 /** 2230 * Create an L2cap {@link BluetoothSocket} ready to start an insecure 2231 * outgoing connection to this remote device on given channel. 2232 * <p>The remote device will be not authenticated and communication on this 2233 * socket will not be encrypted. 2234 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 2235 * connection. 2236 * <p>Valid L2CAP PSM channels are in range 1 to 2^16. 2237 * 2238 * @param channel L2cap PSM/channel to connect to 2239 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2240 * @throws IOException on error, for example Bluetooth not available, or insufficient 2241 * permissions 2242 * @hide 2243 */ 2244 @RequiresLegacyBluetoothPermission 2245 @RequiresBluetoothConnectPermission 2246 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2247 @SuppressLint("AndroidFrameworkRequiresPermission") createInsecureL2capSocket(int channel)2248 public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException { 2249 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel, 2250 null); 2251 } 2252 2253 /** 2254 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 2255 * outgoing connection to this remote device using SDP lookup of uuid. 2256 * <p>This is designed to be used with {@link 2257 * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer 2258 * Bluetooth applications. 2259 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 2260 * connection. This will also perform an SDP lookup of the given uuid to 2261 * determine which channel to connect to. 2262 * <p>The remote device will be authenticated and communication on this 2263 * socket will be encrypted. 2264 * <p> Use this socket only if an authenticated socket link is possible. 2265 * Authentication refers to the authentication of the link key to 2266 * prevent person-in-the-middle type of attacks. 2267 * For example, for Bluetooth 2.1 devices, if any of the devices does not 2268 * have an input and output capability or just has the ability to 2269 * display a numeric key, a secure socket connection is not possible. 2270 * In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}. 2271 * For more details, refer to the Security Model section 5.2 (vol 3) of 2272 * Bluetooth Core Specification version 2.1 + EDR. 2273 * <p>Hint: If you are connecting to a Bluetooth serial board then try 2274 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 2275 * However if you are connecting to an Android peer then please generate 2276 * your own unique UUID. 2277 * 2278 * @param uuid service record uuid to lookup RFCOMM channel 2279 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2280 * @throws IOException on error, for example Bluetooth not available, or insufficient 2281 * permissions 2282 */ 2283 @RequiresLegacyBluetoothPermission 2284 @RequiresBluetoothConnectPermission 2285 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2286 @SuppressLint("AndroidFrameworkRequiresPermission") createRfcommSocketToServiceRecord(UUID uuid)2287 public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException { 2288 if (!isBluetoothEnabled()) { 2289 Log.e(TAG, "Bluetooth is not enabled"); 2290 throw new IOException(); 2291 } 2292 2293 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1, 2294 new ParcelUuid(uuid)); 2295 } 2296 2297 /** 2298 * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure 2299 * outgoing connection to this remote device using SDP lookup of uuid. 2300 * <p> The communication channel will not have an authenticated link key 2301 * i.e it will be subject to person-in-the-middle attacks. For Bluetooth 2.1 2302 * devices, the link key will be encrypted, as encryption is mandatory. 2303 * For legacy devices (pre Bluetooth 2.1 devices) the link key will 2304 * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an 2305 * encrypted and authenticated communication channel is desired. 2306 * <p>This is designed to be used with {@link 2307 * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer 2308 * Bluetooth applications. 2309 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 2310 * connection. This will also perform an SDP lookup of the given uuid to 2311 * determine which channel to connect to. 2312 * <p>The remote device will be authenticated and communication on this 2313 * socket will be encrypted. 2314 * <p>Hint: If you are connecting to a Bluetooth serial board then try 2315 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 2316 * However if you are connecting to an Android peer then please generate 2317 * your own unique UUID. 2318 * 2319 * @param uuid service record uuid to lookup RFCOMM channel 2320 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 2321 * @throws IOException on error, for example Bluetooth not available, or insufficient 2322 * permissions 2323 */ 2324 @RequiresLegacyBluetoothPermission 2325 @RequiresBluetoothConnectPermission 2326 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2327 @SuppressLint("AndroidFrameworkRequiresPermission") createInsecureRfcommSocketToServiceRecord(UUID uuid)2328 public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException { 2329 if (!isBluetoothEnabled()) { 2330 Log.e(TAG, "Bluetooth is not enabled"); 2331 throw new IOException(); 2332 } 2333 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1, 2334 new ParcelUuid(uuid)); 2335 } 2336 2337 /** 2338 * Construct an insecure RFCOMM socket ready to start an outgoing 2339 * connection. 2340 * Call #connect on the returned #BluetoothSocket to begin the connection. 2341 * The remote device will not be authenticated and communication on this 2342 * socket will not be encrypted. 2343 * 2344 * @param port remote port 2345 * @return An RFCOMM BluetoothSocket 2346 * @throws IOException On error, for example Bluetooth not available, or insufficient 2347 * permissions. 2348 * @hide 2349 */ 2350 @UnsupportedAppUsage(publicAlternatives = "Use " 2351 + "{@link #createInsecureRfcommSocketToServiceRecord} instead.") 2352 @RequiresLegacyBluetoothAdminPermission 2353 @RequiresBluetoothConnectPermission 2354 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2355 @SuppressLint("AndroidFrameworkRequiresPermission") createInsecureRfcommSocket(int port)2356 public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException { 2357 if (!isBluetoothEnabled()) { 2358 Log.e(TAG, "Bluetooth is not enabled"); 2359 throw new IOException(); 2360 } 2361 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port, 2362 null); 2363 } 2364 2365 /** 2366 * Construct a SCO socket ready to start an outgoing connection. 2367 * Call #connect on the returned #BluetoothSocket to begin the connection. 2368 * 2369 * @return a SCO BluetoothSocket 2370 * @throws IOException on error, for example Bluetooth not available, or insufficient 2371 * permissions. 2372 * @hide 2373 */ 2374 @UnsupportedAppUsage 2375 @RequiresLegacyBluetoothAdminPermission 2376 @RequiresBluetoothConnectPermission 2377 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2378 @SuppressLint("AndroidFrameworkRequiresPermission") createScoSocket()2379 public BluetoothSocket createScoSocket() throws IOException { 2380 if (!isBluetoothEnabled()) { 2381 Log.e(TAG, "Bluetooth is not enabled"); 2382 throw new IOException(); 2383 } 2384 return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null); 2385 } 2386 2387 /** 2388 * Check that a pin is valid and convert to byte array. 2389 * 2390 * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters. 2391 * 2392 * @param pin pin as java String 2393 * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin. 2394 * @hide 2395 */ 2396 @UnsupportedAppUsage convertPinToBytes(String pin)2397 public static byte[] convertPinToBytes(String pin) { 2398 if (pin == null) { 2399 return null; 2400 } 2401 byte[] pinBytes; 2402 try { 2403 pinBytes = pin.getBytes("UTF-8"); 2404 } catch (UnsupportedEncodingException uee) { 2405 Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen 2406 return null; 2407 } 2408 if (pinBytes.length <= 0 || pinBytes.length > 16) { 2409 return null; 2410 } 2411 return pinBytes; 2412 } 2413 2414 /** 2415 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 2416 * The callback is used to deliver results to Caller, such as connection status as well 2417 * as any further GATT client operations. 2418 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 2419 * GATT client operations. 2420 * 2421 * @param callback GATT callback handler that will receive asynchronous callbacks. 2422 * @param autoConnect Whether to directly connect to the remote device (false) or to 2423 * automatically connect as soon as the remote device becomes available (true). 2424 * @throws IllegalArgumentException if callback is null 2425 */ 2426 @RequiresBluetoothConnectPermission 2427 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)2428 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 2429 BluetoothGattCallback callback) { 2430 return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO)); 2431 } 2432 2433 /** 2434 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 2435 * The callback is used to deliver results to Caller, such as connection status as well 2436 * as any further GATT client operations. 2437 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 2438 * GATT client operations. 2439 * 2440 * @param callback GATT callback handler that will receive asynchronous callbacks. 2441 * @param autoConnect Whether to directly connect to the remote device (false) or to 2442 * automatically connect as soon as the remote device becomes available (true). 2443 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 2444 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 2445 * BluetoothDevice#TRANSPORT_LE} 2446 * @throws IllegalArgumentException if callback is null 2447 */ 2448 @RequiresBluetoothConnectPermission 2449 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)2450 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 2451 BluetoothGattCallback callback, int transport) { 2452 return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK)); 2453 } 2454 2455 /** 2456 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 2457 * The callback is used to deliver results to Caller, such as connection status as well 2458 * as any further GATT client operations. 2459 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 2460 * GATT client operations. 2461 * 2462 * @param callback GATT callback handler that will receive asynchronous callbacks. 2463 * @param autoConnect Whether to directly connect to the remote device (false) or to 2464 * automatically connect as soon as the remote device becomes available (true). 2465 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 2466 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 2467 * BluetoothDevice#TRANSPORT_LE} 2468 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 2469 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link 2470 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} 2471 * is set to true. 2472 * @throws NullPointerException if callback is null 2473 */ 2474 @RequiresBluetoothConnectPermission 2475 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy)2476 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 2477 BluetoothGattCallback callback, int transport, int phy) { 2478 return connectGatt(context, autoConnect, callback, transport, phy, null); 2479 } 2480 2481 /** 2482 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 2483 * The callback is used to deliver results to Caller, such as connection status as well 2484 * as any further GATT client operations. 2485 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 2486 * GATT client operations. 2487 * 2488 * @param callback GATT callback handler that will receive asynchronous callbacks. 2489 * @param autoConnect Whether to directly connect to the remote device (false) or to 2490 * automatically connect as soon as the remote device becomes available (true). 2491 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 2492 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 2493 * BluetoothDevice#TRANSPORT_LE} 2494 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 2495 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link 2496 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} 2497 * is set to true. 2498 * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on 2499 * an un-specified background thread. 2500 * @throws NullPointerException if callback is null 2501 */ 2502 @RequiresBluetoothConnectPermission 2503 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler)2504 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 2505 BluetoothGattCallback callback, int transport, int phy, 2506 Handler handler) { 2507 return connectGatt(context, autoConnect, callback, transport, false, phy, handler); 2508 } 2509 2510 /** 2511 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 2512 * The callback is used to deliver results to Caller, such as connection status as well 2513 * as any further GATT client operations. 2514 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 2515 * GATT client operations. 2516 * 2517 * @param callback GATT callback handler that will receive asynchronous callbacks. 2518 * @param autoConnect Whether to directly connect to the remote device (false) or to 2519 * automatically connect as soon as the remote device becomes available (true). 2520 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 2521 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 2522 * BluetoothDevice#TRANSPORT_LE} 2523 * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client 2524 * does not hold a GATT connection. It automatically disconnects when no other GATT connections 2525 * are active for the remote device. 2526 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 2527 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link 2528 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} 2529 * is set to true. 2530 * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on 2531 * an un-specified background thread. 2532 * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client 2533 * operations. 2534 * @hide 2535 */ 2536 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2537 @RequiresBluetoothConnectPermission 2538 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, boolean opportunistic, int phy, Handler handler)2539 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 2540 BluetoothGattCallback callback, int transport, 2541 boolean opportunistic, int phy, Handler handler) { 2542 if (callback == null) { 2543 throw new NullPointerException("callback is null"); 2544 } 2545 2546 // TODO(Bluetooth) check whether platform support BLE 2547 // Do the check here or in GattServer? 2548 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 2549 IBluetoothManager managerService = adapter.getBluetoothManager(); 2550 try { 2551 IBluetoothGatt iGatt = managerService.getBluetoothGatt(); 2552 if (iGatt == null) { 2553 // BLE is not supported 2554 return null; 2555 } 2556 BluetoothGatt gatt = new BluetoothGatt( 2557 iGatt, this, transport, opportunistic, phy, mAttributionSource); 2558 gatt.connect(autoConnect, callback, handler); 2559 return gatt; 2560 } catch (RemoteException e) { 2561 Log.e(TAG, "", e); 2562 } 2563 return null; 2564 } 2565 2566 /** 2567 * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can 2568 * be used to start a secure outgoing connection to the remote device with the same dynamic 2569 * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only. 2570 * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for 2571 * peer-peer Bluetooth applications. 2572 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 2573 * <p>Application using this API is responsible for obtaining PSM value from remote device. 2574 * <p>The remote device will be authenticated and communication on this socket will be 2575 * encrypted. 2576 * <p> Use this socket if an authenticated socket link is possible. Authentication refers 2577 * to the authentication of the link key to prevent person-in-the-middle type of attacks. 2578 * 2579 * @param psm dynamic PSM value from remote device 2580 * @return a CoC #BluetoothSocket ready for an outgoing connection 2581 * @throws IOException on error, for example Bluetooth not available, or insufficient 2582 * permissions 2583 */ 2584 @RequiresLegacyBluetoothPermission 2585 @RequiresBluetoothConnectPermission 2586 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2587 @SuppressLint("AndroidFrameworkRequiresPermission") createL2capChannel(int psm)2588 public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException { 2589 if (!isBluetoothEnabled()) { 2590 Log.e(TAG, "createL2capChannel: Bluetooth is not enabled"); 2591 throw new IOException(); 2592 } 2593 if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm); 2594 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm, 2595 null); 2596 } 2597 2598 /** 2599 * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can 2600 * be used to start a secure outgoing connection to the remote device with the same dynamic 2601 * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only. 2602 * <p>This is designed to be used with {@link 2603 * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications. 2604 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 2605 * <p>Application using this API is responsible for obtaining PSM value from remote device. 2606 * <p> The communication channel may not have an authenticated link key, i.e. it may be subject 2607 * to person-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and 2608 * authenticated communication channel is possible. 2609 * 2610 * @param psm dynamic PSM value from remote device 2611 * @return a CoC #BluetoothSocket ready for an outgoing connection 2612 * @throws IOException on error, for example Bluetooth not available, or insufficient 2613 * permissions 2614 */ 2615 @RequiresLegacyBluetoothPermission 2616 @RequiresBluetoothConnectPermission 2617 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 2618 @SuppressLint("AndroidFrameworkRequiresPermission") createInsecureL2capChannel(int psm)2619 public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException { 2620 if (!isBluetoothEnabled()) { 2621 Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled"); 2622 throw new IOException(); 2623 } 2624 if (DBG) { 2625 Log.d(TAG, "createInsecureL2capChannel: psm=" + psm); 2626 } 2627 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm, 2628 null); 2629 } 2630 2631 /** 2632 * Set a keyed metadata of this {@link BluetoothDevice} to a 2633 * {@link String} value. 2634 * Only bonded devices's metadata will be persisted across Bluetooth 2635 * restart. 2636 * Metadata will be removed when the device's bond state is moved to 2637 * {@link #BOND_NONE}. 2638 * 2639 * @param key must be within the list of BluetoothDevice.METADATA_* 2640 * @param value a byte array data to set for key. Must be less than 2641 * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length 2642 * @return true on success, false on error 2643 * @hide 2644 */ 2645 @SystemApi 2646 @RequiresPermission(allOf = { 2647 android.Manifest.permission.BLUETOOTH_CONNECT, 2648 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2649 }) setMetadata(@etadataKey int key, @NonNull byte[] value)2650 public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) { 2651 final IBluetooth service = sService; 2652 if (service == null) { 2653 Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata"); 2654 return false; 2655 } 2656 if (value.length > METADATA_MAX_LENGTH) { 2657 throw new IllegalArgumentException("value length is " + value.length 2658 + ", should not over " + METADATA_MAX_LENGTH); 2659 } 2660 try { 2661 return service.setMetadata(this, key, value, mAttributionSource); 2662 } catch (RemoteException e) { 2663 Log.e(TAG, "setMetadata fail", e); 2664 return false; 2665 } 2666 } 2667 2668 /** 2669 * Get a keyed metadata for this {@link BluetoothDevice} as {@link String} 2670 * 2671 * @param key must be within the list of BluetoothDevice.METADATA_* 2672 * @return Metadata of the key as byte array, null on error or not found 2673 * @hide 2674 */ 2675 @SystemApi 2676 @Nullable 2677 @RequiresPermission(allOf = { 2678 android.Manifest.permission.BLUETOOTH_CONNECT, 2679 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 2680 }) getMetadata(@etadataKey int key)2681 public byte[] getMetadata(@MetadataKey int key) { 2682 final IBluetooth service = sService; 2683 if (service == null) { 2684 Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata"); 2685 return null; 2686 } 2687 try { 2688 return service.getMetadata(this, key, mAttributionSource); 2689 } catch (RemoteException e) { 2690 Log.e(TAG, "getMetadata fail", e); 2691 return null; 2692 } 2693 } 2694 2695 /** 2696 * Get the maxinum metadata key ID. 2697 * 2698 * @return the last supported metadata key 2699 * @hide 2700 */ getMaxMetadataKey()2701 public static @MetadataKey int getMaxMetadataKey() { 2702 return METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD; 2703 } 2704 } 2705