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