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