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