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.annotation.SdkConstant; 20 import android.annotation.SdkConstant.SdkConstantType; 21 import android.os.IBinder; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.os.ParcelUuid; 25 import android.os.RemoteException; 26 import android.os.ServiceManager; 27 import android.util.Log; 28 29 import java.io.IOException; 30 import java.io.UnsupportedEncodingException; 31 import java.util.UUID; 32 33 /** 34 * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you 35 * create a connection with the respective device or query information about 36 * it, such as the name, address, class, and bonding state. 37 * 38 * <p>This class is really just a thin wrapper for a Bluetooth hardware 39 * address. Objects of this class are immutable. Operations on this class 40 * are performed on the remote Bluetooth hardware address, using the 41 * {@link BluetoothAdapter} that was used to create this {@link 42 * BluetoothDevice}. 43 * 44 * <p>To get a {@link BluetoothDevice}, use 45 * {@link BluetoothAdapter#getRemoteDevice(String) 46 * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device 47 * of a known MAC address (which you can get through device discovery with 48 * {@link BluetoothAdapter}) or get one from the set of bonded devices 49 * returned by {@link BluetoothAdapter#getBondedDevices() 50 * BluetoothAdapter.getBondedDevices()}. You can then open a 51 * {@link BluetoothSocket} for communication with the remote device, using 52 * {@link #createRfcommSocketToServiceRecord(UUID)}. 53 * 54 * <p class="note"><strong>Note:</strong> 55 * Requires the {@link android.Manifest.permission#BLUETOOTH} permission. 56 * 57 * <div class="special reference"> 58 * <h3>Developer Guides</h3> 59 * <p>For more information about using Bluetooth, read the 60 * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p> 61 * </div> 62 * 63 * {@see BluetoothAdapter} 64 * {@see BluetoothSocket} 65 */ 66 public final class BluetoothDevice implements Parcelable { 67 private static final String TAG = "BluetoothDevice"; 68 69 /** 70 * Sentinel error value for this class. Guaranteed to not equal any other 71 * integer constant in this class. Provided as a convenience for functions 72 * that require a sentinel error value, for example: 73 * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 74 * BluetoothDevice.ERROR)</code> 75 */ 76 public static final int ERROR = Integer.MIN_VALUE; 77 78 /** 79 * Broadcast Action: Remote device discovered. 80 * <p>Sent when a remote device is found during discovery. 81 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 82 * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or 83 * {@link #EXTRA_RSSI} if they are available. 84 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 85 */ 86 // TODO: Change API to not broadcast RSSI if not available (incoming connection) 87 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 88 public static final String ACTION_FOUND = 89 "android.bluetooth.device.action.FOUND"; 90 91 /** 92 * Broadcast Action: Remote device disappeared. 93 * <p>Sent when a remote device that was found in the last discovery is not 94 * found in the current discovery. 95 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 96 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 97 * @hide 98 */ 99 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 100 public static final String ACTION_DISAPPEARED = 101 "android.bluetooth.device.action.DISAPPEARED"; 102 103 /** 104 * Broadcast Action: Bluetooth class of a remote device has changed. 105 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 106 * #EXTRA_CLASS}. 107 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 108 * @see {@link BluetoothClass} 109 */ 110 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 111 public static final String ACTION_CLASS_CHANGED = 112 "android.bluetooth.device.action.CLASS_CHANGED"; 113 114 /** 115 * Broadcast Action: Indicates a low level (ACL) connection has been 116 * established with a remote device. 117 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 118 * <p>ACL connections are managed automatically by the Android Bluetooth 119 * stack. 120 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 121 */ 122 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 123 public static final String ACTION_ACL_CONNECTED = 124 "android.bluetooth.device.action.ACL_CONNECTED"; 125 126 /** 127 * Broadcast Action: Indicates that a low level (ACL) disconnection has 128 * been requested for a remote device, and it will soon be disconnected. 129 * <p>This is useful for graceful disconnection. Applications should use 130 * this intent as a hint to immediately terminate higher level connections 131 * (RFCOMM, L2CAP, or profile connections) to the remote device. 132 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 133 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 134 */ 135 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 136 public static final String ACTION_ACL_DISCONNECT_REQUESTED = 137 "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED"; 138 139 /** 140 * Broadcast Action: Indicates a low level (ACL) disconnection from a 141 * remote device. 142 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 143 * <p>ACL connections are managed automatically by the Android Bluetooth 144 * stack. 145 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 146 */ 147 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 148 public static final String ACTION_ACL_DISCONNECTED = 149 "android.bluetooth.device.action.ACL_DISCONNECTED"; 150 151 /** 152 * Broadcast Action: Indicates the friendly name of a remote device has 153 * been retrieved for the first time, or changed since the last retrieval. 154 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 155 * #EXTRA_NAME}. 156 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 157 */ 158 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 159 public static final String ACTION_NAME_CHANGED = 160 "android.bluetooth.device.action.NAME_CHANGED"; 161 162 /** 163 * Broadcast Action: Indicates a change in the bond state of a remote 164 * device. For example, if a device is bonded (paired). 165 * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link 166 * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}. 167 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 168 */ 169 // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also 170 // contain a hidden extra field EXTRA_REASON with the result code. 171 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 172 public static final String ACTION_BOND_STATE_CHANGED = 173 "android.bluetooth.device.action.BOND_STATE_CHANGED"; 174 175 /** 176 * Used as a Parcelable {@link BluetoothDevice} extra field in every intent 177 * broadcast by this class. It contains the {@link BluetoothDevice} that 178 * the intent applies to. 179 */ 180 public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE"; 181 182 /** 183 * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link 184 * #ACTION_FOUND} intents. It contains the friendly Bluetooth name. 185 */ 186 public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME"; 187 188 /** 189 * Used as an optional short extra field in {@link #ACTION_FOUND} intents. 190 * Contains the RSSI value of the remote device as reported by the 191 * Bluetooth hardware. 192 */ 193 public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI"; 194 195 /** 196 * Used as an Parcelable {@link BluetoothClass} extra field in {@link 197 * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents. 198 */ 199 public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS"; 200 201 /** 202 * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. 203 * Contains the bond state of the remote device. 204 * <p>Possible values are: 205 * {@link #BOND_NONE}, 206 * {@link #BOND_BONDING}, 207 * {@link #BOND_BONDED}. 208 */ 209 public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE"; 210 /** 211 * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. 212 * Contains the previous bond state of the remote device. 213 * <p>Possible values are: 214 * {@link #BOND_NONE}, 215 * {@link #BOND_BONDING}, 216 * {@link #BOND_BONDED}. 217 */ 218 public static final String EXTRA_PREVIOUS_BOND_STATE = 219 "android.bluetooth.device.extra.PREVIOUS_BOND_STATE"; 220 /** 221 * Indicates the remote device is not bonded (paired). 222 * <p>There is no shared link key with the remote device, so communication 223 * (if it is allowed at all) will be unauthenticated and unencrypted. 224 */ 225 public static final int BOND_NONE = 10; 226 /** 227 * Indicates bonding (pairing) is in progress with the remote device. 228 */ 229 public static final int BOND_BONDING = 11; 230 /** 231 * Indicates the remote device is bonded (paired). 232 * <p>A shared link keys exists locally for the remote device, so 233 * communication can be authenticated and encrypted. 234 * <p><i>Being bonded (paired) with a remote device does not necessarily 235 * mean the device is currently connected. It just means that the pending 236 * procedure was completed at some earlier time, and the link key is still 237 * stored locally, ready to use on the next connection. 238 * </i> 239 */ 240 public static final int BOND_BONDED = 12; 241 242 /** @hide */ 243 public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON"; 244 /** @hide */ 245 public static final String EXTRA_PAIRING_VARIANT = 246 "android.bluetooth.device.extra.PAIRING_VARIANT"; 247 /** @hide */ 248 public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY"; 249 250 /** 251 * Broadcast Action: This intent is used to broadcast the {@link UUID} 252 * wrapped as a {@link android.os.ParcelUuid} of the remote device after it 253 * has been fetched. This intent is sent only when the UUIDs of the remote 254 * device are requested to be fetched using Service Discovery Protocol 255 * <p> Always contains the extra field {@link #EXTRA_DEVICE} 256 * <p> Always contains the extra field {@link #EXTRA_UUID} 257 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 258 */ 259 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 260 public static final String ACTION_UUID = 261 "android.bluetooth.device.action.UUID"; 262 263 /** 264 * Broadcast Action: Indicates a failure to retrieve the name of a remote 265 * device. 266 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 267 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 268 * @hide 269 */ 270 //TODO: is this actually useful? 271 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 272 public static final String ACTION_NAME_FAILED = 273 "android.bluetooth.device.action.NAME_FAILED"; 274 275 /** @hide */ 276 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 277 public static final String ACTION_PAIRING_REQUEST = 278 "android.bluetooth.device.action.PAIRING_REQUEST"; 279 /** @hide */ 280 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 281 public static final String ACTION_PAIRING_CANCEL = 282 "android.bluetooth.device.action.PAIRING_CANCEL"; 283 284 /** @hide */ 285 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 286 public static final String ACTION_CONNECTION_ACCESS_REQUEST = 287 "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST"; 288 289 /** @hide */ 290 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 291 public static final String ACTION_CONNECTION_ACCESS_REPLY = 292 "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY"; 293 294 /** @hide */ 295 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 296 public static final String ACTION_CONNECTION_ACCESS_CANCEL = 297 "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL"; 298 299 /** 300 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent. 301 * @hide 302 */ 303 public static final String EXTRA_ACCESS_REQUEST_TYPE = 304 "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE"; 305 306 /**@hide*/ 307 public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1; 308 309 /**@hide*/ 310 public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2; 311 312 /** 313 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, 314 * Contains package name to return reply intent to. 315 * @hide 316 */ 317 public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME"; 318 319 /** 320 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, 321 * Contains class name to return reply intent to. 322 * @hide 323 */ 324 public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME"; 325 326 /** 327 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent. 328 * @hide 329 */ 330 public static final String EXTRA_CONNECTION_ACCESS_RESULT = 331 "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT"; 332 333 /**@hide*/ 334 public static final int CONNECTION_ACCESS_YES = 1; 335 336 /**@hide*/ 337 public static final int CONNECTION_ACCESS_NO = 2; 338 339 /** 340 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents, 341 * Contains boolean to indicate if the allowed response is once-for-all so that 342 * next request will be granted without asking user again. 343 * @hide 344 */ 345 public static final String EXTRA_ALWAYS_ALLOWED = 346 "android.bluetooth.device.extra.ALWAYS_ALLOWED"; 347 348 /** 349 * A bond attempt succeeded 350 * @hide 351 */ 352 public static final int BOND_SUCCESS = 0; 353 354 /** 355 * A bond attempt failed because pins did not match, or remote device did 356 * not respond to pin request in time 357 * @hide 358 */ 359 public static final int UNBOND_REASON_AUTH_FAILED = 1; 360 361 /** 362 * A bond attempt failed because the other side explicitly rejected 363 * bonding 364 * @hide 365 */ 366 public static final int UNBOND_REASON_AUTH_REJECTED = 2; 367 368 /** 369 * A bond attempt failed because we canceled the bonding process 370 * @hide 371 */ 372 public static final int UNBOND_REASON_AUTH_CANCELED = 3; 373 374 /** 375 * A bond attempt failed because we could not contact the remote device 376 * @hide 377 */ 378 public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4; 379 380 /** 381 * A bond attempt failed because a discovery is in progress 382 * @hide 383 */ 384 public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5; 385 386 /** 387 * A bond attempt failed because of authentication timeout 388 * @hide 389 */ 390 public static final int UNBOND_REASON_AUTH_TIMEOUT = 6; 391 392 /** 393 * A bond attempt failed because of repeated attempts 394 * @hide 395 */ 396 public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7; 397 398 /** 399 * A bond attempt failed because we received an Authentication Cancel 400 * by remote end 401 * @hide 402 */ 403 public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8; 404 405 /** 406 * An existing bond was explicitly revoked 407 * @hide 408 */ 409 public static final int UNBOND_REASON_REMOVED = 9; 410 411 /** 412 * The user will be prompted to enter a pin 413 * @hide 414 */ 415 public static final int PAIRING_VARIANT_PIN = 0; 416 417 /** 418 * The user will be prompted to enter a passkey 419 * @hide 420 */ 421 public static final int PAIRING_VARIANT_PASSKEY = 1; 422 423 /** 424 * The user will be prompted to confirm the passkey displayed on the screen 425 * @hide 426 */ 427 public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2; 428 429 /** 430 * The user will be prompted to accept or deny the incoming pairing request 431 * @hide 432 */ 433 public static final int PAIRING_VARIANT_CONSENT = 3; 434 435 /** 436 * The user will be prompted to enter the passkey displayed on remote device 437 * This is used for Bluetooth 2.1 pairing. 438 * @hide 439 */ 440 public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4; 441 442 /** 443 * The user will be prompted to enter the PIN displayed on remote device. 444 * This is used for Bluetooth 2.0 pairing. 445 * @hide 446 */ 447 public static final int PAIRING_VARIANT_DISPLAY_PIN = 5; 448 449 /** 450 * The user will be prompted to accept or deny the OOB pairing request 451 * @hide 452 */ 453 public static final int PAIRING_VARIANT_OOB_CONSENT = 6; 454 455 /** 456 * Used as an extra field in {@link #ACTION_UUID} intents, 457 * Contains the {@link android.os.ParcelUuid}s of the remote device which 458 * is a parcelable version of {@link UUID}. 459 */ 460 public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID"; 461 462 /** 463 * Lazy initialization. Guaranteed final after first object constructed, or 464 * getService() called. 465 * TODO: Unify implementation of sService amongst BluetoothFoo API's 466 */ 467 private static IBluetooth sService; 468 469 private final String mAddress; 470 471 /*package*/ static IBluetooth getService() { 472 synchronized (BluetoothDevice.class) { 473 if (sService == null) { 474 IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE); 475 if (b == null) { 476 throw new RuntimeException("Bluetooth service not available"); 477 } 478 sService = IBluetooth.Stub.asInterface(b); 479 } 480 } 481 return sService; 482 } 483 484 /** 485 * Create a new BluetoothDevice 486 * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB", 487 * and is validated in this constructor. 488 * @param address valid Bluetooth MAC address 489 * @throws RuntimeException Bluetooth is not available on this platform 490 * @throws IllegalArgumentException address is invalid 491 * @hide 492 */ 493 /*package*/ BluetoothDevice(String address) { 494 getService(); // ensures sService is initialized 495 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 496 throw new IllegalArgumentException(address + " is not a valid Bluetooth address"); 497 } 498 499 mAddress = address; 500 } 501 502 @Override 503 public boolean equals(Object o) { 504 if (o instanceof BluetoothDevice) { 505 return mAddress.equals(((BluetoothDevice)o).getAddress()); 506 } 507 return false; 508 } 509 510 @Override 511 public int hashCode() { 512 return mAddress.hashCode(); 513 } 514 515 /** 516 * Returns a string representation of this BluetoothDevice. 517 * <p>Currently this is the Bluetooth hardware address, for example 518 * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress} 519 * if you explicitly require the Bluetooth hardware address in case the 520 * {@link #toString} representation changes in the future. 521 * @return string representation of this BluetoothDevice 522 */ 523 @Override 524 public String toString() { 525 return mAddress; 526 } 527 528 public int describeContents() { 529 return 0; 530 } 531 532 public static final Parcelable.Creator<BluetoothDevice> CREATOR = 533 new Parcelable.Creator<BluetoothDevice>() { 534 public BluetoothDevice createFromParcel(Parcel in) { 535 return new BluetoothDevice(in.readString()); 536 } 537 public BluetoothDevice[] newArray(int size) { 538 return new BluetoothDevice[size]; 539 } 540 }; 541 542 public void writeToParcel(Parcel out, int flags) { 543 out.writeString(mAddress); 544 } 545 546 /** 547 * Returns the hardware address of this BluetoothDevice. 548 * <p> For example, "00:11:22:AA:BB:CC". 549 * @return Bluetooth hardware address as string 550 */ 551 public String getAddress() { 552 return mAddress; 553 } 554 555 /** 556 * Get the friendly Bluetooth name of the remote device. 557 * 558 * <p>The local adapter will automatically retrieve remote names when 559 * performing a device scan, and will cache them. This method just returns 560 * the name for this device from the cache. 561 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 562 * 563 * @return the Bluetooth name, or null if there was a problem. 564 */ 565 public String getName() { 566 try { 567 return sService.getRemoteName(mAddress); 568 } catch (RemoteException e) {Log.e(TAG, "", e);} 569 return null; 570 } 571 572 /** 573 * Get the Bluetooth alias of the remote device. 574 * <p>Alias is the locally modified name of a remote device. 575 * 576 * @return the Bluetooth alias, or null if no alias or there was a problem 577 * @hide 578 */ 579 public String getAlias() { 580 try { 581 return sService.getRemoteAlias(mAddress); 582 } catch (RemoteException e) {Log.e(TAG, "", e);} 583 return null; 584 } 585 586 /** 587 * Set the Bluetooth alias of the remote device. 588 * <p>Alias is the locally modified name of a remote device. 589 * <p>This methoid overwrites the alias. The changed 590 * alias is saved in the local storage so that the change 591 * is preserved over power cycle. 592 * 593 * @return true on success, false on error 594 * @hide 595 */ 596 public boolean setAlias(String alias) { 597 try { 598 return sService.setRemoteAlias(mAddress, alias); 599 } catch (RemoteException e) {Log.e(TAG, "", e);} 600 return false; 601 } 602 603 /** 604 * Get the Bluetooth alias of the remote device. 605 * If Alias is null, get the Bluetooth name instead. 606 * @see #getAlias() 607 * @see #getName() 608 * 609 * @return the Bluetooth alias, or null if no alias or there was a problem 610 * @hide 611 */ 612 public String getAliasName() { 613 String name = getAlias(); 614 if (name == null) { 615 name = getName(); 616 } 617 return name; 618 } 619 620 /** 621 * Start the bonding (pairing) process with the remote device. 622 * <p>This is an asynchronous call, it will return immediately. Register 623 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 624 * the bonding process completes, and its result. 625 * <p>Android system services will handle the necessary user interactions 626 * to confirm and complete the bonding process. 627 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 628 * 629 * @return false on immediate error, true if bonding will begin 630 * @hide 631 */ 632 public boolean createBond() { 633 try { 634 return sService.createBond(mAddress); 635 } catch (RemoteException e) {Log.e(TAG, "", e);} 636 return false; 637 } 638 639 /** 640 * Start the bonding (pairing) process with the remote device using the 641 * Out Of Band mechanism. 642 * 643 * <p>This is an asynchronous call, it will return immediately. Register 644 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 645 * the bonding process completes, and its result. 646 * 647 * <p>Android system services will handle the necessary user interactions 648 * to confirm and complete the bonding process. 649 * 650 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 651 * 652 * @param hash - Simple Secure pairing hash 653 * @param randomizer - The random key obtained using OOB 654 * @return false on immediate error, true if bonding will begin 655 * 656 * @hide 657 */ 658 public boolean createBondOutOfBand(byte[] hash, byte[] randomizer) { 659 try { 660 return sService.createBondOutOfBand(mAddress, hash, randomizer); 661 } catch (RemoteException e) {Log.e(TAG, "", e);} 662 return false; 663 } 664 665 /** 666 * Set the Out Of Band data for a remote device to be used later 667 * in the pairing mechanism. Users can obtain this data through other 668 * trusted channels 669 * 670 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 671 * 672 * @param hash Simple Secure pairing hash 673 * @param randomizer The random key obtained using OOB 674 * @return false on error; true otherwise 675 * 676 * @hide 677 */ 678 public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) { 679 try { 680 return sService.setDeviceOutOfBandData(mAddress, hash, randomizer); 681 } catch (RemoteException e) {Log.e(TAG, "", e);} 682 return false; 683 } 684 685 /** 686 * Cancel an in-progress bonding request started with {@link #createBond}. 687 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 688 * 689 * @return true on success, false on error 690 * @hide 691 */ 692 public boolean cancelBondProcess() { 693 try { 694 return sService.cancelBondProcess(mAddress); 695 } catch (RemoteException e) {Log.e(TAG, "", e);} 696 return false; 697 } 698 699 /** 700 * Remove bond (pairing) with the remote device. 701 * <p>Delete the link key associated with the remote device, and 702 * immediately terminate connections to that device that require 703 * authentication and encryption. 704 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 705 * 706 * @return true on success, false on error 707 * @hide 708 */ 709 public boolean removeBond() { 710 try { 711 return sService.removeBond(mAddress); 712 } catch (RemoteException e) {Log.e(TAG, "", e);} 713 return false; 714 } 715 716 /** 717 * Get the bond state of the remote device. 718 * <p>Possible values for the bond state are: 719 * {@link #BOND_NONE}, 720 * {@link #BOND_BONDING}, 721 * {@link #BOND_BONDED}. 722 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 723 * 724 * @return the bond state 725 */ 726 public int getBondState() { 727 try { 728 return sService.getBondState(mAddress); 729 } catch (RemoteException e) {Log.e(TAG, "", e);} 730 return BOND_NONE; 731 } 732 733 /** 734 * Get the Bluetooth class of the remote device. 735 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 736 * 737 * @return Bluetooth class object, or null on error 738 */ 739 public BluetoothClass getBluetoothClass() { 740 try { 741 int classInt = sService.getRemoteClass(mAddress); 742 if (classInt == BluetoothClass.ERROR) return null; 743 return new BluetoothClass(classInt); 744 } catch (RemoteException e) {Log.e(TAG, "", e);} 745 return null; 746 } 747 748 /** 749 * Get trust state of a remote device. 750 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 751 * @hide 752 */ 753 public boolean getTrustState() { 754 try { 755 return sService.getTrustState(mAddress); 756 } catch (RemoteException e) { 757 Log.e(TAG, "", e); 758 } 759 return false; 760 } 761 762 /** 763 * Set trust state for a remote device. 764 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 765 * @param value the trust state value (true or false) 766 * @hide 767 */ 768 public boolean setTrust(boolean value) { 769 try { 770 return sService.setTrust(mAddress, value); 771 } catch (RemoteException e) { 772 Log.e(TAG, "", e); 773 } 774 return false; 775 } 776 777 /** 778 * Returns the supported features (UUIDs) of the remote device. 779 * 780 * <p>This method does not start a service discovery procedure to retrieve the UUIDs 781 * from the remote device. Instead, the local cached copy of the service 782 * UUIDs are returned. 783 * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired. 784 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 785 * 786 * @return the supported features (UUIDs) of the remote device, 787 * or null on error 788 */ 789 public ParcelUuid[] getUuids() { 790 try { 791 return sService.getRemoteUuids(mAddress); 792 } catch (RemoteException e) {Log.e(TAG, "", e);} 793 return null; 794 } 795 796 /** 797 * Perform a service discovery on the remote device to get the UUIDs supported. 798 * 799 * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent, 800 * with the UUIDs supported by the remote end. If there is an error 801 * in getting the SDP records or if the process takes a long time, 802 * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently 803 * present in the cache. Clients should use the {@link #getUuids} to get UUIDs 804 * if service discovery is not to be performed. 805 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 806 * 807 * @return False if the sanity check fails, True if the process 808 * of initiating an ACL connection to the remote device 809 * was started. 810 */ 811 public boolean fetchUuidsWithSdp() { 812 try { 813 return sService.fetchRemoteUuids(mAddress, null, null); 814 } catch (RemoteException e) {Log.e(TAG, "", e);} 815 return false; 816 } 817 818 /** @hide */ 819 public int getServiceChannel(ParcelUuid uuid) { 820 try { 821 return sService.getRemoteServiceChannel(mAddress, uuid); 822 } catch (RemoteException e) {Log.e(TAG, "", e);} 823 return BluetoothDevice.ERROR; 824 } 825 826 /** @hide */ 827 public boolean setPin(byte[] pin) { 828 try { 829 return sService.setPin(mAddress, pin); 830 } catch (RemoteException e) {Log.e(TAG, "", e);} 831 return false; 832 } 833 834 /** @hide */ 835 public boolean setPasskey(int passkey) { 836 try { 837 return sService.setPasskey(mAddress, passkey); 838 } catch (RemoteException e) {Log.e(TAG, "", e);} 839 return false; 840 } 841 842 /** @hide */ 843 public boolean setPairingConfirmation(boolean confirm) { 844 try { 845 return sService.setPairingConfirmation(mAddress, confirm); 846 } catch (RemoteException e) {Log.e(TAG, "", e);} 847 return false; 848 } 849 850 /** @hide */ 851 public boolean setRemoteOutOfBandData() { 852 try { 853 return sService.setRemoteOutOfBandData(mAddress); 854 } catch (RemoteException e) {Log.e(TAG, "", e);} 855 return false; 856 } 857 858 /** @hide */ 859 public boolean cancelPairingUserInput() { 860 try { 861 return sService.cancelPairingUserInput(mAddress); 862 } catch (RemoteException e) {Log.e(TAG, "", e);} 863 return false; 864 } 865 866 /** @hide */ 867 public boolean isBluetoothDock() { 868 try { 869 return sService.isBluetoothDock(mAddress); 870 } catch (RemoteException e) {Log.e(TAG, "", e);} 871 return false; 872 } 873 874 /** 875 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 876 * outgoing connection to this remote device on given channel. 877 * <p>The remote device will be authenticated and communication on this 878 * socket will be encrypted. 879 * <p> Use this socket only if an authenticated socket link is possible. 880 * Authentication refers to the authentication of the link key to 881 * prevent man-in-the-middle type of attacks. 882 * For example, for Bluetooth 2.1 devices, if any of the devices does not 883 * have an input and output capability or just has the ability to 884 * display a numeric key, a secure socket connection is not possible. 885 * In such a case, use {#link createInsecureRfcommSocket}. 886 * For more details, refer to the Security Model section 5.2 (vol 3) of 887 * Bluetooth Core Specification version 2.1 + EDR. 888 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 889 * connection. 890 * <p>Valid RFCOMM channels are in range 1 to 30. 891 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 892 * 893 * @param channel RFCOMM channel to connect to 894 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 895 * @throws IOException on error, for example Bluetooth not available, or 896 * insufficient permissions 897 * @hide 898 */ 899 public BluetoothSocket createRfcommSocket(int channel) throws IOException { 900 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel, 901 null); 902 } 903 904 /** 905 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 906 * outgoing connection to this remote device using SDP lookup of uuid. 907 * <p>This is designed to be used with {@link 908 * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer 909 * Bluetooth applications. 910 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 911 * connection. This will also perform an SDP lookup of the given uuid to 912 * determine which channel to connect to. 913 * <p>The remote device will be authenticated and communication on this 914 * socket will be encrypted. 915 * <p> Use this socket only if an authenticated socket link is possible. 916 * Authentication refers to the authentication of the link key to 917 * prevent man-in-the-middle type of attacks. 918 * For example, for Bluetooth 2.1 devices, if any of the devices does not 919 * have an input and output capability or just has the ability to 920 * display a numeric key, a secure socket connection is not possible. 921 * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}. 922 * For more details, refer to the Security Model section 5.2 (vol 3) of 923 * Bluetooth Core Specification version 2.1 + EDR. 924 * <p>Hint: If you are connecting to a Bluetooth serial board then try 925 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 926 * However if you are connecting to an Android peer then please generate 927 * your own unique UUID. 928 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 929 * 930 * @param uuid service record uuid to lookup RFCOMM channel 931 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 932 * @throws IOException on error, for example Bluetooth not available, or 933 * insufficient permissions 934 */ 935 public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException { 936 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1, 937 new ParcelUuid(uuid)); 938 } 939 940 /** 941 * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure 942 * outgoing connection to this remote device using SDP lookup of uuid. 943 * <p> The communication channel will not have an authenticated link key 944 * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1 945 * devices, the link key will be encrypted, as encryption is mandatory. 946 * For legacy devices (pre Bluetooth 2.1 devices) the link key will 947 * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an 948 * encrypted and authenticated communication channel is desired. 949 * <p>This is designed to be used with {@link 950 * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer 951 * Bluetooth applications. 952 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 953 * connection. This will also perform an SDP lookup of the given uuid to 954 * determine which channel to connect to. 955 * <p>The remote device will be authenticated and communication on this 956 * socket will be encrypted. 957 * <p>Hint: If you are connecting to a Bluetooth serial board then try 958 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 959 * However if you are connecting to an Android peer then please generate 960 * your own unique UUID. 961 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 962 * 963 * @param uuid service record uuid to lookup RFCOMM channel 964 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 965 * @throws IOException on error, for example Bluetooth not available, or 966 * insufficient permissions 967 */ 968 public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException { 969 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1, 970 new ParcelUuid(uuid)); 971 } 972 973 /** 974 * Construct an insecure RFCOMM socket ready to start an outgoing 975 * connection. 976 * Call #connect on the returned #BluetoothSocket to begin the connection. 977 * The remote device will not be authenticated and communication on this 978 * socket will not be encrypted. 979 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 980 * 981 * @param port remote port 982 * @return An RFCOMM BluetoothSocket 983 * @throws IOException On error, for example Bluetooth not available, or 984 * insufficient permissions. 985 * @hide 986 */ 987 public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException { 988 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port, 989 null); 990 } 991 992 /** 993 * Construct a SCO socket ready to start an outgoing connection. 994 * Call #connect on the returned #BluetoothSocket to begin the connection. 995 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 996 * 997 * @return a SCO BluetoothSocket 998 * @throws IOException on error, for example Bluetooth not available, or 999 * insufficient permissions. 1000 * @hide 1001 */ 1002 public BluetoothSocket createScoSocket() throws IOException { 1003 return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null); 1004 } 1005 1006 /** 1007 * Check that a pin is valid and convert to byte array. 1008 * 1009 * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters. 1010 * @param pin pin as java String 1011 * @return the pin code as a UTF-8 byte array, or null if it is an invalid 1012 * Bluetooth pin. 1013 * @hide 1014 */ 1015 public static byte[] convertPinToBytes(String pin) { 1016 if (pin == null) { 1017 return null; 1018 } 1019 byte[] pinBytes; 1020 try { 1021 pinBytes = pin.getBytes("UTF-8"); 1022 } catch (UnsupportedEncodingException uee) { 1023 Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen 1024 return null; 1025 } 1026 if (pinBytes.length <= 0 || pinBytes.length > 16) { 1027 return null; 1028 } 1029 return pinBytes; 1030 } 1031 1032 } 1033