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