BluetoothDevice.java revision 68c692df5f667dcee42506d3c6459d3dc2e1cdd6
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 17package android.bluetooth; 18 19import android.annotation.SdkConstant; 20import android.annotation.SdkConstant.SdkConstantType; 21import android.content.Context; 22import android.os.IBinder; 23import android.os.Parcel; 24import android.os.Parcelable; 25import android.os.ParcelUuid; 26import android.os.RemoteException; 27import android.os.ServiceManager; 28import android.util.Log; 29 30import java.io.IOException; 31import java.io.UnsupportedEncodingException; 32import 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 */ 67public 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} to receive. 326 */ 327 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 328 public static final String ACTION_PAIRING_REQUEST = 329 "android.bluetooth.device.action.PAIRING_REQUEST"; 330 /** @hide */ 331 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 332 public static final String ACTION_PAIRING_CANCEL = 333 "android.bluetooth.device.action.PAIRING_CANCEL"; 334 335 /** @hide */ 336 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 337 public static final String ACTION_CONNECTION_ACCESS_REQUEST = 338 "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST"; 339 340 /** @hide */ 341 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 342 public static final String ACTION_CONNECTION_ACCESS_REPLY = 343 "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY"; 344 345 /** @hide */ 346 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 347 public static final String ACTION_CONNECTION_ACCESS_CANCEL = 348 "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL"; 349 350 /** 351 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent. 352 * @hide 353 */ 354 public static final String EXTRA_ACCESS_REQUEST_TYPE = 355 "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE"; 356 357 /**@hide*/ 358 public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1; 359 360 /**@hide*/ 361 public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2; 362 363 /**@hide*/ 364 public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3; 365 366 /** 367 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, 368 * Contains package name to return reply intent to. 369 * @hide 370 */ 371 public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME"; 372 373 /** 374 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, 375 * Contains class name to return reply intent to. 376 * @hide 377 */ 378 public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME"; 379 380 /** 381 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent. 382 * @hide 383 */ 384 public static final String EXTRA_CONNECTION_ACCESS_RESULT = 385 "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT"; 386 387 /**@hide*/ 388 public static final int CONNECTION_ACCESS_YES = 1; 389 390 /**@hide*/ 391 public static final int CONNECTION_ACCESS_NO = 2; 392 393 /** 394 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents, 395 * Contains boolean to indicate if the allowed response is once-for-all so that 396 * next request will be granted without asking user again. 397 * @hide 398 */ 399 public static final String EXTRA_ALWAYS_ALLOWED = 400 "android.bluetooth.device.extra.ALWAYS_ALLOWED"; 401 402 /** 403 * A bond attempt succeeded 404 * @hide 405 */ 406 public static final int BOND_SUCCESS = 0; 407 408 /** 409 * A bond attempt failed because pins did not match, or remote device did 410 * not respond to pin request in time 411 * @hide 412 */ 413 public static final int UNBOND_REASON_AUTH_FAILED = 1; 414 415 /** 416 * A bond attempt failed because the other side explicitly rejected 417 * bonding 418 * @hide 419 */ 420 public static final int UNBOND_REASON_AUTH_REJECTED = 2; 421 422 /** 423 * A bond attempt failed because we canceled the bonding process 424 * @hide 425 */ 426 public static final int UNBOND_REASON_AUTH_CANCELED = 3; 427 428 /** 429 * A bond attempt failed because we could not contact the remote device 430 * @hide 431 */ 432 public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4; 433 434 /** 435 * A bond attempt failed because a discovery is in progress 436 * @hide 437 */ 438 public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5; 439 440 /** 441 * A bond attempt failed because of authentication timeout 442 * @hide 443 */ 444 public static final int UNBOND_REASON_AUTH_TIMEOUT = 6; 445 446 /** 447 * A bond attempt failed because of repeated attempts 448 * @hide 449 */ 450 public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7; 451 452 /** 453 * A bond attempt failed because we received an Authentication Cancel 454 * by remote end 455 * @hide 456 */ 457 public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8; 458 459 /** 460 * An existing bond was explicitly revoked 461 * @hide 462 */ 463 public static final int UNBOND_REASON_REMOVED = 9; 464 465 /** 466 * The user will be prompted to enter a pin or 467 * a privileged app will enter a pin for user. 468 */ 469 public static final int PAIRING_VARIANT_PIN = 0; 470 471 /** 472 * The user will be prompted to enter a passkey 473 * @hide 474 */ 475 public static final int PAIRING_VARIANT_PASSKEY = 1; 476 477 /** 478 * The user will be prompted to confirm the passkey displayed on the screen or 479 * a privileged app will confirm the passkey for the user. 480 */ 481 public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2; 482 483 /** 484 * The user will be prompted to accept or deny the incoming pairing request 485 * @hide 486 */ 487 public static final int PAIRING_VARIANT_CONSENT = 3; 488 489 /** 490 * The user will be prompted to enter the passkey displayed on remote device 491 * This is used for Bluetooth 2.1 pairing. 492 * @hide 493 */ 494 public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4; 495 496 /** 497 * The user will be prompted to enter the PIN displayed on remote device. 498 * This is used for Bluetooth 2.0 pairing. 499 * @hide 500 */ 501 public static final int PAIRING_VARIANT_DISPLAY_PIN = 5; 502 503 /** 504 * The user will be prompted to accept or deny the OOB pairing request 505 * @hide 506 */ 507 public static final int PAIRING_VARIANT_OOB_CONSENT = 6; 508 509 /** 510 * Used as an extra field in {@link #ACTION_UUID} intents, 511 * Contains the {@link android.os.ParcelUuid}s of the remote device which 512 * is a parcelable version of {@link UUID}. 513 */ 514 public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID"; 515 516 /** 517 * Lazy initialization. Guaranteed final after first object constructed, or 518 * getService() called. 519 * TODO: Unify implementation of sService amongst BluetoothFoo API's 520 */ 521 private static IBluetooth sService; 522 523 private final String mAddress; 524 525 /*package*/ static IBluetooth getService() { 526 synchronized (BluetoothDevice.class) { 527 if (sService == null) { 528 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 529 sService = adapter.getBluetoothService(mStateChangeCallback); 530 } 531 } 532 return sService; 533 } 534 535 static IBluetoothManagerCallback mStateChangeCallback = new IBluetoothManagerCallback.Stub() { 536 537 public void onBluetoothServiceUp(IBluetooth bluetoothService) 538 throws RemoteException { 539 synchronized (BluetoothDevice.class) { 540 sService = bluetoothService; 541 } 542 } 543 544 public void onBluetoothServiceDown() 545 throws RemoteException { 546 synchronized (BluetoothDevice.class) { 547 sService = null; 548 } 549 } 550 }; 551 /** 552 * Create a new BluetoothDevice 553 * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB", 554 * and is validated in this constructor. 555 * @param address valid Bluetooth MAC address 556 * @throws RuntimeException Bluetooth is not available on this platform 557 * @throws IllegalArgumentException address is invalid 558 * @hide 559 */ 560 /*package*/ BluetoothDevice(String address) { 561 getService(); // ensures sService is initialized 562 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 563 throw new IllegalArgumentException(address + " is not a valid Bluetooth address"); 564 } 565 566 mAddress = address; 567 } 568 569 @Override 570 public boolean equals(Object o) { 571 if (o instanceof BluetoothDevice) { 572 return mAddress.equals(((BluetoothDevice)o).getAddress()); 573 } 574 return false; 575 } 576 577 @Override 578 public int hashCode() { 579 return mAddress.hashCode(); 580 } 581 582 /** 583 * Returns a string representation of this BluetoothDevice. 584 * <p>Currently this is the Bluetooth hardware address, for example 585 * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress} 586 * if you explicitly require the Bluetooth hardware address in case the 587 * {@link #toString} representation changes in the future. 588 * @return string representation of this BluetoothDevice 589 */ 590 @Override 591 public String toString() { 592 return mAddress; 593 } 594 595 public int describeContents() { 596 return 0; 597 } 598 599 public static final Parcelable.Creator<BluetoothDevice> CREATOR = 600 new Parcelable.Creator<BluetoothDevice>() { 601 public BluetoothDevice createFromParcel(Parcel in) { 602 return new BluetoothDevice(in.readString()); 603 } 604 public BluetoothDevice[] newArray(int size) { 605 return new BluetoothDevice[size]; 606 } 607 }; 608 609 public void writeToParcel(Parcel out, int flags) { 610 out.writeString(mAddress); 611 } 612 613 /** 614 * Returns the hardware address of this BluetoothDevice. 615 * <p> For example, "00:11:22:AA:BB:CC". 616 * @return Bluetooth hardware address as string 617 */ 618 public String getAddress() { 619 if (DBG) Log.d(TAG, "mAddress: " + mAddress); 620 return mAddress; 621 } 622 623 /** 624 * Get the friendly Bluetooth name of the remote device. 625 * 626 * <p>The local adapter will automatically retrieve remote names when 627 * performing a device scan, and will cache them. This method just returns 628 * the name for this device from the cache. 629 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 630 * 631 * @return the Bluetooth name, or null if there was a problem. 632 */ 633 public String getName() { 634 if (sService == null) { 635 Log.e(TAG, "BT not enabled. Cannot get Remote Device name"); 636 return null; 637 } 638 try { 639 return sService.getRemoteName(this); 640 } catch (RemoteException e) {Log.e(TAG, "", e);} 641 return null; 642 } 643 644 /** 645 * Get the Bluetooth device type of the remote device. 646 * 647 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 648 * 649 * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} 650 * {@link #DEVICE_TYPE_DUAL}. 651 * {@link #DEVICE_TYPE_UNKNOWN} if it's not available 652 */ 653 public int getType() { 654 if (sService == null) { 655 Log.e(TAG, "BT not enabled. Cannot get Remote Device type"); 656 return DEVICE_TYPE_UNKNOWN; 657 } 658 try { 659 return sService.getRemoteType(this); 660 } catch (RemoteException e) {Log.e(TAG, "", e);} 661 return DEVICE_TYPE_UNKNOWN; 662 } 663 664 /** 665 * Get the Bluetooth alias of the remote device. 666 * <p>Alias is the locally modified name of a remote device. 667 * 668 * @return the Bluetooth alias, or null if no alias or there was a problem 669 * @hide 670 */ 671 public String getAlias() { 672 if (sService == null) { 673 Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias"); 674 return null; 675 } 676 try { 677 return sService.getRemoteAlias(this); 678 } catch (RemoteException e) {Log.e(TAG, "", e);} 679 return null; 680 } 681 682 /** 683 * Set the Bluetooth alias of the remote device. 684 * <p>Alias is the locally modified name of a remote device. 685 * <p>This methoid overwrites the alias. The changed 686 * alias is saved in the local storage so that the change 687 * is preserved over power cycle. 688 * 689 * @return true on success, false on error 690 * @hide 691 */ 692 public boolean setAlias(String alias) { 693 if (sService == null) { 694 Log.e(TAG, "BT not enabled. Cannot set Remote Device name"); 695 return false; 696 } 697 try { 698 return sService.setRemoteAlias(this, alias); 699 } catch (RemoteException e) {Log.e(TAG, "", e);} 700 return false; 701 } 702 703 /** 704 * Get the Bluetooth alias of the remote device. 705 * If Alias is null, get the Bluetooth name instead. 706 * @see #getAlias() 707 * @see #getName() 708 * 709 * @return the Bluetooth alias, or null if no alias or there was a problem 710 * @hide 711 */ 712 public String getAliasName() { 713 String name = getAlias(); 714 if (name == null) { 715 name = getName(); 716 } 717 return name; 718 } 719 720 /** 721 * Start the bonding (pairing) process with the remote device. 722 * <p>This is an asynchronous call, it will return immediately. Register 723 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 724 * the bonding process completes, and its result. 725 * <p>Android system services will handle the necessary user interactions 726 * to confirm and complete the bonding process. 727 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. 728 * 729 * @return false on immediate error, true if bonding will begin 730 */ 731 public boolean createBond() { 732 if (sService == null) { 733 Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device"); 734 return false; 735 } 736 try { 737 return sService.createBond(this); 738 } catch (RemoteException e) {Log.e(TAG, "", e);} 739 return false; 740 } 741 742 /** 743 * Start the bonding (pairing) process with the remote device using the 744 * Out Of Band mechanism. 745 * 746 * <p>This is an asynchronous call, it will return immediately. Register 747 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 748 * the bonding process completes, and its result. 749 * 750 * <p>Android system services will handle the necessary user interactions 751 * to confirm and complete the bonding process. 752 * 753 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 754 * 755 * @param hash - Simple Secure pairing hash 756 * @param randomizer - The random key obtained using OOB 757 * @return false on immediate error, true if bonding will begin 758 * 759 * @hide 760 */ 761 public boolean createBondOutOfBand(byte[] hash, byte[] randomizer) { 762 //TODO(BT) 763 /* 764 try { 765 return sService.createBondOutOfBand(this, hash, randomizer); 766 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 767 return false; 768 } 769 770 /** 771 * Set the Out Of Band data for a remote device to be used later 772 * in the pairing mechanism. Users can obtain this data through other 773 * trusted channels 774 * 775 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 776 * 777 * @param hash Simple Secure pairing hash 778 * @param randomizer The random key obtained using OOB 779 * @return false on error; true otherwise 780 * 781 * @hide 782 */ 783 public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) { 784 //TODO(BT) 785 /* 786 try { 787 return sService.setDeviceOutOfBandData(this, hash, randomizer); 788 } catch (RemoteException e) {Log.e(TAG, "", e);} */ 789 return false; 790 } 791 792 /** 793 * Cancel an in-progress bonding request started with {@link #createBond}. 794 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 795 * 796 * @return true on success, false on error 797 * @hide 798 */ 799 public boolean cancelBondProcess() { 800 if (sService == null) { 801 Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond"); 802 return false; 803 } 804 try { 805 return sService.cancelBondProcess(this); 806 } catch (RemoteException e) {Log.e(TAG, "", e);} 807 return false; 808 } 809 810 /** 811 * Remove bond (pairing) with the remote device. 812 * <p>Delete the link key associated with the remote device, and 813 * immediately terminate connections to that device that require 814 * authentication and encryption. 815 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 816 * 817 * @return true on success, false on error 818 * @hide 819 */ 820 public boolean removeBond() { 821 if (sService == null) { 822 Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond"); 823 return false; 824 } 825 try { 826 return sService.removeBond(this); 827 } catch (RemoteException e) {Log.e(TAG, "", e);} 828 return false; 829 } 830 831 /** 832 * Get the bond state of the remote device. 833 * <p>Possible values for the bond state are: 834 * {@link #BOND_NONE}, 835 * {@link #BOND_BONDING}, 836 * {@link #BOND_BONDED}. 837 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 838 * 839 * @return the bond state 840 */ 841 public int getBondState() { 842 if (sService == null) { 843 Log.e(TAG, "BT not enabled. Cannot get bond state"); 844 return BOND_NONE; 845 } 846 try { 847 return sService.getBondState(this); 848 } catch (RemoteException e) {Log.e(TAG, "", e);} 849 catch (NullPointerException npe) { 850 // Handle case where bluetooth service proxy 851 // is already null. 852 Log.e(TAG, "NullPointerException for getBondState() of device ("+ 853 getAddress()+")", npe); 854 } 855 return BOND_NONE; 856 } 857 858 /** 859 * Get the Bluetooth class of the remote device. 860 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 861 * 862 * @return Bluetooth class object, or null on error 863 */ 864 public BluetoothClass getBluetoothClass() { 865 if (sService == null) { 866 Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class"); 867 return null; 868 } 869 try { 870 int classInt = sService.getRemoteClass(this); 871 if (classInt == BluetoothClass.ERROR) return null; 872 return new BluetoothClass(classInt); 873 } catch (RemoteException e) {Log.e(TAG, "", e);} 874 return null; 875 } 876 877 /** 878 * Get trust state of a remote device. 879 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 880 * @hide 881 */ 882 public boolean getTrustState() { 883 //TODO(BT) 884 /* 885 try { 886 return sService.getTrustState(this); 887 } catch (RemoteException e) { 888 Log.e(TAG, "", e); 889 }*/ 890 return false; 891 } 892 893 /** 894 * Set trust state for a remote device. 895 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 896 * @param value the trust state value (true or false) 897 * @hide 898 */ 899 public boolean setTrust(boolean value) { 900 //TODO(BT) 901 /* 902 try { 903 return sService.setTrust(this, value); 904 } catch (RemoteException e) { 905 Log.e(TAG, "", e); 906 }*/ 907 return false; 908 } 909 910 /** 911 * Returns the supported features (UUIDs) of the remote device. 912 * 913 * <p>This method does not start a service discovery procedure to retrieve the UUIDs 914 * from the remote device. Instead, the local cached copy of the service 915 * UUIDs are returned. 916 * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired. 917 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 918 * 919 * @return the supported features (UUIDs) of the remote device, 920 * or null on error 921 */ 922 public ParcelUuid[] getUuids() { 923 if (sService == null) { 924 Log.e(TAG, "BT not enabled. Cannot get remote device Uuids"); 925 return null; 926 } 927 try { 928 return sService.getRemoteUuids(this); 929 } catch (RemoteException e) {Log.e(TAG, "", e);} 930 return null; 931 } 932 933 /** 934 * Perform a service discovery on the remote device to get the UUIDs supported. 935 * 936 * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent, 937 * with the UUIDs supported by the remote end. If there is an error 938 * in getting the SDP records or if the process takes a long time, 939 * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently 940 * present in the cache. Clients should use the {@link #getUuids} to get UUIDs 941 * if service discovery is not to be performed. 942 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 943 * 944 * @return False if the sanity check fails, True if the process 945 * of initiating an ACL connection to the remote device 946 * was started. 947 */ 948 public boolean fetchUuidsWithSdp() { 949 try { 950 return sService.fetchRemoteUuids(this); 951 } catch (RemoteException e) {Log.e(TAG, "", e);} 952 return false; 953 } 954 955 /** @hide */ 956 public int getServiceChannel(ParcelUuid uuid) { 957 //TODO(BT) 958 /* 959 try { 960 return sService.getRemoteServiceChannel(this, uuid); 961 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 962 return BluetoothDevice.ERROR; 963 } 964 965 /** 966 * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} 967 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. 968 * 969 * @return true pin has been set 970 * false for error 971 */ 972 public boolean setPin(byte[] pin) { 973 if (sService == null) { 974 Log.e(TAG, "BT not enabled. Cannot set Remote Device pin"); 975 return false; 976 } 977 try { 978 return sService.setPin(this, true, pin.length, pin); 979 } catch (RemoteException e) {Log.e(TAG, "", e);} 980 return false; 981 } 982 983 /** @hide */ 984 public boolean setPasskey(int passkey) { 985 //TODO(BT) 986 /* 987 try { 988 return sService.setPasskey(this, true, 4, passkey); 989 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 990 return false; 991 } 992 993 /** 994 * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing. 995 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. 996 * 997 * @return true confirmation has been sent out 998 * false for error 999 */ 1000 public boolean setPairingConfirmation(boolean confirm) { 1001 if (sService == null) { 1002 Log.e(TAG, "BT not enabled. Cannot set pairing confirmation"); 1003 return false; 1004 } 1005 try { 1006 return sService.setPairingConfirmation(this, confirm); 1007 } catch (RemoteException e) {Log.e(TAG, "", e);} 1008 return false; 1009 } 1010 1011 /** @hide */ 1012 public boolean setRemoteOutOfBandData() { 1013 // TODO(BT) 1014 /* 1015 try { 1016 return sService.setRemoteOutOfBandData(this); 1017 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 1018 return false; 1019 } 1020 1021 /** @hide */ 1022 public boolean cancelPairingUserInput() { 1023 if (sService == null) { 1024 Log.e(TAG, "BT not enabled. Cannot create pairing user input"); 1025 return false; 1026 } 1027 try { 1028 return sService.cancelBondProcess(this); 1029 } catch (RemoteException e) {Log.e(TAG, "", e);} 1030 return false; 1031 } 1032 1033 /** @hide */ 1034 public boolean isBluetoothDock() { 1035 // TODO(BT) 1036 /* 1037 try { 1038 return sService.isBluetoothDock(this); 1039 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 1040 return false; 1041 } 1042 1043 /** 1044 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 1045 * outgoing connection to this remote device on given channel. 1046 * <p>The remote device will be authenticated and communication on this 1047 * socket will be encrypted. 1048 * <p> Use this socket only if an authenticated socket link is possible. 1049 * Authentication refers to the authentication of the link key to 1050 * prevent man-in-the-middle type of attacks. 1051 * For example, for Bluetooth 2.1 devices, if any of the devices does not 1052 * have an input and output capability or just has the ability to 1053 * display a numeric key, a secure socket connection is not possible. 1054 * In such a case, use {#link createInsecureRfcommSocket}. 1055 * For more details, refer to the Security Model section 5.2 (vol 3) of 1056 * Bluetooth Core Specification version 2.1 + EDR. 1057 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1058 * connection. 1059 * <p>Valid RFCOMM channels are in range 1 to 30. 1060 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1061 * 1062 * @param channel RFCOMM channel to connect to 1063 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1064 * @throws IOException on error, for example Bluetooth not available, or 1065 * insufficient permissions 1066 * @hide 1067 */ 1068 public BluetoothSocket createRfcommSocket(int channel) throws IOException { 1069 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel, 1070 null); 1071 } 1072 1073 /** 1074 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 1075 * outgoing connection to this remote device using SDP lookup of uuid. 1076 * <p>This is designed to be used with {@link 1077 * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer 1078 * Bluetooth applications. 1079 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1080 * connection. This will also perform an SDP lookup of the given uuid to 1081 * determine which channel to connect to. 1082 * <p>The remote device will be authenticated and communication on this 1083 * socket will be encrypted. 1084 * <p> Use this socket only if an authenticated socket link is possible. 1085 * Authentication refers to the authentication of the link key to 1086 * prevent man-in-the-middle type of attacks. 1087 * For example, for Bluetooth 2.1 devices, if any of the devices does not 1088 * have an input and output capability or just has the ability to 1089 * display a numeric key, a secure socket connection is not possible. 1090 * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}. 1091 * For more details, refer to the Security Model section 5.2 (vol 3) of 1092 * Bluetooth Core Specification version 2.1 + EDR. 1093 * <p>Hint: If you are connecting to a Bluetooth serial board then try 1094 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 1095 * However if you are connecting to an Android peer then please generate 1096 * your own unique UUID. 1097 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1098 * 1099 * @param uuid service record uuid to lookup RFCOMM channel 1100 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1101 * @throws IOException on error, for example Bluetooth not available, or 1102 * insufficient permissions 1103 */ 1104 public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException { 1105 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1, 1106 new ParcelUuid(uuid)); 1107 } 1108 1109 /** 1110 * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure 1111 * outgoing connection to this remote device using SDP lookup of uuid. 1112 * <p> The communication channel will not have an authenticated link key 1113 * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1 1114 * devices, the link key will be encrypted, as encryption is mandatory. 1115 * For legacy devices (pre Bluetooth 2.1 devices) the link key will 1116 * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an 1117 * encrypted and authenticated communication channel is desired. 1118 * <p>This is designed to be used with {@link 1119 * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer 1120 * Bluetooth applications. 1121 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1122 * connection. This will also perform an SDP lookup of the given uuid to 1123 * determine which channel to connect to. 1124 * <p>The remote device will be authenticated and communication on this 1125 * socket will be encrypted. 1126 * <p>Hint: If you are connecting to a Bluetooth serial board then try 1127 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 1128 * However if you are connecting to an Android peer then please generate 1129 * your own unique UUID. 1130 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1131 * 1132 * @param uuid service record uuid to lookup RFCOMM channel 1133 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1134 * @throws IOException on error, for example Bluetooth not available, or 1135 * insufficient permissions 1136 */ 1137 public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException { 1138 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1, 1139 new ParcelUuid(uuid)); 1140 } 1141 1142 /** 1143 * Construct an insecure RFCOMM socket ready to start an outgoing 1144 * connection. 1145 * Call #connect on the returned #BluetoothSocket to begin the connection. 1146 * The remote device will not be authenticated and communication on this 1147 * socket will not be encrypted. 1148 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 1149 * 1150 * @param port remote port 1151 * @return An RFCOMM BluetoothSocket 1152 * @throws IOException On error, for example Bluetooth not available, or 1153 * insufficient permissions. 1154 * @hide 1155 */ 1156 public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException { 1157 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port, 1158 null); 1159 } 1160 1161 /** 1162 * Construct a SCO socket ready to start an outgoing connection. 1163 * Call #connect on the returned #BluetoothSocket to begin the connection. 1164 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 1165 * 1166 * @return a SCO BluetoothSocket 1167 * @throws IOException on error, for example Bluetooth not available, or 1168 * insufficient permissions. 1169 * @hide 1170 */ 1171 public BluetoothSocket createScoSocket() throws IOException { 1172 return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null); 1173 } 1174 1175 /** 1176 * Check that a pin is valid and convert to byte array. 1177 * 1178 * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters. 1179 * @param pin pin as java String 1180 * @return the pin code as a UTF-8 byte array, or null if it is an invalid 1181 * Bluetooth pin. 1182 * @hide 1183 */ 1184 public static byte[] convertPinToBytes(String pin) { 1185 if (pin == null) { 1186 return null; 1187 } 1188 byte[] pinBytes; 1189 try { 1190 pinBytes = pin.getBytes("UTF-8"); 1191 } catch (UnsupportedEncodingException uee) { 1192 Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen 1193 return null; 1194 } 1195 if (pinBytes.length <= 0 || pinBytes.length > 16) { 1196 return null; 1197 } 1198 return pinBytes; 1199 } 1200 1201 /** 1202 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 1203 * The callback is used to deliver results to Caller, such as connection status as well 1204 * as any further GATT client operations. 1205 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 1206 * GATT client operations. 1207 * @param callback GATT callback handler that will receive asynchronous callbacks. 1208 * @param autoConnect Whether to directly connect to the remote device (false) 1209 * or to automatically connect as soon as the remote 1210 * device becomes available (true). 1211 * @throws IllegalArgumentException if callback is null 1212 */ 1213 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 1214 BluetoothGattCallback callback) { 1215 // TODO(Bluetooth) check whether platform support BLE 1216 // Do the check here or in GattServer? 1217 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1218 IBluetoothManager managerService = adapter.getBluetoothManager(); 1219 try { 1220 IBluetoothGatt iGatt = managerService.getBluetoothGatt(); 1221 if (iGatt == null) { 1222 // BLE is not supported 1223 return null; 1224 } 1225 BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this); 1226 gatt.connect(autoConnect, callback); 1227 return gatt; 1228 } catch (RemoteException e) {Log.e(TAG, "", e);} 1229 return null; 1230 } 1231} 1232