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