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