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.Manifest; 20 import android.annotation.RequiresPermission; 21 import android.annotation.SdkConstant; 22 import android.annotation.SdkConstant.SdkConstantType; 23 import android.annotation.SystemApi; 24 import android.content.Context; 25 import android.os.Handler; 26 import android.os.Parcel; 27 import android.os.ParcelUuid; 28 import android.os.Parcelable; 29 import android.os.Process; 30 import android.os.RemoteException; 31 import android.util.Log; 32 33 import java.io.IOException; 34 import java.io.UnsupportedEncodingException; 35 import java.util.UUID; 36 37 /** 38 * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you 39 * create a connection with the respective device or query information about 40 * it, such as the name, address, class, and bonding state. 41 * 42 * <p>This class is really just a thin wrapper for a Bluetooth hardware 43 * address. Objects of this class are immutable. Operations on this class 44 * are performed on the remote Bluetooth hardware address, using the 45 * {@link BluetoothAdapter} that was used to create this {@link 46 * BluetoothDevice}. 47 * 48 * <p>To get a {@link BluetoothDevice}, use 49 * {@link BluetoothAdapter#getRemoteDevice(String) 50 * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device 51 * of a known MAC address (which you can get through device discovery with 52 * {@link BluetoothAdapter}) or get one from the set of bonded devices 53 * returned by {@link BluetoothAdapter#getBondedDevices() 54 * BluetoothAdapter.getBondedDevices()}. You can then open a 55 * {@link BluetoothSocket} for communication with the remote device, using 56 * {@link #createRfcommSocketToServiceRecord(UUID)}. 57 * 58 * <p class="note"><strong>Note:</strong> 59 * Requires the {@link android.Manifest.permission#BLUETOOTH} permission. 60 * 61 * <div class="special reference"> 62 * <h3>Developer Guides</h3> 63 * <p> 64 * For more information about using Bluetooth, read the <a href= 65 * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer 66 * guide. 67 * </p> 68 * </div> 69 * 70 * {@see BluetoothAdapter} 71 * {@see BluetoothSocket} 72 */ 73 public final class BluetoothDevice implements Parcelable { 74 private static final String TAG = "BluetoothDevice"; 75 private static final boolean DBG = false; 76 77 /** 78 * Connection state bitmask as returned by getConnectionState. 79 */ 80 private static final int CONNECTION_STATE_DISCONNECTED = 0; 81 private static final int CONNECTION_STATE_CONNECTED = 1; 82 private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2; 83 private static final int CONNECTION_STATE_ENCRYPTED_LE = 4; 84 85 /** 86 * Sentinel error value for this class. Guaranteed to not equal any other 87 * integer constant in this class. Provided as a convenience for functions 88 * that require a sentinel error value, for example: 89 * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 90 * BluetoothDevice.ERROR)</code> 91 */ 92 public static final int ERROR = Integer.MIN_VALUE; 93 94 /** 95 * Broadcast Action: Remote device discovered. 96 * <p>Sent when a remote device is found during discovery. 97 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 98 * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or 99 * {@link #EXTRA_RSSI} if they are available. 100 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} and 101 * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive. 102 */ 103 // TODO: Change API to not broadcast RSSI if not available (incoming connection) 104 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 105 public static final String ACTION_FOUND = 106 "android.bluetooth.device.action.FOUND"; 107 108 /** 109 * Broadcast Action: Remote device disappeared. 110 * <p>Sent when a remote device that was found in the last discovery is not 111 * found in the current discovery. 112 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 113 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 114 * 115 * @hide 116 */ 117 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 118 public static final String ACTION_DISAPPEARED = 119 "android.bluetooth.device.action.DISAPPEARED"; 120 121 /** 122 * Broadcast Action: Bluetooth class of a remote device has changed. 123 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 124 * #EXTRA_CLASS}. 125 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 126 * {@see BluetoothClass} 127 */ 128 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 129 public static final String ACTION_CLASS_CHANGED = 130 "android.bluetooth.device.action.CLASS_CHANGED"; 131 132 /** 133 * Broadcast Action: Indicates a low level (ACL) connection has been 134 * established with a remote device. 135 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 136 * <p>ACL connections are managed automatically by the Android Bluetooth 137 * stack. 138 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 139 */ 140 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 141 public static final String ACTION_ACL_CONNECTED = 142 "android.bluetooth.device.action.ACL_CONNECTED"; 143 144 /** 145 * Broadcast Action: Indicates that a low level (ACL) disconnection has 146 * been requested for a remote device, and it will soon be disconnected. 147 * <p>This is useful for graceful disconnection. Applications should use 148 * this intent as a hint to immediately terminate higher level connections 149 * (RFCOMM, L2CAP, or profile connections) to the remote device. 150 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 151 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 152 */ 153 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 154 public static final String ACTION_ACL_DISCONNECT_REQUESTED = 155 "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED"; 156 157 /** 158 * Broadcast Action: Indicates a low level (ACL) disconnection from a 159 * remote device. 160 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 161 * <p>ACL connections are managed automatically by the Android Bluetooth 162 * stack. 163 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 164 */ 165 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 166 public static final String ACTION_ACL_DISCONNECTED = 167 "android.bluetooth.device.action.ACL_DISCONNECTED"; 168 169 /** 170 * Broadcast Action: Indicates the friendly name of a remote device has 171 * been retrieved for the first time, or changed since the last retrieval. 172 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 173 * #EXTRA_NAME}. 174 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 175 */ 176 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 177 public static final String ACTION_NAME_CHANGED = 178 "android.bluetooth.device.action.NAME_CHANGED"; 179 180 /** 181 * Broadcast Action: Indicates the alias of a remote device has been 182 * changed. 183 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 184 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 185 * 186 * @hide 187 */ 188 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 189 public static final String ACTION_ALIAS_CHANGED = 190 "android.bluetooth.device.action.ALIAS_CHANGED"; 191 192 /** 193 * Broadcast Action: Indicates a change in the bond state of a remote 194 * device. For example, if a device is bonded (paired). 195 * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link 196 * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}. 197 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 198 */ 199 // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also 200 // contain a hidden extra field EXTRA_REASON with the result code. 201 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 202 public static final String ACTION_BOND_STATE_CHANGED = 203 "android.bluetooth.device.action.BOND_STATE_CHANGED"; 204 205 /** 206 * Broadcast Action: Indicates the battery level of a remote device has 207 * been retrieved for the first time, or changed since the last retrieval 208 * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link 209 * #EXTRA_BATTERY_LEVEL}. 210 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 211 * 212 * @hide 213 */ 214 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 215 public static final String ACTION_BATTERY_LEVEL_CHANGED = 216 "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED"; 217 218 /** 219 * Used as an Integer extra field in {@link #ACTION_BATTERY_LEVEL_CHANGED} 220 * intent. It contains the most recently retrieved battery level information 221 * ranging from 0% to 100% for a remote device, {@link #BATTERY_LEVEL_UNKNOWN} 222 * when the valid is unknown or there is an error 223 * 224 * @hide 225 */ 226 public static final String EXTRA_BATTERY_LEVEL = 227 "android.bluetooth.device.extra.BATTERY_LEVEL"; 228 229 /** 230 * Used as the unknown value for {@link #EXTRA_BATTERY_LEVEL} and {@link #getBatteryLevel()} 231 * 232 * @hide 233 */ 234 public static final int BATTERY_LEVEL_UNKNOWN = -1; 235 236 /** 237 * Used as a Parcelable {@link BluetoothDevice} extra field in every intent 238 * broadcast by this class. It contains the {@link BluetoothDevice} that 239 * the intent applies to. 240 */ 241 public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE"; 242 243 /** 244 * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link 245 * #ACTION_FOUND} intents. It contains the friendly Bluetooth name. 246 */ 247 public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME"; 248 249 /** 250 * Used as an optional short extra field in {@link #ACTION_FOUND} intents. 251 * Contains the RSSI value of the remote device as reported by the 252 * Bluetooth hardware. 253 */ 254 public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI"; 255 256 /** 257 * Used as a Parcelable {@link BluetoothClass} extra field in {@link 258 * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents. 259 */ 260 public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS"; 261 262 /** 263 * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. 264 * Contains the bond state of the remote device. 265 * <p>Possible values are: 266 * {@link #BOND_NONE}, 267 * {@link #BOND_BONDING}, 268 * {@link #BOND_BONDED}. 269 */ 270 public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE"; 271 /** 272 * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. 273 * Contains the previous bond state of the remote device. 274 * <p>Possible values are: 275 * {@link #BOND_NONE}, 276 * {@link #BOND_BONDING}, 277 * {@link #BOND_BONDED}. 278 */ 279 public static final String EXTRA_PREVIOUS_BOND_STATE = 280 "android.bluetooth.device.extra.PREVIOUS_BOND_STATE"; 281 /** 282 * Indicates the remote device is not bonded (paired). 283 * <p>There is no shared link key with the remote device, so communication 284 * (if it is allowed at all) will be unauthenticated and unencrypted. 285 */ 286 public static final int BOND_NONE = 10; 287 /** 288 * Indicates bonding (pairing) is in progress with the remote device. 289 */ 290 public static final int BOND_BONDING = 11; 291 /** 292 * Indicates the remote device is bonded (paired). 293 * <p>A shared link keys exists locally for the remote device, so 294 * communication can be authenticated and encrypted. 295 * <p><i>Being bonded (paired) with a remote device does not necessarily 296 * mean the device is currently connected. It just means that the pending 297 * procedure was completed at some earlier time, and the link key is still 298 * stored locally, ready to use on the next connection. 299 * </i> 300 */ 301 public static final int BOND_BONDED = 12; 302 303 /** 304 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} 305 * intents for unbond reason. 306 * 307 * @hide 308 */ 309 public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON"; 310 311 /** 312 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} 313 * intents to indicate pairing method used. Possible values are: 314 * {@link #PAIRING_VARIANT_PIN}, 315 * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION}, 316 */ 317 public static final String EXTRA_PAIRING_VARIANT = 318 "android.bluetooth.device.extra.PAIRING_VARIANT"; 319 320 /** 321 * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} 322 * intents as the value of passkey. 323 */ 324 public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY"; 325 326 /** 327 * Bluetooth device type, Unknown 328 */ 329 public static final int DEVICE_TYPE_UNKNOWN = 0; 330 331 /** 332 * Bluetooth device type, Classic - BR/EDR devices 333 */ 334 public static final int DEVICE_TYPE_CLASSIC = 1; 335 336 /** 337 * Bluetooth device type, Low Energy - LE-only 338 */ 339 public static final int DEVICE_TYPE_LE = 2; 340 341 /** 342 * Bluetooth device type, Dual Mode - BR/EDR/LE 343 */ 344 public static final int DEVICE_TYPE_DUAL = 3; 345 346 347 /** @hide */ 348 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 349 public static final String ACTION_SDP_RECORD = 350 "android.bluetooth.device.action.SDP_RECORD"; 351 352 /** 353 * Broadcast Action: This intent is used to broadcast the {@link UUID} 354 * wrapped as a {@link android.os.ParcelUuid} of the remote device after it 355 * has been fetched. This intent is sent only when the UUIDs of the remote 356 * device are requested to be fetched using Service Discovery Protocol 357 * <p> Always contains the extra field {@link #EXTRA_DEVICE} 358 * <p> Always contains the extra field {@link #EXTRA_UUID} 359 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 360 */ 361 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 362 public static final String ACTION_UUID = 363 "android.bluetooth.device.action.UUID"; 364 365 /** @hide */ 366 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 367 public static final String ACTION_MAS_INSTANCE = 368 "android.bluetooth.device.action.MAS_INSTANCE"; 369 370 /** 371 * Broadcast Action: Indicates a failure to retrieve the name of a remote 372 * device. 373 * <p>Always contains the extra field {@link #EXTRA_DEVICE}. 374 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 375 * 376 * @hide 377 */ 378 //TODO: is this actually useful? 379 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 380 public static final String ACTION_NAME_FAILED = 381 "android.bluetooth.device.action.NAME_FAILED"; 382 383 /** 384 * Broadcast Action: This intent is used to broadcast PAIRING REQUEST 385 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to 386 * receive. 387 */ 388 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 389 public static final String ACTION_PAIRING_REQUEST = 390 "android.bluetooth.device.action.PAIRING_REQUEST"; 391 /** @hide */ 392 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 393 public static final String ACTION_PAIRING_CANCEL = 394 "android.bluetooth.device.action.PAIRING_CANCEL"; 395 396 /** @hide */ 397 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 398 public static final String ACTION_CONNECTION_ACCESS_REQUEST = 399 "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST"; 400 401 /** @hide */ 402 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 403 public static final String ACTION_CONNECTION_ACCESS_REPLY = 404 "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY"; 405 406 /** @hide */ 407 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 408 public static final String ACTION_CONNECTION_ACCESS_CANCEL = 409 "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL"; 410 411 /** 412 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent. 413 * 414 * @hide 415 */ 416 public static final String EXTRA_ACCESS_REQUEST_TYPE = 417 "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE"; 418 419 /** @hide */ 420 public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1; 421 422 /** @hide */ 423 public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2; 424 425 /** @hide */ 426 public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3; 427 428 /** @hide */ 429 public static final int REQUEST_TYPE_SIM_ACCESS = 4; 430 431 /** 432 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, 433 * Contains package name to return reply intent to. 434 * 435 * @hide 436 */ 437 public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME"; 438 439 /** 440 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, 441 * Contains class name to return reply intent to. 442 * 443 * @hide 444 */ 445 public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME"; 446 447 /** 448 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent. 449 * 450 * @hide 451 */ 452 public static final String EXTRA_CONNECTION_ACCESS_RESULT = 453 "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT"; 454 455 /** @hide */ 456 public static final int CONNECTION_ACCESS_YES = 1; 457 458 /** @hide */ 459 public static final int CONNECTION_ACCESS_NO = 2; 460 461 /** 462 * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents, 463 * Contains boolean to indicate if the allowed response is once-for-all so that 464 * next request will be granted without asking user again. 465 * 466 * @hide 467 */ 468 public static final String EXTRA_ALWAYS_ALLOWED = 469 "android.bluetooth.device.extra.ALWAYS_ALLOWED"; 470 471 /** 472 * A bond attempt succeeded 473 * 474 * @hide 475 */ 476 public static final int BOND_SUCCESS = 0; 477 478 /** 479 * A bond attempt failed because pins did not match, or remote device did 480 * not respond to pin request in time 481 * 482 * @hide 483 */ 484 public static final int UNBOND_REASON_AUTH_FAILED = 1; 485 486 /** 487 * A bond attempt failed because the other side explicitly rejected 488 * bonding 489 * 490 * @hide 491 */ 492 public static final int UNBOND_REASON_AUTH_REJECTED = 2; 493 494 /** 495 * A bond attempt failed because we canceled the bonding process 496 * 497 * @hide 498 */ 499 public static final int UNBOND_REASON_AUTH_CANCELED = 3; 500 501 /** 502 * A bond attempt failed because we could not contact the remote device 503 * 504 * @hide 505 */ 506 public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4; 507 508 /** 509 * A bond attempt failed because a discovery is in progress 510 * 511 * @hide 512 */ 513 public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5; 514 515 /** 516 * A bond attempt failed because of authentication timeout 517 * 518 * @hide 519 */ 520 public static final int UNBOND_REASON_AUTH_TIMEOUT = 6; 521 522 /** 523 * A bond attempt failed because of repeated attempts 524 * 525 * @hide 526 */ 527 public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7; 528 529 /** 530 * A bond attempt failed because we received an Authentication Cancel 531 * by remote end 532 * 533 * @hide 534 */ 535 public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8; 536 537 /** 538 * An existing bond was explicitly revoked 539 * 540 * @hide 541 */ 542 public static final int UNBOND_REASON_REMOVED = 9; 543 544 /** 545 * The user will be prompted to enter a pin or 546 * an app will enter a pin for user. 547 */ 548 public static final int PAIRING_VARIANT_PIN = 0; 549 550 /** 551 * The user will be prompted to enter a passkey 552 * 553 * @hide 554 */ 555 public static final int PAIRING_VARIANT_PASSKEY = 1; 556 557 /** 558 * The user will be prompted to confirm the passkey displayed on the screen or 559 * an app will confirm the passkey for the user. 560 */ 561 public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2; 562 563 /** 564 * The user will be prompted to accept or deny the incoming pairing request 565 * 566 * @hide 567 */ 568 public static final int PAIRING_VARIANT_CONSENT = 3; 569 570 /** 571 * The user will be prompted to enter the passkey displayed on remote device 572 * This is used for Bluetooth 2.1 pairing. 573 * 574 * @hide 575 */ 576 public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4; 577 578 /** 579 * The user will be prompted to enter the PIN displayed on remote device. 580 * This is used for Bluetooth 2.0 pairing. 581 * 582 * @hide 583 */ 584 public static final int PAIRING_VARIANT_DISPLAY_PIN = 5; 585 586 /** 587 * The user will be prompted to accept or deny the OOB pairing request 588 * 589 * @hide 590 */ 591 public static final int PAIRING_VARIANT_OOB_CONSENT = 6; 592 593 /** 594 * The user will be prompted to enter a 16 digit pin or 595 * an app will enter a 16 digit pin for user. 596 * 597 * @hide 598 */ 599 public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7; 600 601 /** 602 * Used as an extra field in {@link #ACTION_UUID} intents, 603 * Contains the {@link android.os.ParcelUuid}s of the remote device which 604 * is a parcelable version of {@link UUID}. 605 */ 606 public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID"; 607 608 /** @hide */ 609 public static final String EXTRA_SDP_RECORD = 610 "android.bluetooth.device.extra.SDP_RECORD"; 611 612 /** @hide */ 613 public static final String EXTRA_SDP_SEARCH_STATUS = 614 "android.bluetooth.device.extra.SDP_SEARCH_STATUS"; 615 /** 616 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, 617 * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 618 * 619 * @hide 620 */ 621 @SystemApi 622 public static final int ACCESS_UNKNOWN = 0; 623 624 /** 625 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, 626 * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 627 * 628 * @hide 629 */ 630 @SystemApi 631 public static final int ACCESS_ALLOWED = 1; 632 633 /** 634 * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, 635 * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}. 636 * 637 * @hide 638 */ 639 @SystemApi 640 public static final int ACCESS_REJECTED = 2; 641 642 /** 643 * No preferrence of physical transport for GATT connections to remote dual-mode devices 644 */ 645 public static final int TRANSPORT_AUTO = 0; 646 647 /** 648 * Prefer BR/EDR transport for GATT connections to remote dual-mode devices 649 */ 650 public static final int TRANSPORT_BREDR = 1; 651 652 /** 653 * Prefer LE transport for GATT connections to remote dual-mode devices 654 */ 655 public static final int TRANSPORT_LE = 2; 656 657 /** 658 * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or 659 * connection. 660 */ 661 public static final int PHY_LE_1M = 1; 662 663 /** 664 * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or 665 * connection. 666 */ 667 public static final int PHY_LE_2M = 2; 668 669 /** 670 * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning 671 * or connection. 672 */ 673 public static final int PHY_LE_CODED = 3; 674 675 /** 676 * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available 677 * options in a bitmask. 678 */ 679 public static final int PHY_LE_1M_MASK = 1; 680 681 /** 682 * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available 683 * options in a bitmask. 684 */ 685 public static final int PHY_LE_2M_MASK = 2; 686 687 /** 688 * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many 689 * available options in a bitmask. 690 */ 691 public static final int PHY_LE_CODED_MASK = 4; 692 693 /** 694 * No preferred coding when transmitting on the LE Coded PHY. 695 */ 696 public static final int PHY_OPTION_NO_PREFERRED = 0; 697 698 /** 699 * Prefer the S=2 coding to be used when transmitting on the LE Coded PHY. 700 */ 701 public static final int PHY_OPTION_S2 = 1; 702 703 /** 704 * Prefer the S=8 coding to be used when transmitting on the LE Coded PHY. 705 */ 706 public static final int PHY_OPTION_S8 = 2; 707 708 709 /** @hide */ 710 public static final String EXTRA_MAS_INSTANCE = 711 "android.bluetooth.device.extra.MAS_INSTANCE"; 712 713 /** 714 * Lazy initialization. Guaranteed final after first object constructed, or 715 * getService() called. 716 * TODO: Unify implementation of sService amongst BluetoothFoo API's 717 */ 718 private static volatile IBluetooth sService; 719 720 private final String mAddress; 721 722 /*package*/ getService()723 static IBluetooth getService() { 724 synchronized (BluetoothDevice.class) { 725 if (sService == null) { 726 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 727 sService = adapter.getBluetoothService(sStateChangeCallback); 728 } 729 } 730 return sService; 731 } 732 733 static IBluetoothManagerCallback sStateChangeCallback = new IBluetoothManagerCallback.Stub() { 734 735 public void onBluetoothServiceUp(IBluetooth bluetoothService) 736 throws RemoteException { 737 synchronized (BluetoothDevice.class) { 738 if (sService == null) { 739 sService = bluetoothService; 740 } 741 } 742 } 743 744 public void onBluetoothServiceDown() 745 throws RemoteException { 746 synchronized (BluetoothDevice.class) { 747 sService = null; 748 } 749 } 750 751 public void onBrEdrDown() { 752 if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state"); 753 } 754 }; 755 756 /** 757 * Create a new BluetoothDevice 758 * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB", 759 * and is validated in this constructor. 760 * 761 * @param address valid Bluetooth MAC address 762 * @throws RuntimeException Bluetooth is not available on this platform 763 * @throws IllegalArgumentException address is invalid 764 * @hide 765 */ BluetoothDevice(String address)766 /*package*/ BluetoothDevice(String address) { 767 getService(); // ensures sService is initialized 768 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 769 throw new IllegalArgumentException(address + " is not a valid Bluetooth address"); 770 } 771 772 mAddress = address; 773 } 774 775 @Override equals(Object o)776 public boolean equals(Object o) { 777 if (o instanceof BluetoothDevice) { 778 return mAddress.equals(((BluetoothDevice) o).getAddress()); 779 } 780 return false; 781 } 782 783 @Override hashCode()784 public int hashCode() { 785 return mAddress.hashCode(); 786 } 787 788 /** 789 * Returns a string representation of this BluetoothDevice. 790 * <p>Currently this is the Bluetooth hardware address, for example 791 * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress} 792 * if you explicitly require the Bluetooth hardware address in case the 793 * {@link #toString} representation changes in the future. 794 * 795 * @return string representation of this BluetoothDevice 796 */ 797 @Override toString()798 public String toString() { 799 return mAddress; 800 } 801 802 @Override describeContents()803 public int describeContents() { 804 return 0; 805 } 806 807 public static final Parcelable.Creator<BluetoothDevice> CREATOR = 808 new Parcelable.Creator<BluetoothDevice>() { 809 public BluetoothDevice createFromParcel(Parcel in) { 810 return new BluetoothDevice(in.readString()); 811 } 812 813 public BluetoothDevice[] newArray(int size) { 814 return new BluetoothDevice[size]; 815 } 816 }; 817 818 @Override writeToParcel(Parcel out, int flags)819 public void writeToParcel(Parcel out, int flags) { 820 out.writeString(mAddress); 821 } 822 823 /** 824 * Returns the hardware address of this BluetoothDevice. 825 * <p> For example, "00:11:22:AA:BB:CC". 826 * 827 * @return Bluetooth hardware address as string 828 */ getAddress()829 public String getAddress() { 830 if (DBG) Log.d(TAG, "mAddress: " + mAddress); 831 return mAddress; 832 } 833 834 /** 835 * Get the friendly Bluetooth name of the remote device. 836 * 837 * <p>The local adapter will automatically retrieve remote names when 838 * performing a device scan, and will cache them. This method just returns 839 * the name for this device from the cache. 840 * 841 * @return the Bluetooth name, or null if there was a problem. 842 */ 843 @RequiresPermission(Manifest.permission.BLUETOOTH) getName()844 public String getName() { 845 final IBluetooth service = sService; 846 if (service == null) { 847 Log.e(TAG, "BT not enabled. Cannot get Remote Device name"); 848 return null; 849 } 850 try { 851 String name = service.getRemoteName(this); 852 if (name != null) { 853 return name.replaceAll("[\\t\\n\\r]+", " "); 854 } 855 return null; 856 } catch (RemoteException e) { 857 Log.e(TAG, "", e); 858 } 859 return null; 860 } 861 862 /** 863 * Get the Bluetooth device type of the remote device. 864 * 865 * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} {@link 866 * #DEVICE_TYPE_DUAL}. {@link #DEVICE_TYPE_UNKNOWN} if it's not available 867 */ 868 @RequiresPermission(Manifest.permission.BLUETOOTH) getType()869 public int getType() { 870 final IBluetooth service = sService; 871 if (service == null) { 872 Log.e(TAG, "BT not enabled. Cannot get Remote Device type"); 873 return DEVICE_TYPE_UNKNOWN; 874 } 875 try { 876 return service.getRemoteType(this); 877 } catch (RemoteException e) { 878 Log.e(TAG, "", e); 879 } 880 return DEVICE_TYPE_UNKNOWN; 881 } 882 883 /** 884 * Get the Bluetooth alias of the remote device. 885 * <p>Alias is the locally modified name of a remote device. 886 * 887 * @return the Bluetooth alias, or null if no alias or there was a problem 888 * @hide 889 */ getAlias()890 public String getAlias() { 891 final IBluetooth service = sService; 892 if (service == null) { 893 Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias"); 894 return null; 895 } 896 try { 897 return service.getRemoteAlias(this); 898 } catch (RemoteException e) { 899 Log.e(TAG, "", e); 900 } 901 return null; 902 } 903 904 /** 905 * Set the Bluetooth alias of the remote device. 906 * <p>Alias is the locally modified name of a remote device. 907 * <p>This methoid overwrites the alias. The changed 908 * alias is saved in the local storage so that the change 909 * is preserved over power cycle. 910 * 911 * @return true on success, false on error 912 * @hide 913 */ setAlias(String alias)914 public boolean setAlias(String alias) { 915 final IBluetooth service = sService; 916 if (service == null) { 917 Log.e(TAG, "BT not enabled. Cannot set Remote Device name"); 918 return false; 919 } 920 try { 921 return service.setRemoteAlias(this, alias); 922 } catch (RemoteException e) { 923 Log.e(TAG, "", e); 924 } 925 return false; 926 } 927 928 /** 929 * Get the Bluetooth alias of the remote device. 930 * If Alias is null, get the Bluetooth name instead. 931 * 932 * @return the Bluetooth alias, or null if no alias or there was a problem 933 * @hide 934 * @see #getAlias() 935 * @see #getName() 936 */ getAliasName()937 public String getAliasName() { 938 String name = getAlias(); 939 if (name == null) { 940 name = getName(); 941 } 942 return name; 943 } 944 945 /** 946 * Get the most recent identified battery level of this Bluetooth device 947 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 948 * 949 * @return Battery level in percents from 0 to 100, or {@link #BATTERY_LEVEL_UNKNOWN} if 950 * Bluetooth is disabled, or device is disconnected, or does not have any battery reporting 951 * service, or return value is invalid 952 * @hide 953 */ 954 @RequiresPermission(Manifest.permission.BLUETOOTH) getBatteryLevel()955 public int getBatteryLevel() { 956 final IBluetooth service = sService; 957 if (service == null) { 958 Log.e(TAG, "Bluetooth disabled. Cannot get remote device battery level"); 959 return BATTERY_LEVEL_UNKNOWN; 960 } 961 try { 962 return service.getBatteryLevel(this); 963 } catch (RemoteException e) { 964 Log.e(TAG, "", e); 965 } 966 return BATTERY_LEVEL_UNKNOWN; 967 } 968 969 /** 970 * Start the bonding (pairing) process with the remote device. 971 * <p>This is an asynchronous call, it will return immediately. Register 972 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 973 * the bonding process completes, and its result. 974 * <p>Android system services will handle the necessary user interactions 975 * to confirm and complete the bonding process. 976 * 977 * @return false on immediate error, true if bonding will begin 978 */ 979 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) createBond()980 public boolean createBond() { 981 final IBluetooth service = sService; 982 if (service == null) { 983 Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device"); 984 return false; 985 } 986 try { 987 Log.i(TAG, "createBond() for device " + getAddress() 988 + " called by pid: " + Process.myPid() 989 + " tid: " + Process.myTid()); 990 return service.createBond(this, TRANSPORT_AUTO); 991 } catch (RemoteException e) { 992 Log.e(TAG, "", e); 993 } 994 return false; 995 } 996 997 /** 998 * Start the bonding (pairing) process with the remote device using the 999 * specified transport. 1000 * 1001 * <p>This is an asynchronous call, it will return immediately. Register 1002 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 1003 * the bonding process completes, and its result. 1004 * <p>Android system services will handle the necessary user interactions 1005 * to confirm and complete the bonding process. 1006 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 1007 * 1008 * @param transport The transport to use for the pairing procedure. 1009 * @return false on immediate error, true if bonding will begin 1010 * @throws IllegalArgumentException if an invalid transport was specified 1011 * @hide 1012 */ createBond(int transport)1013 public boolean createBond(int transport) { 1014 final IBluetooth service = sService; 1015 if (service == null) { 1016 Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device"); 1017 return false; 1018 } 1019 if (TRANSPORT_AUTO > transport || transport > TRANSPORT_LE) { 1020 throw new IllegalArgumentException(transport + " is not a valid Bluetooth transport"); 1021 } 1022 try { 1023 Log.i(TAG, "createBond() for device " + getAddress() 1024 + " called by pid: " + Process.myPid() 1025 + " tid: " + Process.myTid()); 1026 return service.createBond(this, transport); 1027 } catch (RemoteException e) { 1028 Log.e(TAG, "", e); 1029 } 1030 return false; 1031 } 1032 1033 /** 1034 * Start the bonding (pairing) process with the remote device using the 1035 * Out Of Band mechanism. 1036 * 1037 * <p>This is an asynchronous call, it will return immediately. Register 1038 * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when 1039 * the bonding process completes, and its result. 1040 * 1041 * <p>Android system services will handle the necessary user interactions 1042 * to confirm and complete the bonding process. 1043 * 1044 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 1045 * 1046 * @param transport - Transport to use 1047 * @param oobData - Out Of Band data 1048 * @return false on immediate error, true if bonding will begin 1049 * @hide 1050 */ createBondOutOfBand(int transport, OobData oobData)1051 public boolean createBondOutOfBand(int transport, OobData oobData) { 1052 final IBluetooth service = sService; 1053 if (service == null) { 1054 Log.w(TAG, "BT not enabled, createBondOutOfBand failed"); 1055 return false; 1056 } 1057 try { 1058 return service.createBondOutOfBand(this, transport, oobData); 1059 } catch (RemoteException e) { 1060 Log.e(TAG, "", e); 1061 } 1062 return false; 1063 } 1064 1065 /** @hide */ isBondingInitiatedLocally()1066 public boolean isBondingInitiatedLocally() { 1067 final IBluetooth service = sService; 1068 if (service == null) { 1069 Log.w(TAG, "BT not enabled, isBondingInitiatedLocally failed"); 1070 return false; 1071 } 1072 try { 1073 return service.isBondingInitiatedLocally(this); 1074 } catch (RemoteException e) { 1075 Log.e(TAG, "", e); 1076 } 1077 return false; 1078 } 1079 1080 /** 1081 * Set the Out Of Band data for a remote device to be used later 1082 * in the pairing mechanism. Users can obtain this data through other 1083 * trusted channels 1084 * 1085 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 1086 * 1087 * @param hash Simple Secure pairing hash 1088 * @param randomizer The random key obtained using OOB 1089 * @return false on error; true otherwise 1090 * @hide 1091 */ setDeviceOutOfBandData(byte[] hash, byte[] randomizer)1092 public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) { 1093 //TODO(BT) 1094 /* 1095 try { 1096 return sService.setDeviceOutOfBandData(this, hash, randomizer); 1097 } catch (RemoteException e) {Log.e(TAG, "", e);} */ 1098 return false; 1099 } 1100 1101 /** 1102 * Cancel an in-progress bonding request started with {@link #createBond}. 1103 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 1104 * 1105 * @return true on success, false on error 1106 * @hide 1107 */ 1108 @SystemApi 1109 @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) cancelBondProcess()1110 public boolean cancelBondProcess() { 1111 final IBluetooth service = sService; 1112 if (service == null) { 1113 Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond"); 1114 return false; 1115 } 1116 try { 1117 Log.i(TAG, "cancelBondProcess() for device " + getAddress() 1118 + " called by pid: " + Process.myPid() 1119 + " tid: " + Process.myTid()); 1120 return service.cancelBondProcess(this); 1121 } catch (RemoteException e) { 1122 Log.e(TAG, "", e); 1123 } 1124 return false; 1125 } 1126 1127 /** 1128 * Remove bond (pairing) with the remote device. 1129 * <p>Delete the link key associated with the remote device, and 1130 * immediately terminate connections to that device that require 1131 * authentication and encryption. 1132 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 1133 * 1134 * @return true on success, false on error 1135 * @hide 1136 */ 1137 @SystemApi 1138 @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) removeBond()1139 public boolean removeBond() { 1140 final IBluetooth service = sService; 1141 if (service == null) { 1142 Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond"); 1143 return false; 1144 } 1145 try { 1146 Log.i(TAG, "removeBond() for device " + getAddress() 1147 + " called by pid: " + Process.myPid() 1148 + " tid: " + Process.myTid()); 1149 return service.removeBond(this); 1150 } catch (RemoteException e) { 1151 Log.e(TAG, "", e); 1152 } 1153 return false; 1154 } 1155 1156 /** 1157 * Get the bond state of the remote device. 1158 * <p>Possible values for the bond state are: 1159 * {@link #BOND_NONE}, 1160 * {@link #BOND_BONDING}, 1161 * {@link #BOND_BONDED}. 1162 * 1163 * @return the bond state 1164 */ 1165 @RequiresPermission(Manifest.permission.BLUETOOTH) getBondState()1166 public int getBondState() { 1167 final IBluetooth service = sService; 1168 if (service == null) { 1169 Log.e(TAG, "BT not enabled. Cannot get bond state"); 1170 return BOND_NONE; 1171 } 1172 try { 1173 return service.getBondState(this); 1174 } catch (RemoteException e) { 1175 Log.e(TAG, "", e); 1176 } 1177 return BOND_NONE; 1178 } 1179 1180 /** 1181 * Returns whether there is an open connection to this device. 1182 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 1183 * 1184 * @return True if there is at least one open connection to this device. 1185 * @hide 1186 */ 1187 @SystemApi 1188 @RequiresPermission(android.Manifest.permission.BLUETOOTH) isConnected()1189 public boolean isConnected() { 1190 final IBluetooth service = sService; 1191 if (service == null) { 1192 // BT is not enabled, we cannot be connected. 1193 return false; 1194 } 1195 try { 1196 return service.getConnectionState(this) != CONNECTION_STATE_DISCONNECTED; 1197 } catch (RemoteException e) { 1198 Log.e(TAG, "", e); 1199 return false; 1200 } 1201 } 1202 1203 /** 1204 * Returns whether there is an open connection to this device 1205 * that has been encrypted. 1206 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 1207 * 1208 * @return True if there is at least one encrypted connection to this device. 1209 * @hide 1210 */ 1211 @SystemApi 1212 @RequiresPermission(android.Manifest.permission.BLUETOOTH) isEncrypted()1213 public boolean isEncrypted() { 1214 final IBluetooth service = sService; 1215 if (service == null) { 1216 // BT is not enabled, we cannot be connected. 1217 return false; 1218 } 1219 try { 1220 return service.getConnectionState(this) > CONNECTION_STATE_CONNECTED; 1221 } catch (RemoteException e) { 1222 Log.e(TAG, "", e); 1223 return false; 1224 } 1225 } 1226 1227 /** 1228 * Get the Bluetooth class of the remote device. 1229 * 1230 * @return Bluetooth class object, or null on error 1231 */ 1232 @RequiresPermission(Manifest.permission.BLUETOOTH) getBluetoothClass()1233 public BluetoothClass getBluetoothClass() { 1234 final IBluetooth service = sService; 1235 if (service == null) { 1236 Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class"); 1237 return null; 1238 } 1239 try { 1240 int classInt = service.getRemoteClass(this); 1241 if (classInt == BluetoothClass.ERROR) return null; 1242 return new BluetoothClass(classInt); 1243 } catch (RemoteException e) { 1244 Log.e(TAG, "", e); 1245 } 1246 return null; 1247 } 1248 1249 /** 1250 * Returns the supported features (UUIDs) of the remote device. 1251 * 1252 * <p>This method does not start a service discovery procedure to retrieve the UUIDs 1253 * from the remote device. Instead, the local cached copy of the service 1254 * UUIDs are returned. 1255 * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired. 1256 * 1257 * @return the supported features (UUIDs) of the remote device, or null on error 1258 */ 1259 @RequiresPermission(Manifest.permission.BLUETOOTH) getUuids()1260 public ParcelUuid[] getUuids() { 1261 final IBluetooth service = sService; 1262 if (service == null || !isBluetoothEnabled()) { 1263 Log.e(TAG, "BT not enabled. Cannot get remote device Uuids"); 1264 return null; 1265 } 1266 try { 1267 return service.getRemoteUuids(this); 1268 } catch (RemoteException e) { 1269 Log.e(TAG, "", e); 1270 } 1271 return null; 1272 } 1273 1274 /** 1275 * Perform a service discovery on the remote device to get the UUIDs supported. 1276 * 1277 * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent, 1278 * with the UUIDs supported by the remote end. If there is an error 1279 * in getting the SDP records or if the process takes a long time, 1280 * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently 1281 * present in the cache. Clients should use the {@link #getUuids} to get UUIDs 1282 * if service discovery is not to be performed. 1283 * 1284 * @return False if the sanity check fails, True if the process of initiating an ACL connection 1285 * to the remote device was started. 1286 */ 1287 @RequiresPermission(Manifest.permission.BLUETOOTH) fetchUuidsWithSdp()1288 public boolean fetchUuidsWithSdp() { 1289 final IBluetooth service = sService; 1290 if (service == null || !isBluetoothEnabled()) { 1291 Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp"); 1292 return false; 1293 } 1294 try { 1295 return service.fetchRemoteUuids(this); 1296 } catch (RemoteException e) { 1297 Log.e(TAG, "", e); 1298 } 1299 return false; 1300 } 1301 1302 /** 1303 * Perform a service discovery on the remote device to get the SDP records associated 1304 * with the specified UUID. 1305 * 1306 * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent, 1307 * with the SDP records found on the remote end. If there is an error 1308 * in getting the SDP records or if the process takes a long time, 1309 * {@link #ACTION_SDP_RECORD} intent is sent with an status value in 1310 * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0. 1311 * Detailed status error codes can be found by members of the Bluetooth package in 1312 * the AbstractionLayer class. 1313 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 1314 * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}. 1315 * The object type will match one of the SdpXxxRecord types, depending on the UUID searched 1316 * for. 1317 * 1318 * @return False if the sanity check fails, True if the process 1319 * of initiating an ACL connection to the remote device 1320 * was started. 1321 */ 1322 /** @hide */ sdpSearch(ParcelUuid uuid)1323 public boolean sdpSearch(ParcelUuid uuid) { 1324 final IBluetooth service = sService; 1325 if (service == null) { 1326 Log.e(TAG, "BT not enabled. Cannot query remote device sdp records"); 1327 return false; 1328 } 1329 try { 1330 return service.sdpSearch(this, uuid); 1331 } catch (RemoteException e) { 1332 Log.e(TAG, "", e); 1333 } 1334 return false; 1335 } 1336 1337 /** 1338 * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN} 1339 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 1340 * 1341 * @return true pin has been set false for error 1342 */ setPin(byte[] pin)1343 public boolean setPin(byte[] pin) { 1344 final IBluetooth service = sService; 1345 if (service == null) { 1346 Log.e(TAG, "BT not enabled. Cannot set Remote Device pin"); 1347 return false; 1348 } 1349 try { 1350 return service.setPin(this, true, pin.length, pin); 1351 } catch (RemoteException e) { 1352 Log.e(TAG, "", e); 1353 } 1354 return false; 1355 } 1356 1357 /** @hide */ setPasskey(int passkey)1358 public boolean setPasskey(int passkey) { 1359 //TODO(BT) 1360 /* 1361 try { 1362 return sService.setPasskey(this, true, 4, passkey); 1363 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 1364 return false; 1365 } 1366 1367 /** 1368 * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing. 1369 * 1370 * @return true confirmation has been sent out false for error 1371 */ 1372 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) setPairingConfirmation(boolean confirm)1373 public boolean setPairingConfirmation(boolean confirm) { 1374 final IBluetooth service = sService; 1375 if (service == null) { 1376 Log.e(TAG, "BT not enabled. Cannot set pairing confirmation"); 1377 return false; 1378 } 1379 try { 1380 return service.setPairingConfirmation(this, confirm); 1381 } catch (RemoteException e) { 1382 Log.e(TAG, "", e); 1383 } 1384 return false; 1385 } 1386 1387 /** @hide */ setRemoteOutOfBandData()1388 public boolean setRemoteOutOfBandData() { 1389 // TODO(BT) 1390 /* 1391 try { 1392 return sService.setRemoteOutOfBandData(this); 1393 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 1394 return false; 1395 } 1396 1397 /** @hide */ cancelPairingUserInput()1398 public boolean cancelPairingUserInput() { 1399 final IBluetooth service = sService; 1400 if (service == null) { 1401 Log.e(TAG, "BT not enabled. Cannot create pairing user input"); 1402 return false; 1403 } 1404 try { 1405 return service.cancelBondProcess(this); 1406 } catch (RemoteException e) { 1407 Log.e(TAG, "", e); 1408 } 1409 return false; 1410 } 1411 1412 /** @hide */ isBluetoothDock()1413 public boolean isBluetoothDock() { 1414 // TODO(BT) 1415 /* 1416 try { 1417 return sService.isBluetoothDock(this); 1418 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 1419 return false; 1420 } 1421 isBluetoothEnabled()1422 boolean isBluetoothEnabled() { 1423 boolean ret = false; 1424 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1425 if (adapter != null && adapter.isEnabled()) { 1426 ret = true; 1427 } 1428 return ret; 1429 } 1430 1431 /** 1432 * Requires {@link android.Manifest.permission#BLUETOOTH}. 1433 * 1434 * @return Whether the phonebook access is allowed to this device. Can be {@link 1435 * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. 1436 * @hide 1437 */ getPhonebookAccessPermission()1438 public int getPhonebookAccessPermission() { 1439 final IBluetooth service = sService; 1440 if (service == null) { 1441 return ACCESS_UNKNOWN; 1442 } 1443 try { 1444 return service.getPhonebookAccessPermission(this); 1445 } catch (RemoteException e) { 1446 Log.e(TAG, "", e); 1447 } 1448 return ACCESS_UNKNOWN; 1449 } 1450 1451 /** 1452 * Sets whether the phonebook access is allowed to this device. 1453 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. 1454 * 1455 * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link 1456 * #ACCESS_REJECTED}. 1457 * @return Whether the value has been successfully set. 1458 * @hide 1459 */ 1460 @SystemApi 1461 @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) setPhonebookAccessPermission(int value)1462 public boolean setPhonebookAccessPermission(int value) { 1463 final IBluetooth service = sService; 1464 if (service == null) { 1465 return false; 1466 } 1467 try { 1468 return service.setPhonebookAccessPermission(this, value); 1469 } catch (RemoteException e) { 1470 Log.e(TAG, "", e); 1471 } 1472 return false; 1473 } 1474 1475 /** 1476 * Requires {@link android.Manifest.permission#BLUETOOTH}. 1477 * 1478 * @return Whether the message access is allowed to this device. Can be {@link #ACCESS_UNKNOWN}, 1479 * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. 1480 * @hide 1481 */ getMessageAccessPermission()1482 public int getMessageAccessPermission() { 1483 final IBluetooth service = sService; 1484 if (service == null) { 1485 return ACCESS_UNKNOWN; 1486 } 1487 try { 1488 return service.getMessageAccessPermission(this); 1489 } catch (RemoteException e) { 1490 Log.e(TAG, "", e); 1491 } 1492 return ACCESS_UNKNOWN; 1493 } 1494 1495 /** 1496 * Sets whether the message access is allowed to this device. 1497 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. 1498 * 1499 * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link 1500 * #ACCESS_REJECTED}. 1501 * @return Whether the value has been successfully set. 1502 * @hide 1503 */ setMessageAccessPermission(int value)1504 public boolean setMessageAccessPermission(int value) { 1505 final IBluetooth service = sService; 1506 if (service == null) { 1507 return false; 1508 } 1509 try { 1510 return service.setMessageAccessPermission(this, value); 1511 } catch (RemoteException e) { 1512 Log.e(TAG, "", e); 1513 } 1514 return false; 1515 } 1516 1517 /** 1518 * Requires {@link android.Manifest.permission#BLUETOOTH}. 1519 * 1520 * @return Whether the Sim access is allowed to this device. Can be {@link #ACCESS_UNKNOWN}, 1521 * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}. 1522 * @hide 1523 */ getSimAccessPermission()1524 public int getSimAccessPermission() { 1525 final IBluetooth service = sService; 1526 if (service == null) { 1527 return ACCESS_UNKNOWN; 1528 } 1529 try { 1530 return service.getSimAccessPermission(this); 1531 } catch (RemoteException e) { 1532 Log.e(TAG, "", e); 1533 } 1534 return ACCESS_UNKNOWN; 1535 } 1536 1537 /** 1538 * Sets whether the Sim access is allowed to this device. 1539 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. 1540 * 1541 * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link 1542 * #ACCESS_REJECTED}. 1543 * @return Whether the value has been successfully set. 1544 * @hide 1545 */ setSimAccessPermission(int value)1546 public boolean setSimAccessPermission(int value) { 1547 final IBluetooth service = sService; 1548 if (service == null) { 1549 return false; 1550 } 1551 try { 1552 return service.setSimAccessPermission(this, value); 1553 } catch (RemoteException e) { 1554 Log.e(TAG, "", e); 1555 } 1556 return false; 1557 } 1558 1559 /** 1560 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 1561 * outgoing connection to this remote device on given channel. 1562 * <p>The remote device will be authenticated and communication on this 1563 * socket will be encrypted. 1564 * <p> Use this socket only if an authenticated socket link is possible. 1565 * Authentication refers to the authentication of the link key to 1566 * prevent man-in-the-middle type of attacks. 1567 * For example, for Bluetooth 2.1 devices, if any of the devices does not 1568 * have an input and output capability or just has the ability to 1569 * display a numeric key, a secure socket connection is not possible. 1570 * In such a case, use {#link createInsecureRfcommSocket}. 1571 * For more details, refer to the Security Model section 5.2 (vol 3) of 1572 * Bluetooth Core Specification version 2.1 + EDR. 1573 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1574 * connection. 1575 * <p>Valid RFCOMM channels are in range 1 to 30. 1576 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1577 * 1578 * @param channel RFCOMM channel to connect to 1579 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1580 * @throws IOException on error, for example Bluetooth not available, or insufficient 1581 * permissions 1582 * @hide 1583 */ createRfcommSocket(int channel)1584 public BluetoothSocket createRfcommSocket(int channel) throws IOException { 1585 if (!isBluetoothEnabled()) { 1586 Log.e(TAG, "Bluetooth is not enabled"); 1587 throw new IOException(); 1588 } 1589 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel, 1590 null); 1591 } 1592 1593 /** 1594 * Create an L2cap {@link BluetoothSocket} ready to start a secure 1595 * outgoing connection to this remote device on given channel. 1596 * <p>The remote device will be authenticated and communication on this 1597 * socket will be encrypted. 1598 * <p> Use this socket only if an authenticated socket link is possible. 1599 * Authentication refers to the authentication of the link key to 1600 * prevent man-in-the-middle type of attacks. 1601 * For example, for Bluetooth 2.1 devices, if any of the devices does not 1602 * have an input and output capability or just has the ability to 1603 * display a numeric key, a secure socket connection is not possible. 1604 * In such a case, use {#link createInsecureRfcommSocket}. 1605 * For more details, refer to the Security Model section 5.2 (vol 3) of 1606 * Bluetooth Core Specification version 2.1 + EDR. 1607 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1608 * connection. 1609 * <p>Valid L2CAP PSM channels are in range 1 to 2^16. 1610 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1611 * 1612 * @param channel L2cap PSM/channel to connect to 1613 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1614 * @throws IOException on error, for example Bluetooth not available, or insufficient 1615 * permissions 1616 * @hide 1617 */ createL2capSocket(int channel)1618 public BluetoothSocket createL2capSocket(int channel) throws IOException { 1619 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel, 1620 null); 1621 } 1622 1623 /** 1624 * Create an L2cap {@link BluetoothSocket} ready to start an insecure 1625 * outgoing connection to this remote device on given channel. 1626 * <p>The remote device will be not authenticated and communication on this 1627 * socket will not be encrypted. 1628 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1629 * connection. 1630 * <p>Valid L2CAP PSM channels are in range 1 to 2^16. 1631 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1632 * 1633 * @param channel L2cap PSM/channel to connect to 1634 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1635 * @throws IOException on error, for example Bluetooth not available, or insufficient 1636 * permissions 1637 * @hide 1638 */ createInsecureL2capSocket(int channel)1639 public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException { 1640 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel, 1641 null); 1642 } 1643 1644 /** 1645 * Create an RFCOMM {@link BluetoothSocket} ready to start a secure 1646 * outgoing connection to this remote device using SDP lookup of uuid. 1647 * <p>This is designed to be used with {@link 1648 * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer 1649 * Bluetooth applications. 1650 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1651 * connection. This will also perform an SDP lookup of the given uuid to 1652 * determine which channel to connect to. 1653 * <p>The remote device will be authenticated and communication on this 1654 * socket will be encrypted. 1655 * <p> Use this socket only if an authenticated socket link is possible. 1656 * Authentication refers to the authentication of the link key to 1657 * prevent man-in-the-middle type of attacks. 1658 * For example, for Bluetooth 2.1 devices, if any of the devices does not 1659 * have an input and output capability or just has the ability to 1660 * display a numeric key, a secure socket connection is not possible. 1661 * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}. 1662 * For more details, refer to the Security Model section 5.2 (vol 3) of 1663 * Bluetooth Core Specification version 2.1 + EDR. 1664 * <p>Hint: If you are connecting to a Bluetooth serial board then try 1665 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 1666 * However if you are connecting to an Android peer then please generate 1667 * your own unique UUID. 1668 * 1669 * @param uuid service record uuid to lookup RFCOMM channel 1670 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1671 * @throws IOException on error, for example Bluetooth not available, or insufficient 1672 * permissions 1673 */ 1674 @RequiresPermission(Manifest.permission.BLUETOOTH) createRfcommSocketToServiceRecord(UUID uuid)1675 public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException { 1676 if (!isBluetoothEnabled()) { 1677 Log.e(TAG, "Bluetooth is not enabled"); 1678 throw new IOException(); 1679 } 1680 1681 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1, 1682 new ParcelUuid(uuid)); 1683 } 1684 1685 /** 1686 * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure 1687 * outgoing connection to this remote device using SDP lookup of uuid. 1688 * <p> The communication channel will not have an authenticated link key 1689 * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1 1690 * devices, the link key will be encrypted, as encryption is mandatory. 1691 * For legacy devices (pre Bluetooth 2.1 devices) the link key will 1692 * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an 1693 * encrypted and authenticated communication channel is desired. 1694 * <p>This is designed to be used with {@link 1695 * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer 1696 * Bluetooth applications. 1697 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing 1698 * connection. This will also perform an SDP lookup of the given uuid to 1699 * determine which channel to connect to. 1700 * <p>The remote device will be authenticated and communication on this 1701 * socket will be encrypted. 1702 * <p>Hint: If you are connecting to a Bluetooth serial board then try 1703 * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB. 1704 * However if you are connecting to an Android peer then please generate 1705 * your own unique UUID. 1706 * 1707 * @param uuid service record uuid to lookup RFCOMM channel 1708 * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection 1709 * @throws IOException on error, for example Bluetooth not available, or insufficient 1710 * permissions 1711 */ 1712 @RequiresPermission(Manifest.permission.BLUETOOTH) createInsecureRfcommSocketToServiceRecord(UUID uuid)1713 public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException { 1714 if (!isBluetoothEnabled()) { 1715 Log.e(TAG, "Bluetooth is not enabled"); 1716 throw new IOException(); 1717 } 1718 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1, 1719 new ParcelUuid(uuid)); 1720 } 1721 1722 /** 1723 * Construct an insecure RFCOMM socket ready to start an outgoing 1724 * connection. 1725 * Call #connect on the returned #BluetoothSocket to begin the connection. 1726 * The remote device will not be authenticated and communication on this 1727 * socket will not be encrypted. 1728 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 1729 * 1730 * @param port remote port 1731 * @return An RFCOMM BluetoothSocket 1732 * @throws IOException On error, for example Bluetooth not available, or insufficient 1733 * permissions. 1734 * @hide 1735 */ createInsecureRfcommSocket(int port)1736 public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException { 1737 if (!isBluetoothEnabled()) { 1738 Log.e(TAG, "Bluetooth is not enabled"); 1739 throw new IOException(); 1740 } 1741 return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port, 1742 null); 1743 } 1744 1745 /** 1746 * Construct a SCO socket ready to start an outgoing connection. 1747 * Call #connect on the returned #BluetoothSocket to begin the connection. 1748 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 1749 * 1750 * @return a SCO BluetoothSocket 1751 * @throws IOException on error, for example Bluetooth not available, or insufficient 1752 * permissions. 1753 * @hide 1754 */ createScoSocket()1755 public BluetoothSocket createScoSocket() throws IOException { 1756 if (!isBluetoothEnabled()) { 1757 Log.e(TAG, "Bluetooth is not enabled"); 1758 throw new IOException(); 1759 } 1760 return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null); 1761 } 1762 1763 /** 1764 * Check that a pin is valid and convert to byte array. 1765 * 1766 * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters. 1767 * 1768 * @param pin pin as java String 1769 * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin. 1770 * @hide 1771 */ convertPinToBytes(String pin)1772 public static byte[] convertPinToBytes(String pin) { 1773 if (pin == null) { 1774 return null; 1775 } 1776 byte[] pinBytes; 1777 try { 1778 pinBytes = pin.getBytes("UTF-8"); 1779 } catch (UnsupportedEncodingException uee) { 1780 Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen 1781 return null; 1782 } 1783 if (pinBytes.length <= 0 || pinBytes.length > 16) { 1784 return null; 1785 } 1786 return pinBytes; 1787 } 1788 1789 /** 1790 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 1791 * The callback is used to deliver results to Caller, such as connection status as well 1792 * as any further GATT client operations. 1793 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 1794 * GATT client operations. 1795 * 1796 * @param callback GATT callback handler that will receive asynchronous callbacks. 1797 * @param autoConnect Whether to directly connect to the remote device (false) or to 1798 * automatically connect as soon as the remote device becomes available (true). 1799 * @throws IllegalArgumentException if callback is null 1800 */ connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)1801 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 1802 BluetoothGattCallback callback) { 1803 return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO)); 1804 } 1805 1806 /** 1807 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 1808 * The callback is used to deliver results to Caller, such as connection status as well 1809 * as any further GATT client operations. 1810 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 1811 * GATT client operations. 1812 * 1813 * @param callback GATT callback handler that will receive asynchronous callbacks. 1814 * @param autoConnect Whether to directly connect to the remote device (false) or to 1815 * automatically connect as soon as the remote device becomes available (true). 1816 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 1817 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 1818 * BluetoothDevice#TRANSPORT_LE} 1819 * @throws IllegalArgumentException if callback is null 1820 */ connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)1821 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 1822 BluetoothGattCallback callback, int transport) { 1823 return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK)); 1824 } 1825 1826 /** 1827 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 1828 * The callback is used to deliver results to Caller, such as connection status as well 1829 * as any further GATT client operations. 1830 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 1831 * GATT client operations. 1832 * 1833 * @param callback GATT callback handler that will receive asynchronous callbacks. 1834 * @param autoConnect Whether to directly connect to the remote device (false) or to 1835 * automatically connect as soon as the remote device becomes available (true). 1836 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 1837 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 1838 * BluetoothDevice#TRANSPORT_LE} 1839 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 1840 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link 1841 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} 1842 * is set to true. 1843 * @throws NullPointerException if callback is null 1844 */ connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy)1845 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 1846 BluetoothGattCallback callback, int transport, int phy) { 1847 return connectGatt(context, autoConnect, callback, transport, phy, null); 1848 } 1849 1850 /** 1851 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 1852 * The callback is used to deliver results to Caller, such as connection status as well 1853 * as any further GATT client operations. 1854 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 1855 * GATT client operations. 1856 * 1857 * @param callback GATT callback handler that will receive asynchronous callbacks. 1858 * @param autoConnect Whether to directly connect to the remote device (false) or to 1859 * automatically connect as soon as the remote device becomes available (true). 1860 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 1861 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 1862 * BluetoothDevice#TRANSPORT_LE} 1863 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 1864 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link 1865 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} 1866 * is set to true. 1867 * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on 1868 * an un-specified background thread. 1869 * @throws NullPointerException if callback is null 1870 */ connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler)1871 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 1872 BluetoothGattCallback callback, int transport, int phy, 1873 Handler handler) { 1874 return connectGatt(context, autoConnect, callback, transport, false, phy, handler); 1875 } 1876 1877 /** 1878 * Connect to GATT Server hosted by this device. Caller acts as GATT client. 1879 * The callback is used to deliver results to Caller, such as connection status as well 1880 * as any further GATT client operations. 1881 * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct 1882 * GATT client operations. 1883 * 1884 * @param callback GATT callback handler that will receive asynchronous callbacks. 1885 * @param autoConnect Whether to directly connect to the remote device (false) or to 1886 * automatically connect as soon as the remote device becomes available (true). 1887 * @param transport preferred transport for GATT connections to remote dual-mode devices {@link 1888 * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link 1889 * BluetoothDevice#TRANSPORT_LE} 1890 * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client 1891 * does not hold a GATT connection. It automatically disconnects when no other GATT connections 1892 * are active for the remote device. 1893 * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link 1894 * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link 1895 * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect} 1896 * is set to true. 1897 * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on 1898 * an un-specified background thread. 1899 * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client 1900 * operations. 1901 * @hide 1902 */ connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, boolean opportunistic, int phy, Handler handler)1903 public BluetoothGatt connectGatt(Context context, boolean autoConnect, 1904 BluetoothGattCallback callback, int transport, 1905 boolean opportunistic, int phy, Handler handler) { 1906 if (callback == null) { 1907 throw new NullPointerException("callback is null"); 1908 } 1909 1910 // TODO(Bluetooth) check whether platform support BLE 1911 // Do the check here or in GattServer? 1912 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1913 IBluetoothManager managerService = adapter.getBluetoothManager(); 1914 try { 1915 IBluetoothGatt iGatt = managerService.getBluetoothGatt(); 1916 if (iGatt == null) { 1917 // BLE is not supported 1918 return null; 1919 } 1920 BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport, opportunistic, phy); 1921 gatt.connect(autoConnect, callback, handler); 1922 return gatt; 1923 } catch (RemoteException e) { 1924 Log.e(TAG, "", e); 1925 } 1926 return null; 1927 } 1928 1929 /** 1930 * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can 1931 * be used to start a secure outgoing connection to the remote device with the same dynamic 1932 * protocol/service multiplexer (PSM) value. 1933 * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capCoc(int)} for 1934 * peer-peer Bluetooth applications. 1935 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 1936 * <p>Application using this API is responsible for obtaining PSM value from remote device. 1937 * <p>The remote device will be authenticated and communication on this socket will be 1938 * encrypted. 1939 * <p> Use this socket if an authenticated socket link is possible. Authentication refers 1940 * to the authentication of the link key to prevent man-in-the-middle type of attacks. When a 1941 * secure socket connection is not possible, use {#link createInsecureLeL2capCocSocket(int, 1942 * int)}. 1943 * 1944 * @param transport Bluetooth transport to use, must be {@link #TRANSPORT_LE} 1945 * @param psm dynamic PSM value from remote device 1946 * @return a CoC #BluetoothSocket ready for an outgoing connection 1947 * @throws IOException on error, for example Bluetooth not available, or insufficient 1948 * permissions 1949 * @hide 1950 */ 1951 @RequiresPermission(Manifest.permission.BLUETOOTH) createL2capCocSocket(int transport, int psm)1952 public BluetoothSocket createL2capCocSocket(int transport, int psm) throws IOException { 1953 if (!isBluetoothEnabled()) { 1954 Log.e(TAG, "createL2capCocSocket: Bluetooth is not enabled"); 1955 throw new IOException(); 1956 } 1957 if (transport != BluetoothDevice.TRANSPORT_LE) { 1958 throw new IllegalArgumentException("Unsupported transport: " + transport); 1959 } 1960 if (DBG) Log.d(TAG, "createL2capCocSocket: transport=" + transport + ", psm=" + psm); 1961 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm, 1962 null); 1963 } 1964 1965 /** 1966 * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can 1967 * be used to start a secure outgoing connection to the remote device with the same dynamic 1968 * protocol/service multiplexer (PSM) value. 1969 * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingInsecureL2capCoc(int)} 1970 * for peer-peer Bluetooth applications. 1971 * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. 1972 * <p>Application using this API is responsible for obtaining PSM value from remote device. 1973 * <p> The communication channel may not have an authenticated link key, i.e. it may be subject 1974 * to man-in-the-middle attacks. Use {@link #createL2capCocSocket(int, int)} if an encrypted and 1975 * authenticated communication channel is possible. 1976 * 1977 * @param transport Bluetooth transport to use, must be {@link #TRANSPORT_LE} 1978 * @param psm dynamic PSM value from remote device 1979 * @return a CoC #BluetoothSocket ready for an outgoing connection 1980 * @throws IOException on error, for example Bluetooth not available, or insufficient 1981 * permissions 1982 * @hide 1983 */ 1984 @RequiresPermission(Manifest.permission.BLUETOOTH) createInsecureL2capCocSocket(int transport, int psm)1985 public BluetoothSocket createInsecureL2capCocSocket(int transport, int psm) throws IOException { 1986 if (!isBluetoothEnabled()) { 1987 Log.e(TAG, "createInsecureL2capCocSocket: Bluetooth is not enabled"); 1988 throw new IOException(); 1989 } 1990 if (transport != BluetoothDevice.TRANSPORT_LE) { 1991 throw new IllegalArgumentException("Unsupported transport: " + transport); 1992 } 1993 if (DBG) { 1994 Log.d(TAG, "createInsecureL2capCocSocket: transport=" + transport + ", psm=" + psm); 1995 } 1996 return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm, 1997 null); 1998 } 1999 } 2000