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