1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.bluetooth; 18 19import android.Manifest; 20import android.annotation.RequiresPermission; 21import android.annotation.SdkConstant; 22import android.annotation.SdkConstant.SdkConstantType; 23import android.annotation.SystemApi; 24import android.content.Context; 25import android.os.Handler; 26import android.os.Parcel; 27import android.os.ParcelUuid; 28import android.os.Parcelable; 29import android.os.Process; 30import android.os.RemoteException; 31import android.util.Log; 32 33import java.io.IOException; 34import java.io.UnsupportedEncodingException; 35import 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 */ 73public 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*/ 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 */ 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 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 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 798 public String toString() { 799 return mAddress; 800 } 801 802 @Override 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 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 */ 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) 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) 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 */ 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 */ 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 */ 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) 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) 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 */ 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 */ 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 */ 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 */ 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) 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) 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) 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) 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) 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) 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) 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) 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 */ 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 */ 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 */ 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) 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 */ 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 */ 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 */ 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 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 */ 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) 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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) 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) 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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) 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) 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