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