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