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