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.RequiresPermission; 21 import android.annotation.SdkConstant; 22 import android.annotation.SdkConstant.SdkConstantType; 23 import android.annotation.SystemApi; 24 import android.content.Context; 25 import android.os.Handler; 26 import android.os.Looper; 27 import android.os.Parcel; 28 import android.os.Parcelable; 29 import android.os.ParcelUuid; 30 import android.os.Process; 31 import android.os.RemoteException; 32 import android.util.Log; 33 34 import java.io.IOException; 35 import java.io.UnsupportedEncodingException; 36 import java.util.UUID; 37 38 /** 39 * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you 40 * create a connection with the respective device or query information about 41 * it, such as the name, address, class, and bonding state. 42 * 43 * <p>This class is really just a thin wrapper for a Bluetooth hardware 44 * address. Objects of this class are immutable. Operations on this class 45 * are performed on the remote Bluetooth hardware address, using the 46 * {@link BluetoothAdapter} that was used to create this {@link 47 * BluetoothDevice}. 48 * 49 * <p>To get a {@link BluetoothDevice}, use 50 * {@link BluetoothAdapter#getRemoteDevice(String) 51 * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device 52 * of a known MAC address (which you can get through device discovery with 53 * {@link BluetoothAdapter}) or get one from the set of bonded devices 54 * returned by {@link BluetoothAdapter#getBondedDevices() 55 * BluetoothAdapter.getBondedDevices()}. You can then open a 56 * {@link BluetoothSocket} for communication with the remote device, using 57 * {@link #createRfcommSocketToServiceRecord(UUID)}. 58 * 59 * <p class="note"><strong>Note:</strong> 60 * Requires the {@link android.Manifest.permission#BLUETOOTH} permission. 61 * 62 * <div class="special reference"> 63 * <h3>Developer Guides</h3> 64 * <p> 65 * For more information about using Bluetooth, read the <a href= 66 * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer 67 * guide. 68 * </p> 69 * </div> 70 * 71 * {@see BluetoothAdapter} 72 * {@see BluetoothSocket} 73 */ 74 public final class BluetoothDevice implements Parcelable { 75 private static final String TAG = "BluetoothDevice"; 76 private static final boolean DBG = false; 77 78 /** 79 * Connection state bitmask as returned by getConnectionState. 80 */ 81 private static final int CONNECTION_STATE_DISCONNECTED = 0; 82 private static final int CONNECTION_STATE_CONNECTED = 1; 83 private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2; 84 private static final int CONNECTION_STATE_ENCRYPTED_LE = 4; 85 86 /** 87 * Sentinel error value for this class. Guaranteed to not equal any other 88 * integer constant in this class. Provided as a convenience for functions 89 * that require a sentinel error value, for example: 90 * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 91 * BluetoothDevice.ERROR)</code> 92 */ 93 public static final int ERROR = Integer.MIN_VALUE; 94 95 /** 96 * Broadcast Action: Remote device discovered. 97 * <p>Sent when a remote device is found during discovery. 98 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 99 * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or 100 * {@link #EXTRA_RSSI} if they are available. 101 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} and 102 * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive. 103 */ 104 // TODO: Change API to not broadcast RSSI if not available (incoming connection) 105 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 106 public static final String ACTION_FOUND = 107 "android.bluetooth.device.action.FOUND"; 108 109 /** 110 * Broadcast Action: Remote device disappeared. 111 * <p>Sent when a remote device that was found in the last discovery is not 112 * found in the current discovery. 113 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 114 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 115 * @hide 116 */ 117 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 118 public static final String ACTION_DISAPPEARED = 119 "android.bluetooth.device.action.DISAPPEARED"; 120 121 /** 122 * Broadcast Action: Bluetooth class of a remote device has changed. 123 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 124 * #EXTRA_CLASS}. 125 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 126 * {@see BluetoothClass} 127 */ 128 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 129 public static final String ACTION_CLASS_CHANGED = 130 "android.bluetooth.device.action.CLASS_CHANGED"; 131 132 /** 133 * Broadcast Action: Indicates a low level (ACL) connection has been 134 * established with a remote device. 135 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 136 * <p>ACL connections are managed automatically by the Android Bluetooth 137 * stack. 138 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 139 */ 140 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 141 public static final String ACTION_ACL_CONNECTED = 142 "android.bluetooth.device.action.ACL_CONNECTED"; 143 144 /** 145 * Broadcast Action: Indicates that a low level (ACL) disconnection has 146 * been requested for a remote device, and it will soon be disconnected. 147 * <p>This is useful for graceful disconnection. Applications should use 148 * this intent as a hint to immediately terminate higher level connections 149 * (RFCOMM, L2CAP, or profile connections) to the remote device. 150 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 151 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 152 */ 153 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 154 public static final String ACTION_ACL_DISCONNECT_REQUESTED = 155 "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED"; 156 157 /** 158 * Broadcast Action: Indicates a low level (ACL) disconnection from a 159 * remote device. 160 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 161 * <p>ACL connections are managed automatically by the Android Bluetooth 162 * stack. 163 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 164 */ 165 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 166 public static final String ACTION_ACL_DISCONNECTED = 167 "android.bluetooth.device.action.ACL_DISCONNECTED"; 168 169 /** 170 * Broadcast Action: Indicates the friendly name of a remote device has 171 * been retrieved for the first time, or changed since the last retrieval. 172 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 173 * #EXTRA_NAME}. 174 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 175 */ 176 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 177 public static final String ACTION_NAME_CHANGED = 178 "android.bluetooth.device.action.NAME_CHANGED"; 179 180 /** 181 * Broadcast Action: Indicates the alias of a remote device has been 182 * changed. 183 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 184 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 185 * 186 * @hide 187 */ 188 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 189 public static final String ACTION_ALIAS_CHANGED = 190 "android.bluetooth.device.action.ALIAS_CHANGED"; 191 192 /** 193 * Broadcast Action: Indicates a change in the bond state of a remote 194 * device. For example, if a device is bonded (paired). 195 * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link 196 * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}. 197 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 198 */ 199 // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also 200 // contain a hidden extra field EXTRA_REASON with the result code. 201 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 202 public static final String ACTION_BOND_STATE_CHANGED = 203 "android.bluetooth.device.action.BOND_STATE_CHANGED"; 204 205 /** 206 * Used as a Parcelable {@link BluetoothDevice} extra field in every intent 207 * broadcast by this class. It contains the {@link BluetoothDevice} that 208 * the intent applies to. 209 */ 210 public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE"; 211 212 /** 213 * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link 214 * #ACTION_FOUND} intents. It contains the friendly Bluetooth name. 215 */ 216 public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME"; 217 218 /** 219 * Used as an optional short extra field in {@link #ACTION_FOUND} intents. 220 * Contains the RSSI value of the remote device as reported by the 221 * Bluetooth hardware. 222 */ 223 public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI"; 224 225 /** 226 * Used as a Parcelable {@link BluetoothClass} extra field in {@link 227 * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents. 228 */ 229 public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS"; 230 231 /** 232 * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. 233 * Contains the bond state of the remote device. 234 * <p>Possible values are: 235 * {@link #BOND_NONE}, 236 * {@link #BOND_BONDING}, 237 * {@link #BOND_BONDED}. 238 */ 239 public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE"; 240 /** 241 * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. 242 * Contains the previous bond state of the remote device. 243 * <p>Possible values are: 244 * {@link #BOND_NONE}, 245 * {@link #BOND_BONDING}, 246 * {@link #BOND_BONDED}. 247 */ 248 public static final String EXTRA_PREVIOUS_BOND_STATE = 249 "android.bluetooth.device.extra.PREVIOUS_BOND_STATE"; 250 /** 251 * Indicates the remote device is not bonded (paired). 252 * <p>There is no shared link key with the remote device, so communication 253 * (if it is allowed at all) will be unauthenticated and unencrypted. 254 */ 255 public static final int BOND_NONE = 10; 256 /** 257 * Indicates bonding (pairing) is in progress with the remote device. 258 */ 259 public static final int BOND_BONDING = 11; 260 /** 261 * Indicates the remote device is bonded (paired). 262 * <p>A shared link keys exists locally for the remote device, so 263 * communication can be authenticated and encrypted. 264 * <p><i>Being bonded (paired) with a remote device does not necessarily 265 * mean the device is currently connected. It just means that the pending 266 * procedure was completed at some earlier time, and the link key is still 267 * stored locally, ready to use on the next connection. 268 * </i> 269 */ 270 public static final int BOND_BONDED = 12; 271 272 /** 273 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} 274 * intents for unbond reason. 275 * @hide 276 */ 277 public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON"; 278 279 /** 280 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} 281 * intents to indicate pairing method used. Possible values are: 282 * {@link #PAIRING_VARIANT_PIN}, 283 * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION}, 284 */ 285 public static final String EXTRA_PAIRING_VARIANT = 286 "android.bluetooth.device.extra.PAIRING_VARIANT"; 287 288 /** 289 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} 290 * intents as the value of passkey. 291 */ 292 public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY"; 293 294 /** 295 * Bluetooth device type, Unknown 296 */ 297 public static final int DEVICE_TYPE_UNKNOWN = 0; 298 299 /** 300 * Bluetooth device type, Classic - BR/EDR devices 301 */ 302 public static final int DEVICE_TYPE_CLASSIC = 1; 303 304 /** 305 * Bluetooth device type, Low Energy - LE-only 306 */ 307 public static final int DEVICE_TYPE_LE = 2; 308 309 /** 310 * Bluetooth device type, Dual Mode - BR/EDR/LE 311 */ 312 public static final int DEVICE_TYPE_DUAL = 3; 313 314 315 /** @hide */ 316 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 317 public static final String ACTION_SDP_RECORD = 318 "android.bluetooth.device.action.SDP_RECORD"; 319 320 /** 321 * Broadcast Action: This intent is used to broadcast the {@link UUID} 322 * wrapped as a {@link android.os.ParcelUuid} of the remote device after it 323 * has been fetched. This intent is sent only when the UUIDs of the remote 324 * device are requested to be fetched using Service Discovery Protocol 325 * <p> Always contains the extra field {@link #EXTRA_DEVICE} 326 * <p> Always contains the extra field {@link #EXTRA_UUID} 327 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 328 */ 329 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 330 public static final String ACTION_UUID = 331 "android.bluetooth.device.action.UUID"; 332 333 /** @hide */ 334 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 335 public static final String ACTION_MAS_INSTANCE = 336 "android.bluetooth.device.action.MAS_INSTANCE"; 337 338 /** 339 * Broadcast Action: Indicates a failure to retrieve the name of a remote 340 * device. 341 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 342 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 343 * @hide 344 */ 345 //TODO: is this actually useful? 346 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 347 public static final String ACTION_NAME_FAILED = 348 "android.bluetooth.device.action.NAME_FAILED"; 349 350 /** 351 * Broadcast Action: This intent is used to broadcast PAIRING REQUEST 352 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to 353 * receive. 354 */ 355 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 356 public static final String ACTION_PAIRING_REQUEST = 357 "android.bluetooth.device.action.PAIRING_REQUEST"; 358 /** @hide */ 359 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 360 public static final String ACTION_PAIRING_CANCEL = 361 "android.bluetooth.device.action.PAIRING_CANCEL"; 362 363 /** @hide */ 364 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 365 public static final String ACTION_CONNECTION_ACCESS_REQUEST = 366 "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST"; 367 368 /** @hide */ 369 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 370 public static final String ACTION_CONNECTION_ACCESS_REPLY = 371 "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY"; 372 373 /** @hide */ 374 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 375 public static final String ACTION_CONNECTION_ACCESS_CANCEL = 376 "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL"; 377 378 /** 379 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent. 380 * @hide 381 */ 382 public static final String EXTRA_ACCESS_REQUEST_TYPE = 383 "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE"; 384 385 /**@hide*/ 386 public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1; 387 388 /**@hide*/ 389 public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2; 390 391 /**@hide*/ 392 public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3; 393 394 /**@hide*/ 395 public static final int REQUEST_TYPE_SIM_ACCESS = 4; 396 397 /** 398 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, 399 * Contains package name to return reply intent to. 400 * @hide 401 */ 402 public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME"; 403 404 /** 405 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, 406 * Contains class name to return reply intent to. 407 * @hide 408 */ 409 public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME"; 410 411 /** 412 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent. 413 * @hide 414 */ 415 public static final String EXTRA_CONNECTION_ACCESS_RESULT = 416 "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT"; 417 418 /**@hide*/ 419 public static final int CONNECTION_ACCESS_YES = 1; 420 421 /**@hide*/ 422 public static final int CONNECTION_ACCESS_NO = 2; 423 424 /** 425 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents, 426 * Contains boolean to indicate if the allowed response is once-for-all so that 427 * next request will be granted without asking user again. 428 * @hide 429 */ 430 public static final String EXTRA_ALWAYS_ALLOWED = 431 "android.bluetooth.device.extra.ALWAYS_ALLOWED"; 432 433 /** 434 * A bond attempt succeeded 435 * @hide 436 */ 437 public static final int BOND_SUCCESS = 0; 438 439 /** 440 * A bond attempt failed because pins did not match, or remote device did 441 * not respond to pin request in time 442 * @hide 443 */ 444 public static final int UNBOND_REASON_AUTH_FAILED = 1; 445 446 /** 447 * A bond attempt failed because the other side explicitly rejected 448 * bonding 449 * @hide 450 */ 451 public static final int UNBOND_REASON_AUTH_REJECTED = 2; 452 453 /** 454 * A bond attempt failed because we canceled the bonding process 455 * @hide 456 */ 457 public static final int UNBOND_REASON_AUTH_CANCELED = 3; 458 459 /** 460 * A bond attempt failed because we could not contact the remote device 461 * @hide 462 */ 463 public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4; 464 465 /** 466 * A bond attempt failed because a discovery is in progress 467 * @hide 468 */ 469 public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5; 470 471 /** 472 * A bond attempt failed because of authentication timeout 473 * @hide 474 */ 475 public static final int UNBOND_REASON_AUTH_TIMEOUT = 6; 476 477 /** 478 * A bond attempt failed because of repeated attempts 479 * @hide 480 */ 481 public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7; 482 483 /** 484 * A bond attempt failed because we received an Authentication Cancel 485 * by remote end 486 * @hide 487 */ 488 public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8; 489 490 /** 491 * An existing bond was explicitly revoked 492 * @hide 493 */ 494 public static final int UNBOND_REASON_REMOVED = 9; 495 496 /** 497 * The user will be prompted to enter a pin or 498 * an app will enter a pin for user. 499 */ 500 public static final int PAIRING_VARIANT_PIN = 0; 501 502 /** 503 * The user will be prompted to enter a passkey 504 * @hide 505 */ 506 public static final int PAIRING_VARIANT_PASSKEY = 1; 507 508 /** 509 * The user will be prompted to confirm the passkey displayed on the screen or 510 * an app will confirm the passkey for the user. 511 */ 512 public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2; 513 514 /** 515 * The user will be prompted to accept or deny the incoming pairing request 516 * @hide 517 */ 518 public static final int PAIRING_VARIANT_CONSENT = 3; 519 520 /** 521 * The user will be prompted to enter the passkey displayed on remote device 522 * This is used for Bluetooth 2.1 pairing. 523 * @hide 524 */ 525 public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4; 526 527 /** 528 * The user will be prompted to enter the PIN displayed on remote device. 529 * This is used for Bluetooth 2.0 pairing. 530 * @hide 531 */ 532 public static final int PAIRING_VARIANT_DISPLAY_PIN = 5; 533 534 /** 535 * The user will be prompted to accept or deny the OOB pairing request 536 * @hide 537 */ 538 public static final int PAIRING_VARIANT_OOB_CONSENT = 6; 539 540 /** 541 * The user will be prompted to enter a 16 digit pin or 542 * an app will enter a 16 digit pin for user. 543 * @hide 544 */ 545 public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7; 546 547 /** 548 * Used as an extra field in {@link #ACTION_UUID} intents, 549 * Contains the {@link android.os.ParcelUuid}s of the remote device which 550 * is a parcelable version of {@link UUID}. 551 */ 552 public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID"; 553 554 /** @hide */ 555 public static final String EXTRA_SDP_RECORD = 556 "android.bluetooth.device.extra.SDP_RECORD"; 557 558 /** @hide */ 559 public static final String EXTRA_SDP_SEARCH_STATUS = 560 "android.bluetooth.device.extra.SDP_SEARCH_STATUS"; 561 /** 562 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, 563 * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 564 * @hide 565 */ 566 public static final int ACCESS_UNKNOWN = 0; 567 568 /** 569 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, 570 * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 571 * @hide 572 */ 573 public static final int ACCESS_ALLOWED = 1; 574 575 /** 576 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, 577 * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 578 * @hide 579 */ 580 public static final int ACCESS_REJECTED = 2; 581 582 /** 583 * No preferrence of physical transport for GATT connections to remote dual-mode devices 584 */ 585 public static final int TRANSPORT_AUTO = 0; 586 587 /** 588 * Prefer BR/EDR transport for GATT connections to remote dual-mode devices 589 */ 590 public static final int TRANSPORT_BREDR = 1; 591 592 /** 593 * Prefer LE transport for GATT connections to remote dual-mode devices 594 */ 595 public static final int TRANSPORT_LE = 2; 596 597 /** 598 * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or 599 * connection. 600 */ 601 public static final int PHY_LE_1M = 1; 602 603 /** 604 * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or 605 * connection. 606 */ 607 public static final int PHY_LE_2M = 2; 608 609 /** 610 * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning 611 * or connection. 612 */ 613 public static final int PHY_LE_CODED = 3; 614 615 /** 616 * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available 617 * options in a bitmask. 618 */ 619 public static final int PHY_LE_1M_MASK = 1; 620 621 /** 622 * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available 623 * options in a bitmask. 624 */ 625 public static final int PHY_LE_2M_MASK = 2; 626 627 /** 628 * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many 629 * available options in a bitmask. 630 */ 631 public static final int PHY_LE_CODED_MASK = 4; 632 633 /** 634 * No preferred coding when transmitting on the LE Coded PHY. 635 */ 636 public static final int PHY_OPTION_NO_PREFERRED = 0; 637 638 /** 639 * Prefer the S=2 coding to be used when transmitting on the LE Coded PHY. 640 */ 641 public static final int PHY_OPTION_S2 = 1; 642 643 /** 644 * Prefer the S=8 coding to be used when transmitting on the LE Coded PHY. 645 */ 646 public static final int PHY_OPTION_S8 = 2; 647 648 649 /** @hide */ 650 public static final String EXTRA_MAS_INSTANCE = 651 "android.bluetooth.device.extra.MAS_INSTANCE"; 652 653 /** 654 * Lazy initialization. Guaranteed final after first object constructed, or 655 * getService() called. 656 * TODO: Unify implementation of sService amongst BluetoothFoo API's 657 */ 658 private static IBluetooth sService; 659 660 private final String mAddress; 661 getService()662 /*package*/ static IBluetooth getService() { 663 synchronized (BluetoothDevice.class) { 664 if (sService == null) { 665 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 666 sService = adapter.getBluetoothService(mStateChangeCallback); 667 } 668 } 669 return sService; 670 } 671 672 static IBluetoothManagerCallback mStateChangeCallback = new IBluetoothManagerCallback.Stub() { 673 674 public void onBluetoothServiceUp(IBluetooth bluetoothService) 675 throws RemoteException { 676 synchronized (BluetoothDevice.class) { 677 if (sService == null) { 678 sService = bluetoothService; 679 } 680 } 681 } 682 683 public void onBluetoothServiceDown() 684 throws RemoteException { 685 synchronized (BluetoothDevice.class) { 686 sService = null; 687 } 688 } 689 690 public void onBrEdrDown() 691 { 692 if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state"); 693 } 694 }; 695 /** 696 * Create a new BluetoothDevice 697 * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB", 698 * and is validated in this constructor. 699 * @param address valid Bluetooth MAC address 700 * @throws RuntimeException Bluetooth is not available on this platform 701 * @throws IllegalArgumentException address is invalid 702 * @hide 703 */ BluetoothDevice(String address)704 /*package*/ BluetoothDevice(String address) { 705 getService(); // ensures sService is initialized 706 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 707 throw new IllegalArgumentException(address + " is not a valid Bluetooth address"); 708 } 709 710 mAddress = address; 711 } 712 713 @Override equals(Object o)714 public boolean equals(Object o) { 715 if (o instanceof BluetoothDevice) { 716 return mAddress.equals(((BluetoothDevice)o).getAddress()); 717 } 718 return false; 719 } 720 721 @Override hashCode()722 public int hashCode() { 723 return mAddress.hashCode(); 724 } 725 726 /** 727 * Returns a string representation of this BluetoothDevice. 728 * <p>Currently this is the Bluetooth hardware address, for example 729 * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress} 730 * if you explicitly require the Bluetooth hardware address in case the 731 * {@link #toString} representation changes in the future. 732 * @return string representation of this BluetoothDevice 733 */ 734 @Override toString()735 public String toString() { 736 return mAddress; 737 } 738 describeContents()739 public int describeContents() { 740 return 0; 741 } 742 743 public static final Parcelable.Creator<BluetoothDevice> CREATOR = 744 new Parcelable.Creator<BluetoothDevice>() { 745 public BluetoothDevice createFromParcel(Parcel in) { 746 return new BluetoothDevice(in.readString()); 747 } 748 public BluetoothDevice[] newArray(int size) { 749 return new BluetoothDevice[size]; 750 } 751 }; 752 writeToParcel(Parcel out, int flags)753 public void writeToParcel(Parcel out, int flags) { 754 out.writeString(mAddress); 755 } 756 757 /** 758 * Returns the hardware address of this BluetoothDevice. 759 * <p> For example, "00:11:22:AA:BB:CC". 760 * @return Bluetooth hardware address as string 761 */ getAddress()762 public String getAddress() { 763 if (DBG) Log.d(TAG, "mAddress: " + mAddress); 764 return mAddress; 765 } 766 767 /** 768 * Get the friendly Bluetooth name of the remote device. 769 * 770 * <p>The local adapter will automatically retrieve remote names when 771 * performing a device scan, and will cache them. This method just returns 772 * the name for this device from the cache. 773 * 774 * @return the Bluetooth name, or null if there was a problem. 775 */ 776 @RequiresPermission(Manifest.permission.BLUETOOTH) getName()777 public String getName() { 778 if (sService == null) { 779 Log.e(TAG, "BT not enabled. Cannot get Remote Device name"); 780 return null; 781 } 782 try { 783 return sService.getRemoteName(this); 784 } catch (RemoteException e) {Log.e(TAG, "", e);} 785 return null; 786 } 787 788 /** 789 * Get the Bluetooth device type of the remote device. 790 * 791 * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} 792 * {@link #DEVICE_TYPE_DUAL}. 793 * {@link #DEVICE_TYPE_UNKNOWN} if it's not available 794 */ 795 @RequiresPermission(Manifest.permission.BLUETOOTH) getType()796 public int getType() { 797 if (sService == null) { 798 Log.e(TAG, "BT not enabled. Cannot get Remote Device type"); 799 return DEVICE_TYPE_UNKNOWN; 800 } 801 try { 802 return sService.getRemoteType(this); 803 } catch (RemoteException e) {Log.e(TAG, "", e);} 804 return DEVICE_TYPE_UNKNOWN; 805 } 806 807 /** 808 * Get the Bluetooth alias of the remote device. 809 * <p>Alias is the locally modified name of a remote device. 810 * 811 * @return the Bluetooth alias, or null if no alias or there was a problem 812 * @hide 813 */ getAlias()814 public String getAlias() { 815 if (sService == null) { 816 Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias"); 817 return null; 818 } 819 try { 820 return sService.getRemoteAlias(this); 821 } catch (RemoteException e) {Log.e(TAG, "", e);} 822 return null; 823 } 824 825 /** 826 * Set the Bluetooth alias of the remote device. 827 * <p>Alias is the locally modified name of a remote device. 828 * <p>This methoid overwrites the alias. The changed 829 * alias is saved in the local storage so that the change 830 * is preserved over power cycle. 831 * 832 * @return true on success, false on error 833 * @hide 834 */ setAlias(String alias)835 public boolean setAlias(String alias) { 836 if (sService == null) { 837 Log.e(TAG, "BT not enabled. Cannot set Remote Device name"); 838 return false; 839 } 840 try { 841 return sService.setRemoteAlias(this, alias); 842 } catch (RemoteException e) {Log.e(TAG, "", e);} 843 return false; 844 } 845 846 /** 847 * Get the Bluetooth alias of the remote device. 848 * If Alias is null, get the Bluetooth name instead. 849 * @see #getAlias() 850 * @see #getName() 851 * 852 * @return the Bluetooth alias, or null if no alias or there was a problem 853 * @hide 854 */ getAliasName()855 public String getAliasName() { 856 String name = getAlias(); 857 if (name == null) { 858 name = getName(); 859 } 860 return name; 861 } 862 863 /** 864 * Start the bonding (pairing) process with the remote device. 865 * <p>This is an asynchronous call, it will return immediately. Register 866 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 867 * the bonding process completes, and its result. 868 * <p>Android system services will handle the necessary user interactions 869 * to confirm and complete the bonding process. 870 * 871 * @return false on immediate error, true if bonding will begin 872 */ 873 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) createBond()874 public boolean createBond() { 875 if (sService == null) { 876 Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device"); 877 return false; 878 } 879 try { 880 Log.i(TAG, "createBond() for device " + getAddress() + 881 " called by pid: " + Process.myPid() + 882 " tid: " + Process.myTid()); 883 return sService.createBond(this, TRANSPORT_AUTO); 884 } catch (RemoteException e) {Log.e(TAG, "", e);} 885 return false; 886 } 887 888 /** 889 * Start the bonding (pairing) process with the remote device using the 890 * specified transport. 891 * 892 * <p>This is an asynchronous call, it will return immediately. Register 893 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 894 * the bonding process completes, and its result. 895 * <p>Android system services will handle the necessary user interactions 896 * to confirm and complete the bonding process. 897 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 898 * 899 * @param transport The transport to use for the pairing procedure. 900 * @return false on immediate error, true if bonding will begin 901 * @throws IllegalArgumentException if an invalid transport was specified 902 * @hide 903 */ createBond(int transport)904 public boolean createBond(int transport) { 905 if (sService == null) { 906 Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device"); 907 return false; 908 } 909 if (TRANSPORT_AUTO > transport || transport > TRANSPORT_LE) 910 { 911 throw new IllegalArgumentException(transport + " is not a valid Bluetooth transport"); 912 } 913 try { 914 Log.i(TAG, "createBond() for device " + getAddress() + 915 " called by pid: " + Process.myPid() + 916 " tid: " + Process.myTid()); 917 return sService.createBond(this, transport); 918 } catch (RemoteException e) {Log.e(TAG, "", e);} 919 return false; 920 } 921 922 /** 923 * Start the bonding (pairing) process with the remote device using the 924 * Out Of Band mechanism. 925 * 926 * <p>This is an asynchronous call, it will return immediately. Register 927 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 928 * the bonding process completes, and its result. 929 * 930 * <p>Android system services will handle the necessary user interactions 931 * to confirm and complete the bonding process. 932 * 933 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 934 * 935 * @param transport - Transport to use 936 * @param oobData - Out Of Band data 937 * @return false on immediate error, true if bonding will begin 938 * 939 * @hide 940 */ createBondOutOfBand(int transport, OobData oobData)941 public boolean createBondOutOfBand(int transport, OobData oobData) { 942 try { 943 return sService.createBondOutOfBand(this, transport, oobData); 944 } catch (RemoteException e) {Log.e(TAG, "", e);} 945 return false; 946 } 947 948 /** @hide */ isBondingInitiatedLocally()949 public boolean isBondingInitiatedLocally() { 950 try { 951 return sService.isBondingInitiatedLocally(this); 952 } catch (RemoteException e) {Log.e(TAG, "", e);} 953 return false; 954 } 955 956 /** 957 * Set the Out Of Band data for a remote device to be used later 958 * in the pairing mechanism. Users can obtain this data through other 959 * trusted channels 960 * 961 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 962 * 963 * @param hash Simple Secure pairing hash 964 * @param randomizer The random key obtained using OOB 965 * @return false on error; true otherwise 966 * 967 * @hide 968 */ setDeviceOutOfBandData(byte[] hash, byte[] randomizer)969 public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) { 970 //TODO(BT) 971 /* 972 try { 973 return sService.setDeviceOutOfBandData(this, hash, randomizer); 974 } catch (RemoteException e) {Log.e(TAG, "", e);} */ 975 return false; 976 } 977 978 /** 979 * Cancel an in-progress bonding request started with {@link #createBond}. 980 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 981 * 982 * @return true on success, false on error 983 * @hide 984 */ cancelBondProcess()985 public boolean cancelBondProcess() { 986 if (sService == null) { 987 Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond"); 988 return false; 989 } 990 try { 991 Log.i(TAG, "cancelBondProcess() for device " + getAddress() + 992 " called by pid: " + Process.myPid() + 993 " tid: " + Process.myTid()); 994 return sService.cancelBondProcess(this); 995 } catch (RemoteException e) {Log.e(TAG, "", e);} 996 return false; 997 } 998 999 /** 1000 * Remove bond (pairing) with the remote device. 1001 * <p>Delete the link key associated with the remote device, and 1002 * immediately terminate connections to that device that require 1003 * authentication and encryption. 1004 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 1005 * 1006 * @return true on success, false on error 1007 * @hide 1008 */ removeBond()1009 public boolean removeBond() { 1010 if (sService == null) { 1011 Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond"); 1012 return false; 1013 } 1014 try { 1015 Log.i(TAG, "removeBond() for device " + getAddress() + 1016 " called by pid: " + Process.myPid() + 1017 " tid: " + Process.myTid()); 1018 return sService.removeBond(this); 1019 } catch (RemoteException e) {Log.e(TAG, "", e);} 1020 return false; 1021 } 1022 1023 /** 1024 * Get the bond state of the remote device. 1025 * <p>Possible values for the bond state are: 1026 * {@link #BOND_NONE}, 1027 * {@link #BOND_BONDING}, 1028 * {@link #BOND_BONDED}. 1029 * 1030 * @return the bond state 1031 */ 1032 @RequiresPermission(Manifest.permission.BLUETOOTH) getBondState()1033 public int getBondState() { 1034 if (sService == null) { 1035 Log.e(TAG, "BT not enabled. Cannot get bond state"); 1036 return BOND_NONE; 1037 } 1038 try { 1039 return sService.getBondState(this); 1040 } catch (RemoteException e) {Log.e(TAG, "", e);} 1041 catch (NullPointerException npe) { 1042 // Handle case where bluetooth service proxy 1043 // is already null. 1044 Log.e(TAG, "NullPointerException for getBondState() of device ("+ 1045 getAddress()+")", npe); 1046 } 1047 return BOND_NONE; 1048 } 1049 1050 /** 1051 * Returns whether there is an open connection to this device. 1052 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 1053 * 1054 * @return True if there is at least one open connection to this device. 1055 * @hide 1056 */ 1057 @SystemApi isConnected()1058 public boolean isConnected() { 1059 if (sService == null) { 1060 // BT is not enabled, we cannot be connected. 1061 return false; 1062 } 1063 try { 1064 return sService.getConnectionState(this) != CONNECTION_STATE_DISCONNECTED; 1065 } catch (RemoteException e) { 1066 Log.e(TAG, "", e); 1067 return false; 1068 } 1069 } 1070 1071 /** 1072 * Returns whether there is an open connection to this device 1073 * that has been encrypted. 1074 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 1075 * 1076 * @return True if there is at least one encrypted connection to this device. 1077 * @hide 1078 */ 1079 @SystemApi isEncrypted()1080 public boolean isEncrypted() { 1081 if (sService == null) { 1082 // BT is not enabled, we cannot be connected. 1083 return false; 1084 } 1085 try { 1086 return sService.getConnectionState(this) > CONNECTION_STATE_CONNECTED; 1087 } catch (RemoteException e) { 1088 Log.e(TAG, "", e); 1089 return false; 1090 } 1091 } 1092 1093 /** 1094 * Get the Bluetooth class of the remote device. 1095 * 1096 * @return Bluetooth class object, or null on error 1097 */ 1098 @RequiresPermission(Manifest.permission.BLUETOOTH) getBluetoothClass()1099 public BluetoothClass getBluetoothClass() { 1100 if (sService == null) { 1101 Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class"); 1102 return null; 1103 } 1104 try { 1105 int classInt = sService.getRemoteClass(this); 1106 if (classInt == BluetoothClass.ERROR) return null; 1107 return new BluetoothClass(classInt); 1108 } catch (RemoteException e) {Log.e(TAG, "", e);} 1109 return null; 1110 } 1111 1112 /** 1113 * Returns the supported features (UUIDs) of the remote device. 1114 * 1115 * <p>This method does not start a service discovery procedure to retrieve the UUIDs 1116 * from the remote device. Instead, the local cached copy of the service 1117 * UUIDs are returned. 1118 * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired. 1119 * 1120 * @return the supported features (UUIDs) of the remote device, 1121 * or null on error 1122 */ 1123 @RequiresPermission(Manifest.permission.BLUETOOTH) getUuids()1124 public ParcelUuid[] getUuids() { 1125 if (sService == null || isBluetoothEnabled() == false) { 1126 Log.e(TAG, "BT not enabled. Cannot get remote device Uuids"); 1127 return null; 1128 } 1129 try { 1130 return sService.getRemoteUuids(this); 1131 } catch (RemoteException e) {Log.e(TAG, "", e);} 1132 return null; 1133 } 1134 1135 /** 1136 * Perform a service discovery on the remote device to get the UUIDs supported. 1137 * 1138 * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent, 1139 * with the UUIDs supported by the remote end. If there is an error 1140 * in getting the SDP records or if the process takes a long time, 1141 * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently 1142 * present in the cache. Clients should use the {@link #getUuids} to get UUIDs 1143 * if service discovery is not to be performed. 1144 * 1145 * @return False if the sanity check fails, True if the process 1146 * of initiating an ACL connection to the remote device 1147 * was started. 1148 */ 1149 @RequiresPermission(Manifest.permission.BLUETOOTH) fetchUuidsWithSdp()1150 public boolean fetchUuidsWithSdp() { 1151 IBluetooth service = sService; 1152 if (service == null || isBluetoothEnabled() == false) { 1153 Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp"); 1154 return false; 1155 } 1156 try { 1157 return service.fetchRemoteUuids(this); 1158 } catch (RemoteException e) {Log.e(TAG, "", e);} 1159 return false; 1160 } 1161 1162 /** 1163 * Perform a service discovery on the remote device to get the SDP records associated 1164 * with the specified UUID. 1165 * 1166 * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent, 1167 * with the SDP records found on the remote end. If there is an error 1168 * in getting the SDP records or if the process takes a long time, 1169 * {@link #ACTION_SDP_RECORD} intent is sent with an status value in 1170 * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0. 1171 * Detailed status error codes can be found by members of the Bluetooth package in 1172 * the AbstractionLayer class. 1173 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 1174 * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}. 1175 * The object type will match one of the SdpXxxRecord types, depending on the UUID searched 1176 * for. 1177 * 1178 * @return False if the sanity check fails, True if the process 1179 * of initiating an ACL connection to the remote device 1180 * was started. 1181 */ 1182 /** @hide */ sdpSearch(ParcelUuid uuid)1183 public boolean sdpSearch(ParcelUuid uuid) { 1184 if (sService == null) { 1185 Log.e(TAG, "BT not enabled. Cannot query remote device sdp records"); 1186 return false; 1187 } 1188 try { 1189 return sService.sdpSearch(this,uuid); 1190 } catch (RemoteException e) {Log.e(TAG, "", e);} 1191 return false; 1192 } 1193 1194 /** 1195 * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} 1196 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 1197 * 1198 * @return true pin has been set 1199 * false for error 1200 */ setPin(byte[] pin)1201 public boolean setPin(byte[] pin) { 1202 if (sService == null) { 1203 Log.e(TAG, "BT not enabled. Cannot set Remote Device pin"); 1204 return false; 1205 } 1206 try { 1207 return sService.setPin(this, true, pin.length, pin); 1208 } catch (RemoteException e) {Log.e(TAG, "", e);} 1209 return false; 1210 } 1211 1212 /** @hide */ setPasskey(int passkey)1213 public boolean setPasskey(int passkey) { 1214 //TODO(BT) 1215 /* 1216 try { 1217 return sService.setPasskey(this, true, 4, passkey); 1218 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 1219 return false; 1220 } 1221 1222 /** 1223 * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing. 1224 * 1225 * @return true confirmation has been sent out 1226 * false for error 1227 */ 1228 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) setPairingConfirmation(boolean confirm)1229 public boolean setPairingConfirmation(boolean confirm) { 1230 if (sService == null) { 1231 Log.e(TAG, "BT not enabled. Cannot set pairing confirmation"); 1232 return false; 1233 } 1234 try { 1235 return sService.setPairingConfirmation(this, confirm); 1236 } catch (RemoteException e) {Log.e(TAG, "", e);} 1237 return false; 1238 } 1239 1240 /** @hide */ setRemoteOutOfBandData()1241 public boolean setRemoteOutOfBandData() { 1242 // TODO(BT) 1243 /* 1244 try { 1245 return sService.setRemoteOutOfBandData(this); 1246 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 1247 return false; 1248 } 1249 1250 /** @hide */ cancelPairingUserInput()1251 public boolean cancelPairingUserInput() { 1252 if (sService == null) { 1253 Log.e(TAG, "BT not enabled. Cannot create pairing user input"); 1254 return false; 1255 } 1256 try { 1257 return sService.cancelBondProcess(this); 1258 } catch (RemoteException e) {Log.e(TAG, "", e);} 1259 return false; 1260 } 1261 1262 /** @hide */ isBluetoothDock()1263 public boolean isBluetoothDock() { 1264 // TODO(BT) 1265 /* 1266 try { 1267 return sService.isBluetoothDock(this); 1268 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 1269 return false; 1270 } 1271 isBluetoothEnabled()1272 boolean isBluetoothEnabled() { 1273 boolean ret = false; 1274 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1275 if (adapter != null && adapter.isEnabled() == true) { 1276 ret = true; 1277 } 1278 return ret; 1279 } 1280 1281 /** 1282 * Requires {@link android.Manifest.permission#BLUETOOTH}. 1283 * @return Whether the phonebook access is allowed to this device. Can be 1284 * {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. 1285 * @hide 1286 */ getPhonebookAccessPermission()1287 public int getPhonebookAccessPermission() { 1288 if (sService == null) { 1289 return ACCESS_UNKNOWN; 1290 } 1291 try { 1292 return sService.getPhonebookAccessPermission(this); 1293 } catch (RemoteException e) { 1294 Log.e(TAG, "", e); 1295 } 1296 return ACCESS_UNKNOWN; 1297 } 1298 1299 /** 1300 * Sets whether the phonebook access is allowed to this device. 1301 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. 1302 * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or 1303 * {@link #ACCESS_REJECTED}. 1304 * @return Whether the value has been successfully set. 1305 * @hide 1306 */ setPhonebookAccessPermission(int value)1307 public boolean setPhonebookAccessPermission(int value) { 1308 if (sService == null) { 1309 return false; 1310 } 1311 try { 1312 return sService.setPhonebookAccessPermission(this, value); 1313 } catch (RemoteException e) { 1314 Log.e(TAG, "", e); 1315 } 1316 return false; 1317 } 1318 1319 /** 1320 * Requires {@link android.Manifest.permission#BLUETOOTH}. 1321 * @return Whether the message access is allowed to this device. Can be 1322 * {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. 1323 * @hide 1324 */ getMessageAccessPermission()1325 public int getMessageAccessPermission() { 1326 if (sService == null) { 1327 return ACCESS_UNKNOWN; 1328 } 1329 try { 1330 return sService.getMessageAccessPermission(this); 1331 } catch (RemoteException e) { 1332 Log.e(TAG, "", e); 1333 } 1334 return ACCESS_UNKNOWN; 1335 } 1336 1337 /** 1338 * Sets whether the message access is allowed to this device. 1339 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. 1340 * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or 1341 * {@link #ACCESS_REJECTED}. 1342 * @return Whether the value has been successfully set. 1343 * @hide 1344 */ setMessageAccessPermission(int value)1345 public boolean setMessageAccessPermission(int value) { 1346 if (sService == null) { 1347 return false; 1348 } 1349 try { 1350 return sService.setMessageAccessPermission(this, value); 1351 } catch (RemoteException e) { 1352 Log.e(TAG, "", e); 1353 } 1354 return false; 1355 } 1356 1357 /** 1358 * Requires {@link android.Manifest.permission#BLUETOOTH}. 1359 * @return Whether the Sim access is allowed to this device. Can be 1360 * {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. 1361 * @hide 1362 */ getSimAccessPermission()1363 public int getSimAccessPermission() { 1364 if (sService == null) { 1365 return ACCESS_UNKNOWN; 1366 } 1367 try { 1368 return sService.getSimAccessPermission(this); 1369 } catch (RemoteException e) { 1370 Log.e(TAG, "", e); 1371 } 1372 return ACCESS_UNKNOWN; 1373 } 1374 1375 /** 1376 * Sets whether the Sim access is allowed to this device. 1377 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. 1378 * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or 1379 * {@link #ACCESS_REJECTED}. 1380 * @return Whether the value has been successfully set. 1381 * @hide 1382 */ setSimAccessPermission(int value)1383 public boolean setSimAccessPermission(int value) { 1384 if (sService == null) { 1385 return false; 1386 } 1387 try { 1388 return sService.setSimAccessPermission(this, value); 1389 } catch (RemoteException e) { 1390 Log.e(TAG, "", e); 1391 } 1392 return false; 1393 } 1394 1395 /** 1396 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 1397 * outgoing connection to this remote device on given channel. 1398 * <p>The remote device will be authenticated and communication on this 1399 * socket will be encrypted. 1400 * <p> Use this socket only if an authenticated socket link is possible. 1401 * Authentication refers to the authentication of the link key to 1402 * prevent man-in-the-middle type of attacks. 1403 * For example, for Bluetooth 2.1 devices, if any of the devices does not 1404 * have an input and output capability or just has the ability to 1405 * display a numeric key, a secure socket connection is not possible. 1406 * In such a case, use {#link createInsecureRfcommSocket}. 1407 * For more details, refer to the Security Model section 5.2 (vol 3) of 1408 * Bluetooth Core Specification version 2.1 + EDR. 1409 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1410 * connection. 1411 * <p>Valid RFCOMM channels are in range 1 to 30. 1412 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1413 * 1414 * @param channel RFCOMM channel to connect to 1415 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1416 * @throws IOException on error, for example Bluetooth not available, or 1417 * insufficient permissions 1418 * @hide 1419 */ createRfcommSocket(int channel)1420 public BluetoothSocket createRfcommSocket(int channel) throws IOException { 1421 if (isBluetoothEnabled() == false) { 1422 Log.e(TAG, "Bluetooth is not enabled"); 1423 throw new IOException(); 1424 } 1425 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel, 1426 null); 1427 } 1428 1429 /** 1430 * Create an L2cap {@link BluetoothSocket} ready to start a secure 1431 * outgoing connection to this remote device on given channel. 1432 * <p>The remote device will be authenticated and communication on this 1433 * socket will be encrypted. 1434 * <p> Use this socket only if an authenticated socket link is possible. 1435 * Authentication refers to the authentication of the link key to 1436 * prevent man-in-the-middle type of attacks. 1437 * For example, for Bluetooth 2.1 devices, if any of the devices does not 1438 * have an input and output capability or just has the ability to 1439 * display a numeric key, a secure socket connection is not possible. 1440 * In such a case, use {#link createInsecureRfcommSocket}. 1441 * For more details, refer to the Security Model section 5.2 (vol 3) of 1442 * Bluetooth Core Specification version 2.1 + EDR. 1443 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1444 * connection. 1445 * <p>Valid L2CAP PSM channels are in range 1 to 2^16. 1446 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1447 * 1448 * @param channel L2cap PSM/channel to connect to 1449 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1450 * @throws IOException on error, for example Bluetooth not available, or 1451 * insufficient permissions 1452 * @hide 1453 */ createL2capSocket(int channel)1454 public BluetoothSocket createL2capSocket(int channel) throws IOException { 1455 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel, 1456 null); 1457 } 1458 1459 /** 1460 * Create an L2cap {@link BluetoothSocket} ready to start an insecure 1461 * outgoing connection to this remote device on given channel. 1462 * <p>The remote device will be not authenticated and communication on this 1463 * socket will not be encrypted. 1464 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1465 * connection. 1466 * <p>Valid L2CAP PSM channels are in range 1 to 2^16. 1467 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1468 * 1469 * @param channel L2cap PSM/channel to connect to 1470 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1471 * @throws IOException on error, for example Bluetooth not available, or 1472 * insufficient permissions 1473 * @hide 1474 */ createInsecureL2capSocket(int channel)1475 public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException { 1476 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel, 1477 null); 1478 } 1479 1480 /** 1481 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 1482 * outgoing connection to this remote device using SDP lookup of uuid. 1483 * <p>This is designed to be used with {@link 1484 * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer 1485 * Bluetooth applications. 1486 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1487 * connection. This will also perform an SDP lookup of the given uuid to 1488 * determine which channel to connect to. 1489 * <p>The remote device will be authenticated and communication on this 1490 * socket will be encrypted. 1491 * <p> Use this socket only if an authenticated socket link is possible. 1492 * Authentication refers to the authentication of the link key to 1493 * prevent man-in-the-middle type of attacks. 1494 * For example, for Bluetooth 2.1 devices, if any of the devices does not 1495 * have an input and output capability or just has the ability to 1496 * display a numeric key, a secure socket connection is not possible. 1497 * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}. 1498 * For more details, refer to the Security Model section 5.2 (vol 3) of 1499 * Bluetooth Core Specification version 2.1 + EDR. 1500 * <p>Hint: If you are connecting to a Bluetooth serial board then try 1501 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 1502 * However if you are connecting to an Android peer then please generate 1503 * your own unique UUID. 1504 * 1505 * @param uuid service record uuid to lookup RFCOMM channel 1506 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1507 * @throws IOException on error, for example Bluetooth not available, or 1508 * insufficient permissions 1509 */ 1510 @RequiresPermission(Manifest.permission.BLUETOOTH) createRfcommSocketToServiceRecord(UUID uuid)1511 public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException { 1512 if (isBluetoothEnabled() == false) { 1513 Log.e(TAG, "Bluetooth is not enabled"); 1514 throw new IOException(); 1515 } 1516 1517 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1, 1518 new ParcelUuid(uuid)); 1519 } 1520 1521 /** 1522 * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure 1523 * outgoing connection to this remote device using SDP lookup of uuid. 1524 * <p> The communication channel will not have an authenticated link key 1525 * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1 1526 * devices, the link key will be encrypted, as encryption is mandatory. 1527 * For legacy devices (pre Bluetooth 2.1 devices) the link key will 1528 * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an 1529 * encrypted and authenticated communication channel is desired. 1530 * <p>This is designed to be used with {@link 1531 * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer 1532 * Bluetooth applications. 1533 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1534 * connection. This will also perform an SDP lookup of the given uuid to 1535 * determine which channel to connect to. 1536 * <p>The remote device will be authenticated and communication on this 1537 * socket will be encrypted. 1538 * <p>Hint: If you are connecting to a Bluetooth serial board then try 1539 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 1540 * However if you are connecting to an Android peer then please generate 1541 * your own unique UUID. 1542 * 1543 * @param uuid service record uuid to lookup RFCOMM channel 1544 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1545 * @throws IOException on error, for example Bluetooth not available, or 1546 * insufficient permissions 1547 */ 1548 @RequiresPermission(Manifest.permission.BLUETOOTH) createInsecureRfcommSocketToServiceRecord(UUID uuid)1549 public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException { 1550 if (isBluetoothEnabled() == false) { 1551 Log.e(TAG, "Bluetooth is not enabled"); 1552 throw new IOException(); 1553 } 1554 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1, 1555 new ParcelUuid(uuid)); 1556 } 1557 1558 /** 1559 * Construct an insecure RFCOMM socket ready to start an outgoing 1560 * connection. 1561 * Call #connect on the returned #BluetoothSocket to begin the connection. 1562 * The remote device will not be authenticated and communication on this 1563 * socket will not be encrypted. 1564 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 1565 * 1566 * @param port remote port 1567 * @return An RFCOMM BluetoothSocket 1568 * @throws IOException On error, for example Bluetooth not available, or 1569 * insufficient permissions. 1570 * @hide 1571 */ createInsecureRfcommSocket(int port)1572 public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException { 1573 1574 if (isBluetoothEnabled() == false) { 1575 Log.e(TAG, "Bluetooth is not enabled"); 1576 throw new IOException(); 1577 } 1578 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port, 1579 null); 1580 } 1581 1582 /** 1583 * Construct a SCO socket ready to start an outgoing connection. 1584 * Call #connect on the returned #BluetoothSocket to begin the connection. 1585 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 1586 * 1587 * @return a SCO BluetoothSocket 1588 * @throws IOException on error, for example Bluetooth not available, or 1589 * insufficient permissions. 1590 * @hide 1591 */ createScoSocket()1592 public BluetoothSocket createScoSocket() throws IOException { 1593 1594 if (isBluetoothEnabled() == false) { 1595 Log.e(TAG, "Bluetooth is not enabled"); 1596 throw new IOException(); 1597 } 1598 return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null); 1599 } 1600 1601 /** 1602 * Check that a pin is valid and convert to byte array. 1603 * 1604 * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters. 1605 * @param pin pin as java String 1606 * @return the pin code as a UTF-8 byte array, or null if it is an invalid 1607 * Bluetooth pin. 1608 * @hide 1609 */ convertPinToBytes(String pin)1610 public static byte[] convertPinToBytes(String pin) { 1611 if (pin == null) { 1612 return null; 1613 } 1614 byte[] pinBytes; 1615 try { 1616 pinBytes = pin.getBytes("UTF-8"); 1617 } catch (UnsupportedEncodingException uee) { 1618 Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen 1619 return null; 1620 } 1621 if (pinBytes.length <= 0 || pinBytes.length > 16) { 1622 return null; 1623 } 1624 return pinBytes; 1625 } 1626 1627 /** 1628 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 1629 * The callback is used to deliver results to Caller, such as connection status as well 1630 * as any further GATT client operations. 1631 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 1632 * GATT client operations. 1633 * @param callback GATT callback handler that will receive asynchronous callbacks. 1634 * @param autoConnect Whether to directly connect to the remote device (false) 1635 * or to automatically connect as soon as the remote 1636 * device becomes available (true). 1637 * @throws IllegalArgumentException if callback is null 1638 */ connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)1639 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 1640 BluetoothGattCallback callback) { 1641 return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO)); 1642 } 1643 1644 /** 1645 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 1646 * The callback is used to deliver results to Caller, such as connection status as well 1647 * as any further GATT client operations. 1648 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 1649 * GATT client operations. 1650 * @param callback GATT callback handler that will receive asynchronous callbacks. 1651 * @param autoConnect Whether to directly connect to the remote device (false) 1652 * or to automatically connect as soon as the remote 1653 * device becomes available (true). 1654 * @param transport preferred transport for GATT connections to remote dual-mode devices 1655 * {@link BluetoothDevice#TRANSPORT_AUTO} or 1656 * {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE} 1657 * @throws IllegalArgumentException if callback is null 1658 */ connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)1659 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 1660 BluetoothGattCallback callback, int transport) { 1661 return (connectGatt(context, autoConnect,callback, transport, PHY_LE_1M_MASK)); 1662 } 1663 1664 /** 1665 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 1666 * The callback is used to deliver results to Caller, such as connection status as well 1667 * as any further GATT client operations. 1668 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 1669 * GATT client operations. 1670 * @param callback GATT callback handler that will receive asynchronous callbacks. 1671 * @param autoConnect Whether to directly connect to the remote device (false) 1672 * or to automatically connect as soon as the remote 1673 * device becomes available (true). 1674 * @param transport preferred transport for GATT connections to remote dual-mode devices 1675 * {@link BluetoothDevice#TRANSPORT_AUTO} or 1676 * {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE} 1677 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of 1678 * {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, 1679 * and {@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect 1680 * if {@code autoConnect} is set to true. 1681 * @throws NullPointerException if callback is null 1682 */ connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy)1683 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 1684 BluetoothGattCallback callback, int transport, int phy) { 1685 return connectGatt(context, autoConnect,callback, transport, phy, null); 1686 } 1687 1688 /** 1689 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 1690 * The callback is used to deliver results to Caller, such as connection status as well 1691 * as any further GATT client operations. 1692 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 1693 * GATT client operations. 1694 * @param callback GATT callback handler that will receive asynchronous callbacks. 1695 * @param autoConnect Whether to directly connect to the remote device (false) 1696 * or to automatically connect as soon as the remote 1697 * device becomes available (true). 1698 * @param transport preferred transport for GATT connections to remote dual-mode devices 1699 * {@link BluetoothDevice#TRANSPORT_AUTO} or 1700 * {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE} 1701 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of 1702 * {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, 1703 * an d{@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect 1704 * if {@code autoConnect} is set to true. 1705 * @param handler The handler to use for the callback. If {@code null}, callbacks will happen 1706 * on an un-specified background thread. 1707 * @throws NullPointerException if callback is null 1708 */ connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler)1709 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 1710 BluetoothGattCallback callback, int transport, int phy, 1711 Handler handler) { 1712 if (callback == null) 1713 throw new NullPointerException("callback is null"); 1714 1715 // TODO(Bluetooth) check whether platform support BLE 1716 // Do the check here or in GattServer? 1717 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1718 IBluetoothManager managerService = adapter.getBluetoothManager(); 1719 try { 1720 IBluetoothGatt iGatt = managerService.getBluetoothGatt(); 1721 if (iGatt == null) { 1722 // BLE is not supported 1723 return null; 1724 } 1725 BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport, phy); 1726 gatt.connect(autoConnect, callback, handler); 1727 return gatt; 1728 } catch (RemoteException e) {Log.e(TAG, "", e);} 1729 return null; 1730 } 1731 } 1732