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