1 /* 2 * Copyright 2009-2016 The Android Open Source Project 3 * Copyright 2015 Samsung LSI 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package android.bluetooth; 19 20 import android.Manifest; 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.RequiresPermission; 25 import android.annotation.SdkConstant; 26 import android.annotation.SdkConstant.SdkConstantType; 27 import android.annotation.SystemApi; 28 import android.app.ActivityThread; 29 import android.app.PropertyInvalidatedCache; 30 import android.bluetooth.BluetoothProfile.ConnectionPolicy; 31 import android.bluetooth.le.BluetoothLeAdvertiser; 32 import android.bluetooth.le.BluetoothLeScanner; 33 import android.bluetooth.le.PeriodicAdvertisingManager; 34 import android.bluetooth.le.ScanCallback; 35 import android.bluetooth.le.ScanFilter; 36 import android.bluetooth.le.ScanRecord; 37 import android.bluetooth.le.ScanResult; 38 import android.bluetooth.le.ScanSettings; 39 import android.compat.annotation.UnsupportedAppUsage; 40 import android.content.Context; 41 import android.os.BatteryStats; 42 import android.os.Binder; 43 import android.os.IBinder; 44 import android.os.ParcelUuid; 45 import android.os.RemoteException; 46 import android.os.ResultReceiver; 47 import android.os.ServiceManager; 48 import android.os.SynchronousResultReceiver; 49 import android.os.SystemProperties; 50 import android.util.Log; 51 import android.util.Pair; 52 53 import java.io.IOException; 54 import java.lang.annotation.Retention; 55 import java.lang.annotation.RetentionPolicy; 56 import java.util.ArrayList; 57 import java.util.Arrays; 58 import java.util.Collections; 59 import java.util.HashMap; 60 import java.util.HashSet; 61 import java.util.List; 62 import java.util.Locale; 63 import java.util.Map; 64 import java.util.Set; 65 import java.util.UUID; 66 import java.util.concurrent.Executor; 67 import java.util.concurrent.TimeoutException; 68 import java.util.concurrent.locks.ReentrantReadWriteLock; 69 70 /** 71 * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter} 72 * lets you perform fundamental Bluetooth tasks, such as initiate 73 * device discovery, query a list of bonded (paired) devices, 74 * instantiate a {@link BluetoothDevice} using a known MAC address, and create 75 * a {@link BluetoothServerSocket} to listen for connection requests from other 76 * devices, and start a scan for Bluetooth LE devices. 77 * 78 * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth 79 * adapter, call the {@link BluetoothManager#getAdapter} function on {@link BluetoothManager}. 80 * On JELLY_BEAN_MR1 and below you will need to use the static {@link #getDefaultAdapter} 81 * method instead. 82 * </p><p> 83 * Fundamentally, this is your starting point for all 84 * Bluetooth actions. Once you have the local adapter, you can get a set of 85 * {@link BluetoothDevice} objects representing all paired devices with 86 * {@link #getBondedDevices()}; start device discovery with 87 * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to 88 * listen for incoming RFComm connection requests with {@link 89 * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented 90 * Channels (CoC) connection requests with {@link #listenUsingL2capChannel()}; or start a scan for 91 * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. 92 * </p> 93 * <p>This class is thread safe.</p> 94 * <p class="note"><strong>Note:</strong> 95 * Most methods require the {@link android.Manifest.permission#BLUETOOTH} 96 * permission and some also require the 97 * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 98 * </p> 99 * <div class="special reference"> 100 * <h3>Developer Guides</h3> 101 * <p> 102 * For more information about using Bluetooth, read the <a href= 103 * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer 104 * guide. 105 * </p> 106 * </div> 107 * 108 * {@see BluetoothDevice} 109 * {@see BluetoothServerSocket} 110 */ 111 public final class BluetoothAdapter { 112 private static final String TAG = "BluetoothAdapter"; 113 private static final boolean DBG = true; 114 private static final boolean VDBG = false; 115 116 /** 117 * Default MAC address reported to a client that does not have the 118 * android.permission.LOCAL_MAC_ADDRESS permission. 119 * 120 * @hide 121 */ 122 public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; 123 124 /** 125 * Sentinel error value for this class. Guaranteed to not equal any other 126 * integer constant in this class. Provided as a convenience for functions 127 * that require a sentinel error value, for example: 128 * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 129 * BluetoothAdapter.ERROR)</code> 130 */ 131 public static final int ERROR = Integer.MIN_VALUE; 132 133 /** 134 * Broadcast Action: The state of the local Bluetooth adapter has been 135 * changed. 136 * <p>For example, Bluetooth has been turned on or off. 137 * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link 138 * #EXTRA_PREVIOUS_STATE} containing the new and old states 139 * respectively. 140 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 141 */ 142 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String 143 ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED"; 144 145 /** 146 * Used as an int extra field in {@link #ACTION_STATE_CHANGED} 147 * intents to request the current power state. Possible values are: 148 * {@link #STATE_OFF}, 149 * {@link #STATE_TURNING_ON}, 150 * {@link #STATE_ON}, 151 * {@link #STATE_TURNING_OFF}, 152 */ 153 public static final String EXTRA_STATE = "android.bluetooth.adapter.extra.STATE"; 154 /** 155 * Used as an int extra field in {@link #ACTION_STATE_CHANGED} 156 * intents to request the previous power state. Possible values are: 157 * {@link #STATE_OFF}, 158 * {@link #STATE_TURNING_ON}, 159 * {@link #STATE_ON}, 160 * {@link #STATE_TURNING_OFF} 161 */ 162 public static final String EXTRA_PREVIOUS_STATE = 163 "android.bluetooth.adapter.extra.PREVIOUS_STATE"; 164 165 /** @hide */ 166 @IntDef(prefix = { "STATE_" }, value = { 167 STATE_OFF, 168 STATE_TURNING_ON, 169 STATE_ON, 170 STATE_TURNING_OFF, 171 STATE_BLE_TURNING_ON, 172 STATE_BLE_ON, 173 STATE_BLE_TURNING_OFF 174 }) 175 @Retention(RetentionPolicy.SOURCE) 176 public @interface AdapterState {} 177 178 /** 179 * Indicates the local Bluetooth adapter is off. 180 */ 181 public static final int STATE_OFF = 10; 182 /** 183 * Indicates the local Bluetooth adapter is turning on. However local 184 * clients should wait for {@link #STATE_ON} before attempting to 185 * use the adapter. 186 */ 187 public static final int STATE_TURNING_ON = 11; 188 /** 189 * Indicates the local Bluetooth adapter is on, and ready for use. 190 */ 191 public static final int STATE_ON = 12; 192 /** 193 * Indicates the local Bluetooth adapter is turning off. Local clients 194 * should immediately attempt graceful disconnection of any remote links. 195 */ 196 public static final int STATE_TURNING_OFF = 13; 197 198 /** 199 * Indicates the local Bluetooth adapter is turning Bluetooth LE mode on. 200 * 201 * @hide 202 */ 203 public static final int STATE_BLE_TURNING_ON = 14; 204 205 /** 206 * Indicates the local Bluetooth adapter is in LE only mode. 207 * 208 * @hide 209 */ 210 public static final int STATE_BLE_ON = 15; 211 212 /** 213 * Indicates the local Bluetooth adapter is turning off LE only mode. 214 * 215 * @hide 216 */ 217 public static final int STATE_BLE_TURNING_OFF = 16; 218 219 /** 220 * UUID of the GATT Read Characteristics for LE_PSM value. 221 * 222 * @hide 223 */ 224 public static final UUID LE_PSM_CHARACTERISTIC_UUID = 225 UUID.fromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a"); 226 227 /** 228 * Human-readable string helper for AdapterState 229 * 230 * @hide 231 */ nameForState(@dapterState int state)232 public static String nameForState(@AdapterState int state) { 233 switch (state) { 234 case STATE_OFF: 235 return "OFF"; 236 case STATE_TURNING_ON: 237 return "TURNING_ON"; 238 case STATE_ON: 239 return "ON"; 240 case STATE_TURNING_OFF: 241 return "TURNING_OFF"; 242 case STATE_BLE_TURNING_ON: 243 return "BLE_TURNING_ON"; 244 case STATE_BLE_ON: 245 return "BLE_ON"; 246 case STATE_BLE_TURNING_OFF: 247 return "BLE_TURNING_OFF"; 248 default: 249 return "?!?!? (" + state + ")"; 250 } 251 } 252 253 /** 254 * Activity Action: Show a system activity that requests discoverable mode. 255 * This activity will also request the user to turn on Bluetooth if it 256 * is not currently enabled. 257 * <p>Discoverable mode is equivalent to {@link 258 * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see 259 * this Bluetooth adapter when they perform a discovery. 260 * <p>For privacy, Android is not discoverable by default. 261 * <p>The sender of this Intent can optionally use extra field {@link 262 * #EXTRA_DISCOVERABLE_DURATION} to request the duration of 263 * discoverability. Currently the default duration is 120 seconds, and 264 * maximum duration is capped at 300 seconds for each request. 265 * <p>Notification of the result of this activity is posted using the 266 * {@link android.app.Activity#onActivityResult} callback. The 267 * <code>resultCode</code> 268 * will be the duration (in seconds) of discoverability or 269 * {@link android.app.Activity#RESULT_CANCELED} if the user rejected 270 * discoverability or an error has occurred. 271 * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED} 272 * for global notification whenever the scan mode changes. For example, an 273 * application can be notified when the device has ended discoverability. 274 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 275 */ 276 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String 277 ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"; 278 279 /** 280 * Used as an optional int extra field in {@link 281 * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration 282 * for discoverability in seconds. The current default is 120 seconds, and 283 * requests over 300 seconds will be capped. These values could change. 284 */ 285 public static final String EXTRA_DISCOVERABLE_DURATION = 286 "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; 287 288 /** 289 * Activity Action: Show a system activity that allows the user to turn on 290 * Bluetooth. 291 * <p>This system activity will return once Bluetooth has completed turning 292 * on, or the user has decided not to turn Bluetooth on. 293 * <p>Notification of the result of this activity is posted using the 294 * {@link android.app.Activity#onActivityResult} callback. The 295 * <code>resultCode</code> 296 * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been 297 * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user 298 * has rejected the request or an error has occurred. 299 * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED} 300 * for global notification whenever Bluetooth is turned on or off. 301 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 302 */ 303 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String 304 ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"; 305 306 /** 307 * Activity Action: Show a system activity that allows the user to turn off 308 * Bluetooth. This is used only if permission review is enabled which is for 309 * apps targeting API less than 23 require a permission review before any of 310 * the app's components can run. 311 * <p>This system activity will return once Bluetooth has completed turning 312 * off, or the user has decided not to turn Bluetooth off. 313 * <p>Notification of the result of this activity is posted using the 314 * {@link android.app.Activity#onActivityResult} callback. The 315 * <code>resultCode</code> 316 * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been 317 * turned off or {@link android.app.Activity#RESULT_CANCELED} if the user 318 * has rejected the request or an error has occurred. 319 * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED} 320 * for global notification whenever Bluetooth is turned on or off. 321 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 322 * 323 * @hide 324 */ 325 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String 326 ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE"; 327 328 /** 329 * Activity Action: Show a system activity that allows user to enable BLE scans even when 330 * Bluetooth is turned off.<p> 331 * 332 * Notification of result of this activity is posted using 333 * {@link android.app.Activity#onActivityResult}. The <code>resultCode</code> will be 334 * {@link android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or 335 * {@link android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an 336 * error occurred. 337 * 338 * @hide 339 */ 340 @SystemApi 341 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 342 public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = 343 "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE"; 344 345 /** 346 * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter 347 * has changed. 348 * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link 349 * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes 350 * respectively. 351 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 352 */ 353 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String 354 ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; 355 356 /** 357 * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} 358 * intents to request the current scan mode. Possible values are: 359 * {@link #SCAN_MODE_NONE}, 360 * {@link #SCAN_MODE_CONNECTABLE}, 361 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, 362 */ 363 public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE"; 364 /** 365 * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} 366 * intents to request the previous scan mode. Possible values are: 367 * {@link #SCAN_MODE_NONE}, 368 * {@link #SCAN_MODE_CONNECTABLE}, 369 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, 370 */ 371 public static final String EXTRA_PREVIOUS_SCAN_MODE = 372 "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE"; 373 374 /** @hide */ 375 @IntDef(prefix = { "SCAN_" }, value = { 376 SCAN_MODE_NONE, 377 SCAN_MODE_CONNECTABLE, 378 SCAN_MODE_CONNECTABLE_DISCOVERABLE 379 }) 380 @Retention(RetentionPolicy.SOURCE) 381 public @interface ScanMode {} 382 383 /** 384 * Indicates that both inquiry scan and page scan are disabled on the local 385 * Bluetooth adapter. Therefore this device is neither discoverable 386 * nor connectable from remote Bluetooth devices. 387 */ 388 public static final int SCAN_MODE_NONE = 20; 389 /** 390 * Indicates that inquiry scan is disabled, but page scan is enabled on the 391 * local Bluetooth adapter. Therefore this device is not discoverable from 392 * remote Bluetooth devices, but is connectable from remote devices that 393 * have previously discovered this device. 394 */ 395 public static final int SCAN_MODE_CONNECTABLE = 21; 396 /** 397 * Indicates that both inquiry scan and page scan are enabled on the local 398 * Bluetooth adapter. Therefore this device is both discoverable and 399 * connectable from remote Bluetooth devices. 400 */ 401 public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; 402 403 /** 404 * Device only has a display. 405 * 406 * @hide 407 */ 408 public static final int IO_CAPABILITY_OUT = 0; 409 410 /** 411 * Device has a display and the ability to input Yes/No. 412 * 413 * @hide 414 */ 415 public static final int IO_CAPABILITY_IO = 1; 416 417 /** 418 * Device only has a keyboard for entry but no display. 419 * 420 * @hide 421 */ 422 public static final int IO_CAPABILITY_IN = 2; 423 424 /** 425 * Device has no Input or Output capability. 426 * 427 * @hide 428 */ 429 public static final int IO_CAPABILITY_NONE = 3; 430 431 /** 432 * Device has a display and a full keyboard. 433 * 434 * @hide 435 */ 436 public static final int IO_CAPABILITY_KBDISP = 4; 437 438 /** 439 * Maximum range value for Input/Output capabilities. 440 * 441 * <p>This should be updated when adding a new Input/Output capability. Other code 442 * like validation depends on this being accurate. 443 * 444 * @hide 445 */ 446 public static final int IO_CAPABILITY_MAX = 5; 447 448 /** 449 * The Input/Output capability of the device is unknown. 450 * 451 * @hide 452 */ 453 public static final int IO_CAPABILITY_UNKNOWN = 255; 454 455 /** @hide */ 456 @IntDef({IO_CAPABILITY_OUT, IO_CAPABILITY_IO, IO_CAPABILITY_IN, IO_CAPABILITY_NONE, 457 IO_CAPABILITY_KBDISP}) 458 @Retention(RetentionPolicy.SOURCE) 459 public @interface IoCapability {} 460 461 /** @hide */ 462 @IntDef(prefix = "ACTIVE_DEVICE_", value = {ACTIVE_DEVICE_AUDIO, 463 ACTIVE_DEVICE_PHONE_CALL, ACTIVE_DEVICE_ALL}) 464 @Retention(RetentionPolicy.SOURCE) 465 public @interface ActiveDeviceUse {} 466 467 /** 468 * Use the specified device for audio (a2dp and hearing aid profile) 469 * 470 * @hide 471 */ 472 @SystemApi 473 public static final int ACTIVE_DEVICE_AUDIO = 0; 474 475 /** 476 * Use the specified device for phone calls (headset profile and hearing 477 * aid profile) 478 * 479 * @hide 480 */ 481 @SystemApi 482 public static final int ACTIVE_DEVICE_PHONE_CALL = 1; 483 484 /** 485 * Use the specified device for a2dp, hearing aid profile, and headset profile 486 * 487 * @hide 488 */ 489 @SystemApi 490 public static final int ACTIVE_DEVICE_ALL = 2; 491 492 /** 493 * Broadcast Action: The local Bluetooth adapter has started the remote 494 * device discovery process. 495 * <p>This usually involves an inquiry scan of about 12 seconds, followed 496 * by a page scan of each new device to retrieve its Bluetooth name. 497 * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as 498 * remote Bluetooth devices are found. 499 * <p>Device discovery is a heavyweight procedure. New connections to 500 * remote Bluetooth devices should not be attempted while discovery is in 501 * progress, and existing connections will experience limited bandwidth 502 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing 503 * discovery. 504 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 505 */ 506 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String 507 ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED"; 508 /** 509 * Broadcast Action: The local Bluetooth adapter has finished the device 510 * discovery process. 511 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 512 */ 513 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String 514 ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED"; 515 516 /** 517 * Broadcast Action: The local Bluetooth adapter has changed its friendly 518 * Bluetooth name. 519 * <p>This name is visible to remote Bluetooth devices. 520 * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing 521 * the name. 522 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 523 */ 524 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String 525 ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED"; 526 /** 527 * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED} 528 * intents to request the local Bluetooth name. 529 */ 530 public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME"; 531 532 /** 533 * Intent used to broadcast the change in connection state of the local 534 * Bluetooth adapter to a profile of the remote device. When the adapter is 535 * not connected to any profiles of any remote devices and it attempts a 536 * connection to a profile this intent will be sent. Once connected, this intent 537 * will not be sent for any more connection attempts to any profiles of any 538 * remote device. When the adapter disconnects from the last profile its 539 * connected to of any remote device, this intent will be sent. 540 * 541 * <p> This intent is useful for applications that are only concerned about 542 * whether the local adapter is connected to any profile of any device and 543 * are not really concerned about which profile. For example, an application 544 * which displays an icon to display whether Bluetooth is connected or not 545 * can use this intent. 546 * 547 * <p>This intent will have 3 extras: 548 * {@link #EXTRA_CONNECTION_STATE} - The current connection state. 549 * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state. 550 * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. 551 * 552 * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE} 553 * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, 554 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. 555 * 556 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 557 */ 558 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String 559 ACTION_CONNECTION_STATE_CHANGED = 560 "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"; 561 562 /** 563 * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} 564 * 565 * This extra represents the current connection state. 566 */ 567 public static final String EXTRA_CONNECTION_STATE = 568 "android.bluetooth.adapter.extra.CONNECTION_STATE"; 569 570 /** 571 * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} 572 * 573 * This extra represents the previous connection state. 574 */ 575 public static final String EXTRA_PREVIOUS_CONNECTION_STATE = 576 "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE"; 577 578 /** 579 * Broadcast Action: The Bluetooth adapter state has changed in LE only mode. 580 * 581 * @hide 582 */ 583 @SystemApi public static final String ACTION_BLE_STATE_CHANGED = 584 "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; 585 586 /** 587 * Intent used to broadcast the change in the Bluetooth address 588 * of the local Bluetooth adapter. 589 * <p>Always contains the extra field {@link 590 * #EXTRA_BLUETOOTH_ADDRESS} containing the Bluetooth address. 591 * 592 * Note: only system level processes are allowed to send this 593 * defined broadcast. 594 * 595 * @hide 596 */ 597 public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED = 598 "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED"; 599 600 /** 601 * Used as a String extra field in {@link 602 * #ACTION_BLUETOOTH_ADDRESS_CHANGED} intent to store the local 603 * Bluetooth address. 604 * 605 * @hide 606 */ 607 public static final String EXTRA_BLUETOOTH_ADDRESS = 608 "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS"; 609 610 /** 611 * Broadcast Action: The notifys Bluetooth ACL connected event. This will be 612 * by BLE Always on enabled application to know the ACL_CONNECTED event 613 * when Bluetooth state in STATE_BLE_ON. This denotes GATT connection 614 * as Bluetooth LE is the only feature available in STATE_BLE_ON 615 * 616 * This is counterpart of {@link BluetoothDevice#ACTION_ACL_CONNECTED} which 617 * works in Bluetooth state STATE_ON 618 * 619 * @hide 620 */ 621 public static final String ACTION_BLE_ACL_CONNECTED = 622 "android.bluetooth.adapter.action.BLE_ACL_CONNECTED"; 623 624 /** 625 * Broadcast Action: The notifys Bluetooth ACL connected event. This will be 626 * by BLE Always on enabled application to know the ACL_DISCONNECTED event 627 * when Bluetooth state in STATE_BLE_ON. This denotes GATT disconnection as Bluetooth 628 * LE is the only feature available in STATE_BLE_ON 629 * 630 * This is counterpart of {@link BluetoothDevice#ACTION_ACL_DISCONNECTED} which 631 * works in Bluetooth state STATE_ON 632 * 633 * @hide 634 */ 635 public static final String ACTION_BLE_ACL_DISCONNECTED = 636 "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED"; 637 638 /** The profile is in disconnected state */ 639 public static final int STATE_DISCONNECTED = BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED; 640 /** The profile is in connecting state */ 641 public static final int STATE_CONNECTING = BluetoothProtoEnums.CONNECTION_STATE_CONNECTING; 642 /** The profile is in connected state */ 643 public static final int STATE_CONNECTED = BluetoothProtoEnums.CONNECTION_STATE_CONNECTED; 644 /** The profile is in disconnecting state */ 645 public static final int STATE_DISCONNECTING = 646 BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING; 647 648 /** @hide */ 649 public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; 650 private final IBinder mToken; 651 652 653 /** 654 * When creating a ServerSocket using listenUsingRfcommOn() or 655 * listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create 656 * a ServerSocket that auto assigns a channel number to the first 657 * bluetooth socket. 658 * The channel number assigned to this first Bluetooth Socket will 659 * be stored in the ServerSocket, and reused for subsequent Bluetooth 660 * sockets. 661 * 662 * @hide 663 */ 664 public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2; 665 666 667 private static final int ADDRESS_LENGTH = 17; 668 669 /** 670 * Lazily initialized singleton. Guaranteed final after first object 671 * constructed. 672 */ 673 private static BluetoothAdapter sAdapter; 674 675 private static BluetoothLeScanner sBluetoothLeScanner; 676 private static BluetoothLeAdvertiser sBluetoothLeAdvertiser; 677 private static PeriodicAdvertisingManager sPeriodicAdvertisingManager; 678 679 private final IBluetoothManager mManagerService; 680 @UnsupportedAppUsage 681 private IBluetooth mService; 682 private Context mContext; 683 private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); 684 685 private final Object mLock = new Object(); 686 private final Map<LeScanCallback, ScanCallback> mLeScanClients; 687 private static final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>> 688 sMetadataListeners = new HashMap<>(); 689 690 /** 691 * Bluetooth metadata listener. Overrides the default BluetoothMetadataListener 692 * implementation. 693 */ 694 private static final IBluetoothMetadataListener sBluetoothMetadataListener = 695 new IBluetoothMetadataListener.Stub() { 696 @Override 697 public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) { 698 synchronized (sMetadataListeners) { 699 if (sMetadataListeners.containsKey(device)) { 700 List<Pair<OnMetadataChangedListener, Executor>> list = 701 sMetadataListeners.get(device); 702 for (Pair<OnMetadataChangedListener, Executor> pair : list) { 703 OnMetadataChangedListener listener = pair.first; 704 Executor executor = pair.second; 705 executor.execute(() -> { 706 listener.onMetadataChanged(device, key, value); 707 }); 708 } 709 } 710 } 711 return; 712 } 713 }; 714 715 /** 716 * Get a handle to the default local Bluetooth adapter. 717 * <p>Currently Android only supports one Bluetooth adapter, but the API 718 * could be extended to support more. This will always return the default 719 * adapter. 720 * </p> 721 * 722 * @return the default local adapter, or null if Bluetooth is not supported on this hardware 723 * platform 724 */ getDefaultAdapter()725 public static synchronized BluetoothAdapter getDefaultAdapter() { 726 if (sAdapter == null) { 727 IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE); 728 if (b != null) { 729 IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b); 730 sAdapter = new BluetoothAdapter(managerService); 731 } else { 732 Log.e(TAG, "Bluetooth binder is null"); 733 } 734 } 735 return sAdapter; 736 } 737 738 /** 739 * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. 740 */ BluetoothAdapter(IBluetoothManager managerService)741 BluetoothAdapter(IBluetoothManager managerService) { 742 743 if (managerService == null) { 744 throw new IllegalArgumentException("bluetooth manager service is null"); 745 } 746 try { 747 mServiceLock.writeLock().lock(); 748 mService = managerService.registerAdapter(mManagerCallback); 749 } catch (RemoteException e) { 750 Log.e(TAG, "", e); 751 } finally { 752 mServiceLock.writeLock().unlock(); 753 } 754 mManagerService = managerService; 755 mLeScanClients = new HashMap<LeScanCallback, ScanCallback>(); 756 mToken = new Binder(); 757 } 758 759 /** 760 * Get a {@link BluetoothDevice} object for the given Bluetooth hardware 761 * address. 762 * <p>Valid Bluetooth hardware addresses must be upper case, in a format 763 * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is 764 * available to validate a Bluetooth address. 765 * <p>A {@link BluetoothDevice} will always be returned for a valid 766 * hardware address, even if this adapter has never seen that device. 767 * 768 * @param address valid Bluetooth MAC address 769 * @throws IllegalArgumentException if address is invalid 770 */ getRemoteDevice(String address)771 public BluetoothDevice getRemoteDevice(String address) { 772 return new BluetoothDevice(address); 773 } 774 775 /** 776 * Get a {@link BluetoothDevice} object for the given Bluetooth hardware 777 * address. 778 * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method 779 * expects the address in network byte order (MSB first). 780 * <p>A {@link BluetoothDevice} will always be returned for a valid 781 * hardware address, even if this adapter has never seen that device. 782 * 783 * @param address Bluetooth MAC address (6 bytes) 784 * @throws IllegalArgumentException if address is invalid 785 */ getRemoteDevice(byte[] address)786 public BluetoothDevice getRemoteDevice(byte[] address) { 787 if (address == null || address.length != 6) { 788 throw new IllegalArgumentException("Bluetooth address must have 6 bytes"); 789 } 790 return new BluetoothDevice( 791 String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1], 792 address[2], address[3], address[4], address[5])); 793 } 794 795 /** 796 * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations. 797 * Will return null if Bluetooth is turned off or if Bluetooth LE Advertising is not 798 * supported on this device. 799 * <p> 800 * Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported 801 * on this device before calling this method. 802 */ getBluetoothLeAdvertiser()803 public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { 804 if (!getLeAccess()) { 805 return null; 806 } 807 synchronized (mLock) { 808 if (sBluetoothLeAdvertiser == null) { 809 sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); 810 } 811 } 812 return sBluetoothLeAdvertiser; 813 } 814 815 /** 816 * Returns a {@link PeriodicAdvertisingManager} object for Bluetooth LE Periodic Advertising 817 * operations. Will return null if Bluetooth is turned off or if Bluetooth LE Periodic 818 * Advertising is not supported on this device. 819 * <p> 820 * Use {@link #isLePeriodicAdvertisingSupported()} to check whether LE Periodic Advertising is 821 * supported on this device before calling this method. 822 * 823 * @hide 824 */ getPeriodicAdvertisingManager()825 public PeriodicAdvertisingManager getPeriodicAdvertisingManager() { 826 if (!getLeAccess()) { 827 return null; 828 } 829 830 if (!isLePeriodicAdvertisingSupported()) { 831 return null; 832 } 833 834 synchronized (mLock) { 835 if (sPeriodicAdvertisingManager == null) { 836 sPeriodicAdvertisingManager = new PeriodicAdvertisingManager(mManagerService); 837 } 838 } 839 return sPeriodicAdvertisingManager; 840 } 841 842 /** 843 * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. 844 */ getBluetoothLeScanner()845 public BluetoothLeScanner getBluetoothLeScanner() { 846 if (!getLeAccess()) { 847 return null; 848 } 849 synchronized (mLock) { 850 if (sBluetoothLeScanner == null) { 851 sBluetoothLeScanner = new BluetoothLeScanner(mManagerService, getOpPackageName(), 852 getAttributionTag()); 853 } 854 } 855 return sBluetoothLeScanner; 856 } 857 858 /** 859 * Return true if Bluetooth is currently enabled and ready for use. 860 * <p>Equivalent to: 861 * <code>getBluetoothState() == STATE_ON</code> 862 * 863 * @return true if the local adapter is turned on 864 */ 865 @RequiresPermission(Manifest.permission.BLUETOOTH) isEnabled()866 public boolean isEnabled() { 867 return getState() == BluetoothAdapter.STATE_ON; 868 } 869 870 /** 871 * Return true if Bluetooth LE(Always BLE On feature) is currently 872 * enabled and ready for use 873 * <p>This returns true if current state is either STATE_ON or STATE_BLE_ON 874 * 875 * @return true if the local Bluetooth LE adapter is turned on 876 * @hide 877 */ 878 @SystemApi isLeEnabled()879 public boolean isLeEnabled() { 880 final int state = getLeState(); 881 if (DBG) { 882 Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state)); 883 } 884 return (state == BluetoothAdapter.STATE_ON 885 || state == BluetoothAdapter.STATE_BLE_ON 886 || state == BluetoothAdapter.STATE_TURNING_ON 887 || state == BluetoothAdapter.STATE_TURNING_OFF); 888 } 889 890 /** 891 * Turns off Bluetooth LE which was earlier turned on by calling enableBLE(). 892 * 893 * <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition 894 * to STATE_OFF and completely shut-down Bluetooth 895 * 896 * <p> If the Adapter state is STATE_ON, This would unregister the existance of 897 * special Bluetooth LE application and hence the further turning off of Bluetooth 898 * from UI would ensure the complete turn-off of Bluetooth rather than staying back 899 * BLE only state 900 * 901 * <p>This is an asynchronous call: it will return immediately, and 902 * clients should listen for {@link #ACTION_BLE_STATE_CHANGED} 903 * to be notified of subsequent adapter state changes If this call returns 904 * true, then the adapter state will immediately transition from {@link 905 * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time 906 * later transition to either {@link #STATE_BLE_ON} or {@link 907 * #STATE_OFF} based on the existance of the further Always BLE ON enabled applications 908 * If this call returns false then there was an 909 * immediate problem that will prevent the QAdapter from being turned off - 910 * such as the QAadapter already being turned off. 911 * 912 * @return true to indicate success, or false on immediate error 913 * @hide 914 */ 915 @SystemApi disableBLE()916 public boolean disableBLE() { 917 if (!isBleScanAlwaysAvailable()) { 918 return false; 919 } 920 String packageName = ActivityThread.currentPackageName(); 921 try { 922 return mManagerService.disableBle(packageName, mToken); 923 } catch (RemoteException e) { 924 Log.e(TAG, "", e); 925 } 926 return false; 927 } 928 929 /** 930 * Applications who want to only use Bluetooth Low Energy (BLE) can call enableBLE. 931 * 932 * enableBLE registers the existence of an app using only LE functions. 933 * 934 * enableBLE may enable Bluetooth to an LE only mode so that an app can use 935 * LE related features (BluetoothGatt or BluetoothGattServer classes) 936 * 937 * If the user disables Bluetooth while an app is registered to use LE only features, 938 * Bluetooth will remain on in LE only mode for the app. 939 * 940 * When Bluetooth is in LE only mode, it is not shown as ON to the UI. 941 * 942 * <p>This is an asynchronous call: it returns immediately, and 943 * clients should listen for {@link #ACTION_BLE_STATE_CHANGED} 944 * to be notified of adapter state changes. 945 * 946 * If this call returns * true, then the adapter state is either in a mode where 947 * LE is available, or will transition from {@link #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, 948 * and some time later transition to either {@link #STATE_OFF} or {@link #STATE_BLE_ON}. 949 * 950 * If this call returns false then there was an immediate problem that prevents the 951 * adapter from being turned on - such as Airplane mode. 952 * 953 * {@link #ACTION_BLE_STATE_CHANGED} returns the Bluetooth Adapter's various 954 * states, It includes all the classic Bluetooth Adapter states along with 955 * internal BLE only states 956 * 957 * @return true to indicate Bluetooth LE will be available, or false on immediate error 958 * @hide 959 */ 960 @SystemApi enableBLE()961 public boolean enableBLE() { 962 if (!isBleScanAlwaysAvailable()) { 963 return false; 964 } 965 String packageName = ActivityThread.currentPackageName(); 966 try { 967 return mManagerService.enableBle(packageName, mToken); 968 } catch (RemoteException e) { 969 Log.e(TAG, "", e); 970 } 971 972 return false; 973 } 974 975 private static final String BLUETOOTH_GET_STATE_CACHE_PROPERTY = "cache_key.bluetooth.get_state"; 976 977 private final PropertyInvalidatedCache<Void, Integer> mBluetoothGetStateCache = 978 new PropertyInvalidatedCache<Void, Integer>( 979 8, BLUETOOTH_GET_STATE_CACHE_PROPERTY) { 980 @Override 981 protected Integer recompute(Void query) { 982 try { 983 return mService.getState(); 984 } catch (RemoteException e) { 985 throw e.rethrowFromSystemServer(); 986 } 987 } 988 }; 989 990 /** @hide */ disableBluetoothGetStateCache()991 public void disableBluetoothGetStateCache() { 992 mBluetoothGetStateCache.disableLocal(); 993 } 994 995 /** @hide */ invalidateBluetoothGetStateCache()996 public static void invalidateBluetoothGetStateCache() { 997 PropertyInvalidatedCache.invalidateCache(BLUETOOTH_GET_STATE_CACHE_PROPERTY); 998 } 999 1000 /** 1001 * Fetch the current bluetooth state. If the service is down, return 1002 * OFF. 1003 */ 1004 @AdapterState getStateInternal()1005 private int getStateInternal() { 1006 int state = BluetoothAdapter.STATE_OFF; 1007 try { 1008 mServiceLock.readLock().lock(); 1009 if (mService != null) { 1010 state = mBluetoothGetStateCache.query(null); 1011 } 1012 } catch (RuntimeException e) { 1013 if (e.getCause() instanceof RemoteException) { 1014 Log.e(TAG, "", e.getCause()); 1015 } else { 1016 throw e; 1017 } 1018 } finally { 1019 mServiceLock.readLock().unlock(); 1020 } 1021 return state; 1022 } 1023 1024 /** 1025 * Get the current state of the local Bluetooth adapter. 1026 * <p>Possible return values are 1027 * {@link #STATE_OFF}, 1028 * {@link #STATE_TURNING_ON}, 1029 * {@link #STATE_ON}, 1030 * {@link #STATE_TURNING_OFF}. 1031 * 1032 * @return current state of Bluetooth adapter 1033 */ 1034 @RequiresPermission(Manifest.permission.BLUETOOTH) 1035 @AdapterState getState()1036 public int getState() { 1037 int state = getStateInternal(); 1038 1039 // Consider all internal states as OFF 1040 if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON 1041 || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { 1042 if (VDBG) { 1043 Log.d(TAG, "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF"); 1044 } 1045 state = BluetoothAdapter.STATE_OFF; 1046 } 1047 if (VDBG) { 1048 Log.d(TAG, "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState( 1049 state)); 1050 } 1051 return state; 1052 } 1053 1054 /** 1055 * Get the current state of the local Bluetooth adapter 1056 * <p>This returns current internal state of Adapter including LE ON/OFF 1057 * 1058 * <p>Possible return values are 1059 * {@link #STATE_OFF}, 1060 * {@link #STATE_BLE_TURNING_ON}, 1061 * {@link #STATE_BLE_ON}, 1062 * {@link #STATE_TURNING_ON}, 1063 * {@link #STATE_ON}, 1064 * {@link #STATE_TURNING_OFF}, 1065 * {@link #STATE_BLE_TURNING_OFF}. 1066 * 1067 * @return current state of Bluetooth adapter 1068 * @hide 1069 */ 1070 @RequiresPermission(Manifest.permission.BLUETOOTH) 1071 @AdapterState 1072 @UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine " 1073 + "whether you can use BLE & BT classic.") getLeState()1074 public int getLeState() { 1075 int state = getStateInternal(); 1076 1077 if (VDBG) { 1078 Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state)); 1079 } 1080 return state; 1081 } 1082 getLeAccess()1083 boolean getLeAccess() { 1084 if (getLeState() == STATE_ON) { 1085 return true; 1086 } else if (getLeState() == STATE_BLE_ON) { 1087 return true; // TODO: FILTER SYSTEM APPS HERE <-- 1088 } 1089 1090 return false; 1091 } 1092 1093 /** 1094 * Turn on the local Bluetooth adapter—do not use without explicit 1095 * user action to turn on Bluetooth. 1096 * <p>This powers on the underlying Bluetooth hardware, and starts all 1097 * Bluetooth system services. 1098 * <p class="caution"><strong>Bluetooth should never be enabled without 1099 * direct user consent</strong>. If you want to turn on Bluetooth in order 1100 * to create a wireless connection, you should use the {@link 1101 * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests 1102 * user permission to turn on Bluetooth. The {@link #enable()} method is 1103 * provided only for applications that include a user interface for changing 1104 * system settings, such as a "power manager" app.</p> 1105 * <p>This is an asynchronous call: it will return immediately, and 1106 * clients should listen for {@link #ACTION_STATE_CHANGED} 1107 * to be notified of subsequent adapter state changes. If this call returns 1108 * true, then the adapter state will immediately transition from {@link 1109 * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time 1110 * later transition to either {@link #STATE_OFF} or {@link 1111 * #STATE_ON}. If this call returns false then there was an 1112 * immediate problem that will prevent the adapter from being turned on - 1113 * such as Airplane mode, or the adapter is already turned on. 1114 * 1115 * @return true to indicate adapter startup has begun, or false on immediate error 1116 */ 1117 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) enable()1118 public boolean enable() { 1119 if (isEnabled()) { 1120 if (DBG) { 1121 Log.d(TAG, "enable(): BT already enabled!"); 1122 } 1123 return true; 1124 } 1125 try { 1126 return mManagerService.enable(ActivityThread.currentPackageName()); 1127 } catch (RemoteException e) { 1128 Log.e(TAG, "", e); 1129 } 1130 return false; 1131 } 1132 1133 /** 1134 * Turn off the local Bluetooth adapter—do not use without explicit 1135 * user action to turn off Bluetooth. 1136 * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth 1137 * system services, and powers down the underlying Bluetooth hardware. 1138 * <p class="caution"><strong>Bluetooth should never be disabled without 1139 * direct user consent</strong>. The {@link #disable()} method is 1140 * provided only for applications that include a user interface for changing 1141 * system settings, such as a "power manager" app.</p> 1142 * <p>This is an asynchronous call: it will return immediately, and 1143 * clients should listen for {@link #ACTION_STATE_CHANGED} 1144 * to be notified of subsequent adapter state changes. If this call returns 1145 * true, then the adapter state will immediately transition from {@link 1146 * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time 1147 * later transition to either {@link #STATE_OFF} or {@link 1148 * #STATE_ON}. If this call returns false then there was an 1149 * immediate problem that will prevent the adapter from being turned off - 1150 * such as the adapter already being turned off. 1151 * 1152 * @return true to indicate adapter shutdown has begun, or false on immediate error 1153 */ 1154 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) disable()1155 public boolean disable() { 1156 try { 1157 return mManagerService.disable(ActivityThread.currentPackageName(), true); 1158 } catch (RemoteException e) { 1159 Log.e(TAG, "", e); 1160 } 1161 return false; 1162 } 1163 1164 /** 1165 * Turn off the local Bluetooth adapter and don't persist the setting. 1166 * 1167 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} 1168 * permission 1169 * 1170 * @return true to indicate adapter shutdown has begun, or false on immediate error 1171 * @hide 1172 */ 1173 @UnsupportedAppUsage disable(boolean persist)1174 public boolean disable(boolean persist) { 1175 1176 try { 1177 return mManagerService.disable(ActivityThread.currentPackageName(), persist); 1178 } catch (RemoteException e) { 1179 Log.e(TAG, "", e); 1180 } 1181 return false; 1182 } 1183 1184 /** 1185 * Returns the hardware address of the local Bluetooth adapter. 1186 * <p>For example, "00:11:22:AA:BB:CC". 1187 * 1188 * @return Bluetooth hardware address as string 1189 */ 1190 @RequiresPermission(Manifest.permission.BLUETOOTH) getAddress()1191 public String getAddress() { 1192 try { 1193 return mManagerService.getAddress(); 1194 } catch (RemoteException e) { 1195 Log.e(TAG, "", e); 1196 } 1197 return null; 1198 } 1199 1200 /** 1201 * Get the friendly Bluetooth name of the local Bluetooth adapter. 1202 * <p>This name is visible to remote Bluetooth devices. 1203 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1204 * 1205 * @return the Bluetooth name, or null on error 1206 */ getName()1207 public String getName() { 1208 try { 1209 return mManagerService.getName(); 1210 } catch (RemoteException e) { 1211 Log.e(TAG, "", e); 1212 } 1213 return null; 1214 } 1215 1216 /** 1217 * Factory reset bluetooth settings. 1218 * 1219 * @return true to indicate that the config file was successfully cleared 1220 * @hide 1221 */ 1222 @UnsupportedAppUsage 1223 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) factoryReset()1224 public boolean factoryReset() { 1225 try { 1226 mServiceLock.readLock().lock(); 1227 if (mService != null && mService.factoryReset() 1228 && mManagerService != null && mManagerService.onFactoryReset()) { 1229 return true; 1230 } 1231 Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later"); 1232 SystemProperties.set("persist.bluetooth.factoryreset", "true"); 1233 } catch (RemoteException e) { 1234 Log.e(TAG, "", e); 1235 } finally { 1236 mServiceLock.readLock().unlock(); 1237 } 1238 return false; 1239 } 1240 1241 /** 1242 * Get the UUIDs supported by the local Bluetooth adapter. 1243 * 1244 * @return the UUIDs supported by the local Bluetooth Adapter. 1245 * @hide 1246 */ 1247 @UnsupportedAppUsage 1248 @RequiresPermission(Manifest.permission.BLUETOOTH) getUuids()1249 public @Nullable ParcelUuid[] getUuids() { 1250 if (getState() != STATE_ON) { 1251 return null; 1252 } 1253 try { 1254 mServiceLock.readLock().lock(); 1255 if (mService != null) { 1256 return mService.getUuids(); 1257 } 1258 } catch (RemoteException e) { 1259 Log.e(TAG, "", e); 1260 } finally { 1261 mServiceLock.readLock().unlock(); 1262 } 1263 return null; 1264 } 1265 1266 /** 1267 * Set the friendly Bluetooth name of the local Bluetooth adapter. 1268 * <p>This name is visible to remote Bluetooth devices. 1269 * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8 1270 * encoding, although many remote devices can only display the first 1271 * 40 characters, and some may be limited to just 20. 1272 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1273 * will return false. After turning on Bluetooth, 1274 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1275 * to get the updated value. 1276 * 1277 * @param name a valid Bluetooth name 1278 * @return true if the name was set, false otherwise 1279 */ 1280 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) setName(String name)1281 public boolean setName(String name) { 1282 if (getState() != STATE_ON) { 1283 return false; 1284 } 1285 try { 1286 mServiceLock.readLock().lock(); 1287 if (mService != null) { 1288 return mService.setName(name); 1289 } 1290 } catch (RemoteException e) { 1291 Log.e(TAG, "", e); 1292 } finally { 1293 mServiceLock.readLock().unlock(); 1294 } 1295 return false; 1296 } 1297 1298 /** 1299 * Returns the {@link BluetoothClass} Bluetooth Class of Device (CoD) of the local Bluetooth 1300 * adapter. 1301 * 1302 * @return {@link BluetoothClass} Bluetooth CoD of local Bluetooth device. 1303 * 1304 * @hide 1305 */ 1306 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) getBluetoothClass()1307 public BluetoothClass getBluetoothClass() { 1308 if (getState() != STATE_ON) { 1309 return null; 1310 } 1311 try { 1312 mServiceLock.readLock().lock(); 1313 if (mService != null) { 1314 return mService.getBluetoothClass(); 1315 } 1316 } catch (RemoteException e) { 1317 Log.e(TAG, "", e); 1318 } finally { 1319 mServiceLock.readLock().unlock(); 1320 } 1321 return null; 1322 } 1323 1324 /** 1325 * Sets the {@link BluetoothClass} Bluetooth Class of Device (CoD) of the local Bluetooth 1326 * adapter. 1327 * 1328 * <p>Note: This value persists across system reboot. 1329 * 1330 * @param bluetoothClass {@link BluetoothClass} to set the local Bluetooth adapter to. 1331 * @return true if successful, false if unsuccessful. 1332 * 1333 * @hide 1334 */ 1335 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) setBluetoothClass(BluetoothClass bluetoothClass)1336 public boolean setBluetoothClass(BluetoothClass bluetoothClass) { 1337 if (getState() != STATE_ON) { 1338 return false; 1339 } 1340 try { 1341 mServiceLock.readLock().lock(); 1342 if (mService != null) { 1343 return mService.setBluetoothClass(bluetoothClass); 1344 } 1345 } catch (RemoteException e) { 1346 Log.e(TAG, "", e); 1347 } finally { 1348 mServiceLock.readLock().unlock(); 1349 } 1350 return false; 1351 } 1352 1353 /** 1354 * Returns the Input/Output capability of the device for classic Bluetooth. 1355 * 1356 * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, 1357 * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE}, 1358 * {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}. 1359 * 1360 * @hide 1361 */ 1362 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) 1363 @IoCapability getIoCapability()1364 public int getIoCapability() { 1365 if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; 1366 try { 1367 mServiceLock.readLock().lock(); 1368 if (mService != null) return mService.getIoCapability(); 1369 } catch (RemoteException e) { 1370 Log.e(TAG, e.getMessage(), e); 1371 } finally { 1372 mServiceLock.readLock().unlock(); 1373 } 1374 return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; 1375 } 1376 1377 /** 1378 * Sets the Input/Output capability of the device for classic Bluetooth. 1379 * 1380 * <p>Changing the Input/Output capability of a device only takes effect on restarting the 1381 * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()} 1382 * and {@link BluetoothAdapter#enable()} to see the changes. 1383 * 1384 * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, 1385 * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, 1386 * {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}. 1387 * 1388 * @hide 1389 */ 1390 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) setIoCapability(@oCapability int capability)1391 public boolean setIoCapability(@IoCapability int capability) { 1392 if (getState() != STATE_ON) return false; 1393 try { 1394 mServiceLock.readLock().lock(); 1395 if (mService != null) return mService.setIoCapability(capability); 1396 } catch (RemoteException e) { 1397 Log.e(TAG, e.getMessage(), e); 1398 } finally { 1399 mServiceLock.readLock().unlock(); 1400 } 1401 return false; 1402 } 1403 1404 /** 1405 * Returns the Input/Output capability of the device for BLE operations. 1406 * 1407 * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, 1408 * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE}, 1409 * {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}. 1410 * 1411 * @hide 1412 */ 1413 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) 1414 @IoCapability getLeIoCapability()1415 public int getLeIoCapability() { 1416 if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; 1417 try { 1418 mServiceLock.readLock().lock(); 1419 if (mService != null) return mService.getLeIoCapability(); 1420 } catch (RemoteException e) { 1421 Log.e(TAG, e.getMessage(), e); 1422 } finally { 1423 mServiceLock.readLock().unlock(); 1424 } 1425 return BluetoothAdapter.IO_CAPABILITY_UNKNOWN; 1426 } 1427 1428 /** 1429 * Sets the Input/Output capability of the device for BLE operations. 1430 * 1431 * <p>Changing the Input/Output capability of a device only takes effect on restarting the 1432 * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()} 1433 * and {@link BluetoothAdapter#enable()} to see the changes. 1434 * 1435 * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT}, 1436 * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, 1437 * {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}. 1438 * 1439 * @hide 1440 */ 1441 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) setLeIoCapability(@oCapability int capability)1442 public boolean setLeIoCapability(@IoCapability int capability) { 1443 if (getState() != STATE_ON) return false; 1444 try { 1445 mServiceLock.readLock().lock(); 1446 if (mService != null) return mService.setLeIoCapability(capability); 1447 } catch (RemoteException e) { 1448 Log.e(TAG, e.getMessage(), e); 1449 } finally { 1450 mServiceLock.readLock().unlock(); 1451 } 1452 return false; 1453 } 1454 1455 /** 1456 * Get the current Bluetooth scan mode of the local Bluetooth adapter. 1457 * <p>The Bluetooth scan mode determines if the local adapter is 1458 * connectable and/or discoverable from remote Bluetooth devices. 1459 * <p>Possible values are: 1460 * {@link #SCAN_MODE_NONE}, 1461 * {@link #SCAN_MODE_CONNECTABLE}, 1462 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. 1463 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1464 * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth, 1465 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1466 * to get the updated value. 1467 * 1468 * @return scan mode 1469 */ 1470 @RequiresPermission(Manifest.permission.BLUETOOTH) 1471 @ScanMode getScanMode()1472 public int getScanMode() { 1473 if (getState() != STATE_ON) { 1474 return SCAN_MODE_NONE; 1475 } 1476 try { 1477 mServiceLock.readLock().lock(); 1478 if (mService != null) { 1479 return mService.getScanMode(); 1480 } 1481 } catch (RemoteException e) { 1482 Log.e(TAG, "", e); 1483 } finally { 1484 mServiceLock.readLock().unlock(); 1485 } 1486 return SCAN_MODE_NONE; 1487 } 1488 1489 /** 1490 * Set the Bluetooth scan mode of the local Bluetooth adapter. 1491 * <p>The Bluetooth scan mode determines if the local adapter is 1492 * connectable and/or discoverable from remote Bluetooth devices. 1493 * <p>For privacy reasons, discoverable mode is automatically turned off 1494 * after <code>durationMillis</code> milliseconds. For example, 120000 milliseconds should be 1495 * enough for a remote device to initiate and complete its discovery process. 1496 * <p>Valid scan mode values are: 1497 * {@link #SCAN_MODE_NONE}, 1498 * {@link #SCAN_MODE_CONNECTABLE}, 1499 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. 1500 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1501 * will return false. After turning on Bluetooth, 1502 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1503 * to get the updated value. 1504 * <p>Applications cannot set the scan mode. They should use 1505 * <code>startActivityForResult( 1506 * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) 1507 * </code>instead. 1508 * 1509 * @param mode valid scan mode 1510 * @param durationMillis time in milliseconds to apply scan mode, only used for {@link 1511 * #SCAN_MODE_CONNECTABLE_DISCOVERABLE} 1512 * @return true if the scan mode was set, false otherwise 1513 * @hide 1514 */ 1515 @UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which " 1516 + "shows UI that confirms the user wants to go into discoverable mode.") 1517 @RequiresPermission(Manifest.permission.BLUETOOTH) setScanMode(@canMode int mode, long durationMillis)1518 public boolean setScanMode(@ScanMode int mode, long durationMillis) { 1519 if (getState() != STATE_ON) { 1520 return false; 1521 } 1522 try { 1523 mServiceLock.readLock().lock(); 1524 if (mService != null) { 1525 int durationSeconds = Math.toIntExact(durationMillis / 1000); 1526 return mService.setScanMode(mode, durationSeconds); 1527 } 1528 } catch (RemoteException e) { 1529 Log.e(TAG, "", e); 1530 } catch (ArithmeticException ex) { 1531 Log.e(TAG, "setScanMode: Duration in seconds outside of the bounds of an int"); 1532 throw new IllegalArgumentException("Duration not in bounds. In seconds, the " 1533 + "durationMillis must be in the range of an int"); 1534 } finally { 1535 mServiceLock.readLock().unlock(); 1536 } 1537 return false; 1538 } 1539 1540 /** 1541 * Set the Bluetooth scan mode of the local Bluetooth adapter. 1542 * <p>The Bluetooth scan mode determines if the local adapter is 1543 * connectable and/or discoverable from remote Bluetooth devices. 1544 * <p>For privacy reasons, discoverable mode is automatically turned off 1545 * after <code>duration</code> seconds. For example, 120 seconds should be 1546 * enough for a remote device to initiate and complete its discovery 1547 * process. 1548 * <p>Valid scan mode values are: 1549 * {@link #SCAN_MODE_NONE}, 1550 * {@link #SCAN_MODE_CONNECTABLE}, 1551 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. 1552 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1553 * will return false. After turning on Bluetooth, 1554 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1555 * to get the updated value. 1556 * <p>Applications cannot set the scan mode. They should use 1557 * <code>startActivityForResult( 1558 * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) 1559 * </code>instead. 1560 * 1561 * @param mode valid scan mode 1562 * @return true if the scan mode was set, false otherwise 1563 * @hide 1564 */ 1565 @UnsupportedAppUsage 1566 @RequiresPermission(Manifest.permission.BLUETOOTH) setScanMode(@canMode int mode)1567 public boolean setScanMode(@ScanMode int mode) { 1568 if (getState() != STATE_ON) { 1569 return false; 1570 } 1571 try { 1572 mServiceLock.readLock().lock(); 1573 if (mService != null) { 1574 return mService.setScanMode(mode, getDiscoverableTimeout()); 1575 } 1576 } catch (RemoteException e) { 1577 Log.e(TAG, "", e); 1578 } finally { 1579 mServiceLock.readLock().unlock(); 1580 } 1581 return false; 1582 } 1583 1584 /** @hide */ 1585 @UnsupportedAppUsage getDiscoverableTimeout()1586 public int getDiscoverableTimeout() { 1587 if (getState() != STATE_ON) { 1588 return -1; 1589 } 1590 try { 1591 mServiceLock.readLock().lock(); 1592 if (mService != null) { 1593 return mService.getDiscoverableTimeout(); 1594 } 1595 } catch (RemoteException e) { 1596 Log.e(TAG, "", e); 1597 } finally { 1598 mServiceLock.readLock().unlock(); 1599 } 1600 return -1; 1601 } 1602 1603 /** @hide */ 1604 @UnsupportedAppUsage setDiscoverableTimeout(int timeout)1605 public void setDiscoverableTimeout(int timeout) { 1606 if (getState() != STATE_ON) { 1607 return; 1608 } 1609 try { 1610 mServiceLock.readLock().lock(); 1611 if (mService != null) { 1612 mService.setDiscoverableTimeout(timeout); 1613 } 1614 } catch (RemoteException e) { 1615 Log.e(TAG, "", e); 1616 } finally { 1617 mServiceLock.readLock().unlock(); 1618 } 1619 } 1620 1621 /** 1622 * Get the end time of the latest remote device discovery process. 1623 * 1624 * @return the latest time that the bluetooth adapter was/will be in discovery mode, in 1625 * milliseconds since the epoch. This time can be in the future if {@link #startDiscovery()} has 1626 * been called recently. 1627 * @hide 1628 */ 1629 @SystemApi 1630 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) getDiscoveryEndMillis()1631 public long getDiscoveryEndMillis() { 1632 try { 1633 mServiceLock.readLock().lock(); 1634 if (mService != null) { 1635 return mService.getDiscoveryEndMillis(); 1636 } 1637 } catch (RemoteException e) { 1638 Log.e(TAG, "", e); 1639 } finally { 1640 mServiceLock.readLock().unlock(); 1641 } 1642 return -1; 1643 } 1644 1645 /** 1646 * Set the context for this BluetoothAdapter (only called from BluetoothManager) 1647 * @hide 1648 */ setContext(Context context)1649 public void setContext(Context context) { 1650 mContext = context; 1651 } 1652 getOpPackageName()1653 private String getOpPackageName() { 1654 // Workaround for legacy API for getting a BluetoothAdapter not 1655 // passing a context 1656 if (mContext != null) { 1657 return mContext.getOpPackageName(); 1658 } 1659 return ActivityThread.currentOpPackageName(); 1660 } 1661 getAttributionTag()1662 private String getAttributionTag() { 1663 // Workaround for legacy API for getting a BluetoothAdapter not 1664 // passing a context 1665 if (mContext != null) { 1666 return mContext.getAttributionTag(); 1667 } 1668 return null; 1669 } 1670 1671 /** 1672 * Start the remote device discovery process. 1673 * <p>The discovery process usually involves an inquiry scan of about 12 1674 * seconds, followed by a page scan of each new device to retrieve its 1675 * Bluetooth name. 1676 * <p>This is an asynchronous call, it will return immediately. Register 1677 * for {@link #ACTION_DISCOVERY_STARTED} and {@link 1678 * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the 1679 * discovery starts and completes. Register for {@link 1680 * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices 1681 * are found. 1682 * <p>Device discovery is a heavyweight procedure. New connections to 1683 * remote Bluetooth devices should not be attempted while discovery is in 1684 * progress, and existing connections will experience limited bandwidth 1685 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing 1686 * discovery. Discovery is not managed by the Activity, 1687 * but is run as a system service, so an application should always call 1688 * {@link BluetoothAdapter#cancelDiscovery()} even if it 1689 * did not directly request a discovery, just to be sure. 1690 * <p>Device discovery will only find remote devices that are currently 1691 * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are 1692 * not discoverable by default, and need to be entered into a special mode. 1693 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1694 * will return false. After turning on Bluetooth, 1695 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1696 * to get the updated value. 1697 * 1698 * @return true on success, false on error 1699 */ 1700 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) startDiscovery()1701 public boolean startDiscovery() { 1702 if (getState() != STATE_ON) { 1703 return false; 1704 } 1705 try { 1706 mServiceLock.readLock().lock(); 1707 if (mService != null) { 1708 return mService.startDiscovery(getOpPackageName(), getAttributionTag()); 1709 } 1710 } catch (RemoteException e) { 1711 Log.e(TAG, "", e); 1712 } finally { 1713 mServiceLock.readLock().unlock(); 1714 } 1715 return false; 1716 } 1717 1718 /** 1719 * Cancel the current device discovery process. 1720 * <p>Because discovery is a heavyweight procedure for the Bluetooth 1721 * adapter, this method should always be called before attempting to connect 1722 * to a remote device with {@link 1723 * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by 1724 * the Activity, but is run as a system service, so an application should 1725 * always call cancel discovery even if it did not directly request a 1726 * discovery, just to be sure. 1727 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1728 * will return false. After turning on Bluetooth, 1729 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1730 * to get the updated value. 1731 * 1732 * @return true on success, false on error 1733 */ 1734 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) cancelDiscovery()1735 public boolean cancelDiscovery() { 1736 if (getState() != STATE_ON) { 1737 return false; 1738 } 1739 try { 1740 mServiceLock.readLock().lock(); 1741 if (mService != null) { 1742 return mService.cancelDiscovery(); 1743 } 1744 } catch (RemoteException e) { 1745 Log.e(TAG, "", e); 1746 } finally { 1747 mServiceLock.readLock().unlock(); 1748 } 1749 return false; 1750 } 1751 1752 /** 1753 * Return true if the local Bluetooth adapter is currently in the device 1754 * discovery process. 1755 * <p>Device discovery is a heavyweight procedure. New connections to 1756 * remote Bluetooth devices should not be attempted while discovery is in 1757 * progress, and existing connections will experience limited bandwidth 1758 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing 1759 * discovery. 1760 * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED} 1761 * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery 1762 * starts or completes. 1763 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1764 * will return false. After turning on Bluetooth, 1765 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1766 * to get the updated value. 1767 * 1768 * @return true if discovering 1769 */ 1770 @RequiresPermission(Manifest.permission.BLUETOOTH) isDiscovering()1771 public boolean isDiscovering() { 1772 if (getState() != STATE_ON) { 1773 return false; 1774 } 1775 try { 1776 mServiceLock.readLock().lock(); 1777 if (mService != null) { 1778 return mService.isDiscovering(); 1779 } 1780 } catch (RemoteException e) { 1781 Log.e(TAG, "", e); 1782 } finally { 1783 mServiceLock.readLock().unlock(); 1784 } 1785 return false; 1786 } 1787 1788 /** 1789 * Removes the active device for the grouping of @ActiveDeviceUse specified 1790 * 1791 * @param profiles represents the purpose for which we are setting this as the active device. 1792 * Possible values are: 1793 * {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO}, 1794 * {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL}, 1795 * {@link BluetoothAdapter#ACTIVE_DEVICE_ALL} 1796 * @return false on immediate error, true otherwise 1797 * @throws IllegalArgumentException if device is null or profiles is not one of 1798 * {@link ActiveDeviceUse} 1799 * @hide 1800 */ 1801 @SystemApi 1802 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) removeActiveDevice(@ctiveDeviceUse int profiles)1803 public boolean removeActiveDevice(@ActiveDeviceUse int profiles) { 1804 if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL 1805 && profiles != ACTIVE_DEVICE_ALL) { 1806 Log.e(TAG, "Invalid profiles param value in removeActiveDevice"); 1807 throw new IllegalArgumentException("Profiles must be one of " 1808 + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, " 1809 + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or " 1810 + "BluetoothAdapter.ACTIVE_DEVICE_ALL"); 1811 } 1812 try { 1813 mServiceLock.readLock().lock(); 1814 if (mService != null) { 1815 return mService.removeActiveDevice(profiles); 1816 } 1817 } catch (RemoteException e) { 1818 Log.e(TAG, "", e); 1819 } finally { 1820 mServiceLock.readLock().unlock(); 1821 } 1822 1823 return false; 1824 } 1825 1826 /** 1827 * Sets device as the active devices for the profiles passed into the function 1828 * 1829 * @param device is the remote bluetooth device 1830 * @param profiles represents the purpose for which we are setting this as the active device. 1831 * Possible values are: 1832 * {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO}, 1833 * {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL}, 1834 * {@link BluetoothAdapter#ACTIVE_DEVICE_ALL} 1835 * @return false on immediate error, true otherwise 1836 * @throws IllegalArgumentException if device is null or profiles is not one of 1837 * {@link ActiveDeviceUse} 1838 * @hide 1839 */ 1840 @SystemApi 1841 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) setActiveDevice(@onNull BluetoothDevice device, @ActiveDeviceUse int profiles)1842 public boolean setActiveDevice(@NonNull BluetoothDevice device, 1843 @ActiveDeviceUse int profiles) { 1844 if (device == null) { 1845 Log.e(TAG, "setActiveDevice: Null device passed as parameter"); 1846 throw new IllegalArgumentException("device cannot be null"); 1847 } 1848 if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL 1849 && profiles != ACTIVE_DEVICE_ALL) { 1850 Log.e(TAG, "Invalid profiles param value in setActiveDevice"); 1851 throw new IllegalArgumentException("Profiles must be one of " 1852 + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, " 1853 + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or " 1854 + "BluetoothAdapter.ACTIVE_DEVICE_ALL"); 1855 } 1856 try { 1857 mServiceLock.readLock().lock(); 1858 if (mService != null) { 1859 return mService.setActiveDevice(device, profiles); 1860 } 1861 } catch (RemoteException e) { 1862 Log.e(TAG, "", e); 1863 } finally { 1864 mServiceLock.readLock().unlock(); 1865 } 1866 1867 return false; 1868 } 1869 1870 /** 1871 * Connects all enabled and supported bluetooth profiles between the local and remote device. 1872 * Connection is asynchronous and you should listen to each profile's broadcast intent 1873 * ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful. For example, 1874 * to verify a2dp is connected, you would listen for 1875 * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} 1876 * 1877 * @param device is the remote device with which to connect these profiles 1878 * @return true if message sent to try to connect all profiles, false if an error occurred 1879 * 1880 * @hide 1881 */ 1882 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) connectAllEnabledProfiles(@onNull BluetoothDevice device)1883 public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) { 1884 try { 1885 mServiceLock.readLock().lock(); 1886 if (mService != null) { 1887 return mService.connectAllEnabledProfiles(device); 1888 } 1889 } catch (RemoteException e) { 1890 Log.e(TAG, "", e); 1891 } finally { 1892 mServiceLock.readLock().unlock(); 1893 } 1894 1895 return false; 1896 } 1897 1898 /** 1899 * Disconnects all enabled and supported bluetooth profiles between the local and remote device. 1900 * Disconnection is asynchronous and you should listen to each profile's broadcast intent 1901 * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example, 1902 * to verify a2dp is disconnected, you would listen for 1903 * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} 1904 * 1905 * @param device is the remote device with which to disconnect these profiles 1906 * @return true if message sent to try to disconnect all profiles, false if an error occurred 1907 * 1908 * @hide 1909 */ 1910 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) disconnectAllEnabledProfiles(@onNull BluetoothDevice device)1911 public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) { 1912 try { 1913 mServiceLock.readLock().lock(); 1914 if (mService != null) { 1915 return mService.disconnectAllEnabledProfiles(device); 1916 } 1917 } catch (RemoteException e) { 1918 Log.e(TAG, "", e); 1919 } finally { 1920 mServiceLock.readLock().unlock(); 1921 } 1922 1923 return false; 1924 } 1925 1926 /** 1927 * Return true if the multi advertisement is supported by the chipset 1928 * 1929 * @return true if Multiple Advertisement feature is supported 1930 */ isMultipleAdvertisementSupported()1931 public boolean isMultipleAdvertisementSupported() { 1932 if (getState() != STATE_ON) { 1933 return false; 1934 } 1935 try { 1936 mServiceLock.readLock().lock(); 1937 if (mService != null) { 1938 return mService.isMultiAdvertisementSupported(); 1939 } 1940 } catch (RemoteException e) { 1941 Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e); 1942 } finally { 1943 mServiceLock.readLock().unlock(); 1944 } 1945 return false; 1946 } 1947 1948 /** 1949 * Returns {@code true} if BLE scan is always available, {@code false} otherwise. <p> 1950 * 1951 * If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan} and 1952 * fetch scan results even when Bluetooth is turned off.<p> 1953 * 1954 * To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}. 1955 * 1956 * @hide 1957 */ 1958 @SystemApi isBleScanAlwaysAvailable()1959 public boolean isBleScanAlwaysAvailable() { 1960 try { 1961 return mManagerService.isBleScanAlwaysAvailable(); 1962 } catch (RemoteException e) { 1963 Log.e(TAG, "remote expection when calling isBleScanAlwaysAvailable", e); 1964 return false; 1965 } 1966 } 1967 1968 private static final String BLUETOOTH_FILTERING_CACHE_PROPERTY = 1969 "cache_key.bluetooth.is_offloaded_filtering_supported"; 1970 private final PropertyInvalidatedCache<Void, Boolean> mBluetoothFilteringCache = 1971 new PropertyInvalidatedCache<Void, Boolean>( 1972 8, BLUETOOTH_FILTERING_CACHE_PROPERTY) { 1973 @Override 1974 protected Boolean recompute(Void query) { 1975 try { 1976 mServiceLock.readLock().lock(); 1977 if (mService != null) { 1978 return mService.isOffloadedFilteringSupported(); 1979 } 1980 } catch (RemoteException e) { 1981 Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); 1982 } finally { 1983 mServiceLock.readLock().unlock(); 1984 } 1985 return false; 1986 1987 } 1988 }; 1989 1990 /** @hide */ disableIsOffloadedFilteringSupportedCache()1991 public void disableIsOffloadedFilteringSupportedCache() { 1992 mBluetoothFilteringCache.disableLocal(); 1993 } 1994 1995 /** @hide */ invalidateIsOffloadedFilteringSupportedCache()1996 public static void invalidateIsOffloadedFilteringSupportedCache() { 1997 PropertyInvalidatedCache.invalidateCache(BLUETOOTH_FILTERING_CACHE_PROPERTY); 1998 } 1999 2000 /** 2001 * Return true if offloaded filters are supported 2002 * 2003 * @return true if chipset supports on-chip filtering 2004 */ isOffloadedFilteringSupported()2005 public boolean isOffloadedFilteringSupported() { 2006 if (!getLeAccess()) { 2007 return false; 2008 } 2009 return mBluetoothFilteringCache.query(null); 2010 } 2011 2012 /** 2013 * Return true if offloaded scan batching is supported 2014 * 2015 * @return true if chipset supports on-chip scan batching 2016 */ isOffloadedScanBatchingSupported()2017 public boolean isOffloadedScanBatchingSupported() { 2018 if (!getLeAccess()) { 2019 return false; 2020 } 2021 try { 2022 mServiceLock.readLock().lock(); 2023 if (mService != null) { 2024 return mService.isOffloadedScanBatchingSupported(); 2025 } 2026 } catch (RemoteException e) { 2027 Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e); 2028 } finally { 2029 mServiceLock.readLock().unlock(); 2030 } 2031 return false; 2032 } 2033 2034 /** 2035 * Return true if LE 2M PHY feature is supported. 2036 * 2037 * @return true if chipset supports LE 2M PHY feature 2038 */ isLe2MPhySupported()2039 public boolean isLe2MPhySupported() { 2040 if (!getLeAccess()) { 2041 return false; 2042 } 2043 try { 2044 mServiceLock.readLock().lock(); 2045 if (mService != null) { 2046 return mService.isLe2MPhySupported(); 2047 } 2048 } catch (RemoteException e) { 2049 Log.e(TAG, "failed to get isExtendedAdvertisingSupported, error: ", e); 2050 } finally { 2051 mServiceLock.readLock().unlock(); 2052 } 2053 return false; 2054 } 2055 2056 /** 2057 * Return true if LE Coded PHY feature is supported. 2058 * 2059 * @return true if chipset supports LE Coded PHY feature 2060 */ isLeCodedPhySupported()2061 public boolean isLeCodedPhySupported() { 2062 if (!getLeAccess()) { 2063 return false; 2064 } 2065 try { 2066 mServiceLock.readLock().lock(); 2067 if (mService != null) { 2068 return mService.isLeCodedPhySupported(); 2069 } 2070 } catch (RemoteException e) { 2071 Log.e(TAG, "failed to get isLeCodedPhySupported, error: ", e); 2072 } finally { 2073 mServiceLock.readLock().unlock(); 2074 } 2075 return false; 2076 } 2077 2078 /** 2079 * Return true if LE Extended Advertising feature is supported. 2080 * 2081 * @return true if chipset supports LE Extended Advertising feature 2082 */ isLeExtendedAdvertisingSupported()2083 public boolean isLeExtendedAdvertisingSupported() { 2084 if (!getLeAccess()) { 2085 return false; 2086 } 2087 try { 2088 mServiceLock.readLock().lock(); 2089 if (mService != null) { 2090 return mService.isLeExtendedAdvertisingSupported(); 2091 } 2092 } catch (RemoteException e) { 2093 Log.e(TAG, "failed to get isLeExtendedAdvertisingSupported, error: ", e); 2094 } finally { 2095 mServiceLock.readLock().unlock(); 2096 } 2097 return false; 2098 } 2099 2100 /** 2101 * Return true if LE Periodic Advertising feature is supported. 2102 * 2103 * @return true if chipset supports LE Periodic Advertising feature 2104 */ isLePeriodicAdvertisingSupported()2105 public boolean isLePeriodicAdvertisingSupported() { 2106 if (!getLeAccess()) { 2107 return false; 2108 } 2109 try { 2110 mServiceLock.readLock().lock(); 2111 if (mService != null) { 2112 return mService.isLePeriodicAdvertisingSupported(); 2113 } 2114 } catch (RemoteException e) { 2115 Log.e(TAG, "failed to get isLePeriodicAdvertisingSupported, error: ", e); 2116 } finally { 2117 mServiceLock.readLock().unlock(); 2118 } 2119 return false; 2120 } 2121 2122 /** 2123 * Return the maximum LE advertising data length in bytes, 2124 * if LE Extended Advertising feature is supported, 0 otherwise. 2125 * 2126 * @return the maximum LE advertising data length. 2127 */ getLeMaximumAdvertisingDataLength()2128 public int getLeMaximumAdvertisingDataLength() { 2129 if (!getLeAccess()) { 2130 return 0; 2131 } 2132 try { 2133 mServiceLock.readLock().lock(); 2134 if (mService != null) { 2135 return mService.getLeMaximumAdvertisingDataLength(); 2136 } 2137 } catch (RemoteException e) { 2138 Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e); 2139 } finally { 2140 mServiceLock.readLock().unlock(); 2141 } 2142 return 0; 2143 } 2144 2145 /** 2146 * Return true if Hearing Aid Profile is supported. 2147 * 2148 * @return true if phone supports Hearing Aid Profile 2149 */ isHearingAidProfileSupported()2150 private boolean isHearingAidProfileSupported() { 2151 try { 2152 return mManagerService.isHearingAidProfileSupported(); 2153 } catch (RemoteException e) { 2154 Log.e(TAG, "remote expection when calling isHearingAidProfileSupported", e); 2155 return false; 2156 } 2157 } 2158 2159 /** 2160 * Get the maximum number of connected audio devices. 2161 * 2162 * @return the maximum number of connected audio devices 2163 * @hide 2164 */ 2165 @RequiresPermission(Manifest.permission.BLUETOOTH) getMaxConnectedAudioDevices()2166 public int getMaxConnectedAudioDevices() { 2167 try { 2168 mServiceLock.readLock().lock(); 2169 if (mService != null) { 2170 return mService.getMaxConnectedAudioDevices(); 2171 } 2172 } catch (RemoteException e) { 2173 Log.e(TAG, "failed to get getMaxConnectedAudioDevices, error: ", e); 2174 } finally { 2175 mServiceLock.readLock().unlock(); 2176 } 2177 return 1; 2178 } 2179 2180 /** 2181 * Return true if hardware has entries available for matching beacons 2182 * 2183 * @return true if there are hw entries available for matching beacons 2184 * @hide 2185 */ isHardwareTrackingFiltersAvailable()2186 public boolean isHardwareTrackingFiltersAvailable() { 2187 if (!getLeAccess()) { 2188 return false; 2189 } 2190 try { 2191 IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); 2192 if (iGatt == null) { 2193 // BLE is not supported 2194 return false; 2195 } 2196 return (iGatt.numHwTrackFiltersAvailable() != 0); 2197 } catch (RemoteException e) { 2198 Log.e(TAG, "", e); 2199 } 2200 return false; 2201 } 2202 2203 /** 2204 * Return the record of {@link BluetoothActivityEnergyInfo} object that 2205 * has the activity and energy info. This can be used to ascertain what 2206 * the controller has been up to, since the last sample. 2207 * 2208 * @param updateType Type of info, cached vs refreshed. 2209 * @return a record with {@link BluetoothActivityEnergyInfo} or null if report is unavailable or 2210 * unsupported 2211 * @hide 2212 * @deprecated use the asynchronous {@link #requestControllerActivityEnergyInfo(ResultReceiver)} 2213 * instead. 2214 */ 2215 @Deprecated getControllerActivityEnergyInfo(int updateType)2216 public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { 2217 SynchronousResultReceiver receiver = new SynchronousResultReceiver(); 2218 requestControllerActivityEnergyInfo(receiver); 2219 try { 2220 SynchronousResultReceiver.Result result = receiver.awaitResult(1000); 2221 if (result.bundle != null) { 2222 return result.bundle.getParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY); 2223 } 2224 } catch (TimeoutException e) { 2225 Log.e(TAG, "getControllerActivityEnergyInfo timed out"); 2226 } 2227 return null; 2228 } 2229 2230 /** 2231 * Request the record of {@link BluetoothActivityEnergyInfo} object that 2232 * has the activity and energy info. This can be used to ascertain what 2233 * the controller has been up to, since the last sample. 2234 * 2235 * A null value for the activity info object may be sent if the bluetooth service is 2236 * unreachable or the device does not support reporting such information. 2237 * 2238 * @param result The callback to which to send the activity info. 2239 * @hide 2240 */ requestControllerActivityEnergyInfo(ResultReceiver result)2241 public void requestControllerActivityEnergyInfo(ResultReceiver result) { 2242 try { 2243 mServiceLock.readLock().lock(); 2244 if (mService != null) { 2245 mService.requestActivityInfo(result); 2246 result = null; 2247 } 2248 } catch (RemoteException e) { 2249 Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e); 2250 } finally { 2251 mServiceLock.readLock().unlock(); 2252 if (result != null) { 2253 // Only send an immediate result if we failed. 2254 result.send(0, null); 2255 } 2256 } 2257 } 2258 2259 /** 2260 * Fetches a list of the most recently connected bluetooth devices ordered by how recently they 2261 * were connected with most recently first and least recently last 2262 * 2263 * @return {@link List} of bonded {@link BluetoothDevice} ordered by how recently they were 2264 * connected 2265 * 2266 * @hide 2267 */ 2268 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) getMostRecentlyConnectedDevices()2269 public @NonNull List<BluetoothDevice> getMostRecentlyConnectedDevices() { 2270 if (getState() != STATE_ON) { 2271 return new ArrayList<>(); 2272 } 2273 try { 2274 mServiceLock.readLock().lock(); 2275 if (mService != null) { 2276 return mService.getMostRecentlyConnectedDevices(); 2277 } 2278 } catch (RemoteException e) { 2279 Log.e(TAG, "", e); 2280 } finally { 2281 mServiceLock.readLock().unlock(); 2282 } 2283 return new ArrayList<>(); 2284 } 2285 2286 /** 2287 * Return the set of {@link BluetoothDevice} objects that are bonded 2288 * (paired) to the local adapter. 2289 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 2290 * will return an empty set. After turning on Bluetooth, 2291 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 2292 * to get the updated value. 2293 * 2294 * @return unmodifiable set of {@link BluetoothDevice}, or null on error 2295 */ 2296 @RequiresPermission(Manifest.permission.BLUETOOTH) getBondedDevices()2297 public Set<BluetoothDevice> getBondedDevices() { 2298 if (getState() != STATE_ON) { 2299 return toDeviceSet(new BluetoothDevice[0]); 2300 } 2301 try { 2302 mServiceLock.readLock().lock(); 2303 if (mService != null) { 2304 return toDeviceSet(mService.getBondedDevices()); 2305 } 2306 return toDeviceSet(new BluetoothDevice[0]); 2307 } catch (RemoteException e) { 2308 Log.e(TAG, "", e); 2309 } finally { 2310 mServiceLock.readLock().unlock(); 2311 } 2312 return null; 2313 } 2314 2315 /** 2316 * Gets the currently supported profiles by the adapter. 2317 * 2318 * <p> This can be used to check whether a profile is supported before attempting 2319 * to connect to its respective proxy. 2320 * 2321 * @return a list of integers indicating the ids of supported profiles as defined in {@link 2322 * BluetoothProfile}. 2323 * @hide 2324 */ getSupportedProfiles()2325 public @NonNull List<Integer> getSupportedProfiles() { 2326 final ArrayList<Integer> supportedProfiles = new ArrayList<Integer>(); 2327 2328 try { 2329 synchronized (mManagerCallback) { 2330 if (mService != null) { 2331 final long supportedProfilesBitMask = mService.getSupportedProfiles(); 2332 2333 for (int i = 0; i <= BluetoothProfile.MAX_PROFILE_ID; i++) { 2334 if ((supportedProfilesBitMask & (1 << i)) != 0) { 2335 supportedProfiles.add(i); 2336 } 2337 } 2338 } else { 2339 // Bluetooth is disabled. Just fill in known supported Profiles 2340 if (isHearingAidProfileSupported()) { 2341 supportedProfiles.add(BluetoothProfile.HEARING_AID); 2342 } 2343 } 2344 } 2345 } catch (RemoteException e) { 2346 Log.e(TAG, "getSupportedProfiles:", e); 2347 } 2348 return supportedProfiles; 2349 } 2350 2351 /** 2352 * Get the current connection state of the local Bluetooth adapter. 2353 * This can be used to check whether the local Bluetooth adapter is connected 2354 * to any profile of any other remote Bluetooth Device. 2355 * 2356 * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED} 2357 * intent to get the connection state of the adapter. 2358 * 2359 * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED}, {@link 2360 * #STATE_CONNECTING} or {@link #STATE_DISCONNECTED} 2361 * @hide 2362 */ 2363 @UnsupportedAppUsage getConnectionState()2364 public int getConnectionState() { 2365 if (getState() != STATE_ON) { 2366 return BluetoothAdapter.STATE_DISCONNECTED; 2367 } 2368 try { 2369 mServiceLock.readLock().lock(); 2370 if (mService != null) { 2371 return mService.getAdapterConnectionState(); 2372 } 2373 } catch (RemoteException e) { 2374 Log.e(TAG, "getConnectionState:", e); 2375 } finally { 2376 mServiceLock.readLock().unlock(); 2377 } 2378 return BluetoothAdapter.STATE_DISCONNECTED; 2379 } 2380 2381 private static final String BLUETOOTH_PROFILE_CACHE_PROPERTY = 2382 "cache_key.bluetooth.get_profile_connection_state"; 2383 private final PropertyInvalidatedCache<Integer, Integer> 2384 mGetProfileConnectionStateCache = 2385 new PropertyInvalidatedCache<Integer, Integer>( 2386 8, BLUETOOTH_PROFILE_CACHE_PROPERTY) { 2387 @Override 2388 protected Integer recompute(Integer query) { 2389 try { 2390 mServiceLock.readLock().lock(); 2391 if (mService != null) { 2392 return mService.getProfileConnectionState(query); 2393 } 2394 } catch (RemoteException e) { 2395 Log.e(TAG, "getProfileConnectionState:", e); 2396 } finally { 2397 mServiceLock.readLock().unlock(); 2398 } 2399 return BluetoothProfile.STATE_DISCONNECTED; 2400 } 2401 @Override 2402 public String queryToString(Integer query) { 2403 return String.format("getProfileConnectionState(profile=\"%d\")", 2404 query); 2405 } 2406 }; 2407 2408 /** @hide */ disableGetProfileConnectionStateCache()2409 public void disableGetProfileConnectionStateCache() { 2410 mGetProfileConnectionStateCache.disableLocal(); 2411 } 2412 2413 /** @hide */ invalidateGetProfileConnectionStateCache()2414 public static void invalidateGetProfileConnectionStateCache() { 2415 PropertyInvalidatedCache.invalidateCache(BLUETOOTH_PROFILE_CACHE_PROPERTY); 2416 } 2417 2418 /** 2419 * Get the current connection state of a profile. 2420 * This function can be used to check whether the local Bluetooth adapter 2421 * is connected to any remote device for a specific profile. 2422 * Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. 2423 * 2424 * <p> Return value can be one of 2425 * {@link BluetoothProfile#STATE_DISCONNECTED}, 2426 * {@link BluetoothProfile#STATE_CONNECTING}, 2427 * {@link BluetoothProfile#STATE_CONNECTED}, 2428 * {@link BluetoothProfile#STATE_DISCONNECTING} 2429 */ 2430 @RequiresPermission(Manifest.permission.BLUETOOTH) getProfileConnectionState(int profile)2431 public int getProfileConnectionState(int profile) { 2432 if (getState() != STATE_ON) { 2433 return BluetoothProfile.STATE_DISCONNECTED; 2434 } 2435 return mGetProfileConnectionStateCache.query(new Integer(profile)); 2436 } 2437 2438 /** 2439 * Create a listening, secure RFCOMM Bluetooth socket. 2440 * <p>A remote device connecting to this socket will be authenticated and 2441 * communication on this socket will be encrypted. 2442 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 2443 * connections from a listening {@link BluetoothServerSocket}. 2444 * <p>Valid RFCOMM channels are in range 1 to 30. 2445 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 2446 * 2447 * @param channel RFCOMM channel to listen on 2448 * @return a listening RFCOMM BluetoothServerSocket 2449 * @throws IOException on error, for example Bluetooth not available, or insufficient 2450 * permissions, or channel in use. 2451 * @hide 2452 */ listenUsingRfcommOn(int channel)2453 public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException { 2454 return listenUsingRfcommOn(channel, false, false); 2455 } 2456 2457 /** 2458 * Create a listening, secure RFCOMM Bluetooth socket. 2459 * <p>A remote device connecting to this socket will be authenticated and 2460 * communication on this socket will be encrypted. 2461 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 2462 * connections from a listening {@link BluetoothServerSocket}. 2463 * <p>Valid RFCOMM channels are in range 1 to 30. 2464 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 2465 * <p>To auto assign a channel without creating a SDP record use 2466 * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. 2467 * 2468 * @param channel RFCOMM channel to listen on 2469 * @param mitm enforce man-in-the-middle protection for authentication. 2470 * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 2471 * connections. 2472 * @return a listening RFCOMM BluetoothServerSocket 2473 * @throws IOException on error, for example Bluetooth not available, or insufficient 2474 * permissions, or channel in use. 2475 * @hide 2476 */ 2477 @UnsupportedAppUsage listenUsingRfcommOn(int channel, boolean mitm, boolean min16DigitPin)2478 public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm, 2479 boolean min16DigitPin) throws IOException { 2480 BluetoothServerSocket socket = 2481 new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm, 2482 min16DigitPin); 2483 int errno = socket.mSocket.bindListen(); 2484 if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 2485 socket.setChannel(socket.mSocket.getPort()); 2486 } 2487 if (errno != 0) { 2488 //TODO(BT): Throw the same exception error code 2489 // that the previous code was using. 2490 //socket.mSocket.throwErrnoNative(errno); 2491 throw new IOException("Error: " + errno); 2492 } 2493 return socket; 2494 } 2495 2496 /** 2497 * Create a listening, secure RFCOMM Bluetooth socket with Service Record. 2498 * <p>A remote device connecting to this socket will be authenticated and 2499 * communication on this socket will be encrypted. 2500 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 2501 * connections from a listening {@link BluetoothServerSocket}. 2502 * <p>The system will assign an unused RFCOMM channel to listen on. 2503 * <p>The system will also register a Service Discovery 2504 * Protocol (SDP) record with the local SDP server containing the specified 2505 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices 2506 * can use the same UUID to query our SDP server and discover which channel 2507 * to connect to. This SDP record will be removed when this socket is 2508 * closed, or if this application closes unexpectedly. 2509 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to 2510 * connect to this socket from another device using the same {@link UUID}. 2511 * 2512 * @param name service name for SDP record 2513 * @param uuid uuid for SDP record 2514 * @return a listening RFCOMM BluetoothServerSocket 2515 * @throws IOException on error, for example Bluetooth not available, or insufficient 2516 * permissions, or channel in use. 2517 */ 2518 @RequiresPermission(Manifest.permission.BLUETOOTH) listenUsingRfcommWithServiceRecord(String name, UUID uuid)2519 public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) 2520 throws IOException { 2521 return createNewRfcommSocketAndRecord(name, uuid, true, true); 2522 } 2523 2524 /** 2525 * Create a listening, insecure RFCOMM Bluetooth socket with Service Record. 2526 * <p>The link key is not required to be authenticated, i.e the communication may be 2527 * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices, 2528 * the link will be encrypted, as encryption is mandartory. 2529 * For legacy devices (pre Bluetooth 2.1 devices) the link will not 2530 * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an 2531 * encrypted and authenticated communication channel is desired. 2532 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 2533 * connections from a listening {@link BluetoothServerSocket}. 2534 * <p>The system will assign an unused RFCOMM channel to listen on. 2535 * <p>The system will also register a Service Discovery 2536 * Protocol (SDP) record with the local SDP server containing the specified 2537 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices 2538 * can use the same UUID to query our SDP server and discover which channel 2539 * to connect to. This SDP record will be removed when this socket is 2540 * closed, or if this application closes unexpectedly. 2541 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to 2542 * connect to this socket from another device using the same {@link UUID}. 2543 * 2544 * @param name service name for SDP record 2545 * @param uuid uuid for SDP record 2546 * @return a listening RFCOMM BluetoothServerSocket 2547 * @throws IOException on error, for example Bluetooth not available, or insufficient 2548 * permissions, or channel in use. 2549 */ 2550 @RequiresPermission(Manifest.permission.BLUETOOTH) listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)2551 public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid) 2552 throws IOException { 2553 return createNewRfcommSocketAndRecord(name, uuid, false, false); 2554 } 2555 2556 /** 2557 * Create a listening, encrypted, 2558 * RFCOMM Bluetooth socket with Service Record. 2559 * <p>The link will be encrypted, but the link key is not required to be authenticated 2560 * i.e the communication is vulnerable to Man In the Middle attacks. Use 2561 * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key. 2562 * <p> Use this socket if authentication of link key is not possible. 2563 * For example, for Bluetooth 2.1 devices, if any of the devices does not have 2564 * an input and output capability or just has the ability to display a numeric key, 2565 * a secure socket connection is not possible and this socket can be used. 2566 * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required. 2567 * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory. 2568 * For more details, refer to the Security Model section 5.2 (vol 3) of 2569 * Bluetooth Core Specification version 2.1 + EDR. 2570 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 2571 * connections from a listening {@link BluetoothServerSocket}. 2572 * <p>The system will assign an unused RFCOMM channel to listen on. 2573 * <p>The system will also register a Service Discovery 2574 * Protocol (SDP) record with the local SDP server containing the specified 2575 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices 2576 * can use the same UUID to query our SDP server and discover which channel 2577 * to connect to. This SDP record will be removed when this socket is 2578 * closed, or if this application closes unexpectedly. 2579 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to 2580 * connect to this socket from another device using the same {@link UUID}. 2581 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 2582 * 2583 * @param name service name for SDP record 2584 * @param uuid uuid for SDP record 2585 * @return a listening RFCOMM BluetoothServerSocket 2586 * @throws IOException on error, for example Bluetooth not available, or insufficient 2587 * permissions, or channel in use. 2588 * @hide 2589 */ 2590 @UnsupportedAppUsage listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid)2591 public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid) 2592 throws IOException { 2593 return createNewRfcommSocketAndRecord(name, uuid, false, true); 2594 } 2595 2596 createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt)2597 private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, 2598 boolean auth, boolean encrypt) throws IOException { 2599 BluetoothServerSocket socket; 2600 socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, encrypt, 2601 new ParcelUuid(uuid)); 2602 socket.setServiceName(name); 2603 int errno = socket.mSocket.bindListen(); 2604 if (errno != 0) { 2605 //TODO(BT): Throw the same exception error code 2606 // that the previous code was using. 2607 //socket.mSocket.throwErrnoNative(errno); 2608 throw new IOException("Error: " + errno); 2609 } 2610 return socket; 2611 } 2612 2613 /** 2614 * Construct an unencrypted, unauthenticated, RFCOMM server socket. 2615 * Call #accept to retrieve connections to this socket. 2616 * 2617 * @return An RFCOMM BluetoothServerSocket 2618 * @throws IOException On error, for example Bluetooth not available, or insufficient 2619 * permissions. 2620 * @hide 2621 */ listenUsingInsecureRfcommOn(int port)2622 public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { 2623 BluetoothServerSocket socket = 2624 new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, false, port); 2625 int errno = socket.mSocket.bindListen(); 2626 if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 2627 socket.setChannel(socket.mSocket.getPort()); 2628 } 2629 if (errno != 0) { 2630 //TODO(BT): Throw the same exception error code 2631 // that the previous code was using. 2632 //socket.mSocket.throwErrnoNative(errno); 2633 throw new IOException("Error: " + errno); 2634 } 2635 return socket; 2636 } 2637 2638 /** 2639 * Construct an encrypted, RFCOMM server socket. 2640 * Call #accept to retrieve connections to this socket. 2641 * 2642 * @return An RFCOMM BluetoothServerSocket 2643 * @throws IOException On error, for example Bluetooth not available, or insufficient 2644 * permissions. 2645 * @hide 2646 */ listenUsingEncryptedRfcommOn(int port)2647 public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) throws IOException { 2648 BluetoothServerSocket socket = 2649 new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, true, port); 2650 int errno = socket.mSocket.bindListen(); 2651 if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 2652 socket.setChannel(socket.mSocket.getPort()); 2653 } 2654 if (errno < 0) { 2655 //TODO(BT): Throw the same exception error code 2656 // that the previous code was using. 2657 //socket.mSocket.throwErrnoNative(errno); 2658 throw new IOException("Error: " + errno); 2659 } 2660 return socket; 2661 } 2662 2663 /** 2664 * Construct a SCO server socket. 2665 * Call #accept to retrieve connections to this socket. 2666 * 2667 * @return A SCO BluetoothServerSocket 2668 * @throws IOException On error, for example Bluetooth not available, or insufficient 2669 * permissions. 2670 * @hide 2671 */ listenUsingScoOn()2672 public static BluetoothServerSocket listenUsingScoOn() throws IOException { 2673 BluetoothServerSocket socket = 2674 new BluetoothServerSocket(BluetoothSocket.TYPE_SCO, false, false, -1); 2675 int errno = socket.mSocket.bindListen(); 2676 if (errno < 0) { 2677 //TODO(BT): Throw the same exception error code 2678 // that the previous code was using. 2679 //socket.mSocket.throwErrnoNative(errno); 2680 } 2681 return socket; 2682 } 2683 2684 /** 2685 * Construct an encrypted, authenticated, L2CAP server socket. 2686 * Call #accept to retrieve connections to this socket. 2687 * <p>To auto assign a port without creating a SDP record use 2688 * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. 2689 * 2690 * @param port the PSM to listen on 2691 * @param mitm enforce man-in-the-middle protection for authentication. 2692 * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 2693 * connections. 2694 * @return An L2CAP BluetoothServerSocket 2695 * @throws IOException On error, for example Bluetooth not available, or insufficient 2696 * permissions. 2697 * @hide 2698 */ listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)2699 public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin) 2700 throws IOException { 2701 BluetoothServerSocket socket = 2702 new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, 2703 min16DigitPin); 2704 int errno = socket.mSocket.bindListen(); 2705 if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 2706 int assignedChannel = socket.mSocket.getPort(); 2707 if (DBG) Log.d(TAG, "listenUsingL2capOn: set assigned channel to " + assignedChannel); 2708 socket.setChannel(assignedChannel); 2709 } 2710 if (errno != 0) { 2711 //TODO(BT): Throw the same exception error code 2712 // that the previous code was using. 2713 //socket.mSocket.throwErrnoNative(errno); 2714 throw new IOException("Error: " + errno); 2715 } 2716 return socket; 2717 } 2718 2719 /** 2720 * Construct an encrypted, authenticated, L2CAP server socket. 2721 * Call #accept to retrieve connections to this socket. 2722 * <p>To auto assign a port without creating a SDP record use 2723 * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. 2724 * 2725 * @param port the PSM to listen on 2726 * @return An L2CAP BluetoothServerSocket 2727 * @throws IOException On error, for example Bluetooth not available, or insufficient 2728 * permissions. 2729 * @hide 2730 */ listenUsingL2capOn(int port)2731 public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { 2732 return listenUsingL2capOn(port, false, false); 2733 } 2734 2735 2736 /** 2737 * Construct an insecure L2CAP server socket. 2738 * Call #accept to retrieve connections to this socket. 2739 * <p>To auto assign a port without creating a SDP record use 2740 * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. 2741 * 2742 * @param port the PSM to listen on 2743 * @return An L2CAP BluetoothServerSocket 2744 * @throws IOException On error, for example Bluetooth not available, or insufficient 2745 * permissions. 2746 * @hide 2747 */ listenUsingInsecureL2capOn(int port)2748 public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException { 2749 Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port); 2750 BluetoothServerSocket socket = 2751 new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, false, false, port, false, 2752 false); 2753 int errno = socket.mSocket.bindListen(); 2754 if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 2755 int assignedChannel = socket.mSocket.getPort(); 2756 if (DBG) { 2757 Log.d(TAG, "listenUsingInsecureL2capOn: set assigned channel to " 2758 + assignedChannel); 2759 } 2760 socket.setChannel(assignedChannel); 2761 } 2762 if (errno != 0) { 2763 //TODO(BT): Throw the same exception error code 2764 // that the previous code was using. 2765 //socket.mSocket.throwErrnoNative(errno); 2766 throw new IOException("Error: " + errno); 2767 } 2768 return socket; 2769 2770 } 2771 2772 /** 2773 * Read the local Out of Band Pairing Data 2774 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 2775 * 2776 * @return Pair<byte[], byte[]> of Hash and Randomizer 2777 * @hide 2778 */ readOutOfBandData()2779 public Pair<byte[], byte[]> readOutOfBandData() { 2780 return null; 2781 } 2782 2783 /** 2784 * Get the profile proxy object associated with the profile. 2785 * 2786 * <p>Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}, 2787 * {@link BluetoothProfile#GATT}, {@link BluetoothProfile#HEARING_AID}, or {@link 2788 * BluetoothProfile#GATT_SERVER}. Clients must implement {@link 2789 * BluetoothProfile.ServiceListener} to get notified of the connection status and to get the 2790 * proxy object. 2791 * 2792 * @param context Context of the application 2793 * @param listener The service Listener for connection callbacks. 2794 * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEADSET}, 2795 * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, {@link 2796 * BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#GATT_SERVER}. 2797 * @return true on success, false on error 2798 */ getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile)2799 public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, 2800 int profile) { 2801 if (context == null || listener == null) { 2802 return false; 2803 } 2804 2805 if (profile == BluetoothProfile.HEADSET) { 2806 BluetoothHeadset headset = new BluetoothHeadset(context, listener); 2807 return true; 2808 } else if (profile == BluetoothProfile.A2DP) { 2809 BluetoothA2dp a2dp = new BluetoothA2dp(context, listener); 2810 return true; 2811 } else if (profile == BluetoothProfile.A2DP_SINK) { 2812 BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener); 2813 return true; 2814 } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) { 2815 BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener); 2816 return true; 2817 } else if (profile == BluetoothProfile.HID_HOST) { 2818 BluetoothHidHost iDev = new BluetoothHidHost(context, listener); 2819 return true; 2820 } else if (profile == BluetoothProfile.PAN) { 2821 BluetoothPan pan = new BluetoothPan(context, listener); 2822 return true; 2823 } else if (profile == BluetoothProfile.PBAP) { 2824 BluetoothPbap pbap = new BluetoothPbap(context, listener); 2825 return true; 2826 } else if (profile == BluetoothProfile.HEALTH) { 2827 Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated"); 2828 return false; 2829 } else if (profile == BluetoothProfile.MAP) { 2830 BluetoothMap map = new BluetoothMap(context, listener); 2831 return true; 2832 } else if (profile == BluetoothProfile.HEADSET_CLIENT) { 2833 BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener); 2834 return true; 2835 } else if (profile == BluetoothProfile.SAP) { 2836 BluetoothSap sap = new BluetoothSap(context, listener); 2837 return true; 2838 } else if (profile == BluetoothProfile.PBAP_CLIENT) { 2839 BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener); 2840 return true; 2841 } else if (profile == BluetoothProfile.MAP_CLIENT) { 2842 BluetoothMapClient mapClient = new BluetoothMapClient(context, listener); 2843 return true; 2844 } else if (profile == BluetoothProfile.HID_DEVICE) { 2845 BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener); 2846 return true; 2847 } else if (profile == BluetoothProfile.HEARING_AID) { 2848 if (isHearingAidProfileSupported()) { 2849 BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener); 2850 return true; 2851 } 2852 return false; 2853 } else { 2854 return false; 2855 } 2856 } 2857 2858 /** 2859 * Close the connection of the profile proxy to the Service. 2860 * 2861 * <p> Clients should call this when they are no longer using 2862 * the proxy obtained from {@link #getProfileProxy}. 2863 * Profile can be one of {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP} 2864 * 2865 * @param profile 2866 * @param proxy Profile proxy object 2867 */ closeProfileProxy(int profile, BluetoothProfile proxy)2868 public void closeProfileProxy(int profile, BluetoothProfile proxy) { 2869 if (proxy == null) { 2870 return; 2871 } 2872 2873 switch (profile) { 2874 case BluetoothProfile.HEADSET: 2875 BluetoothHeadset headset = (BluetoothHeadset) proxy; 2876 headset.close(); 2877 break; 2878 case BluetoothProfile.A2DP: 2879 BluetoothA2dp a2dp = (BluetoothA2dp) proxy; 2880 a2dp.close(); 2881 break; 2882 case BluetoothProfile.A2DP_SINK: 2883 BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink) proxy; 2884 a2dpSink.close(); 2885 break; 2886 case BluetoothProfile.AVRCP_CONTROLLER: 2887 BluetoothAvrcpController avrcp = (BluetoothAvrcpController) proxy; 2888 avrcp.close(); 2889 break; 2890 case BluetoothProfile.HID_HOST: 2891 BluetoothHidHost iDev = (BluetoothHidHost) proxy; 2892 iDev.close(); 2893 break; 2894 case BluetoothProfile.PAN: 2895 BluetoothPan pan = (BluetoothPan) proxy; 2896 pan.close(); 2897 break; 2898 case BluetoothProfile.PBAP: 2899 BluetoothPbap pbap = (BluetoothPbap) proxy; 2900 pbap.close(); 2901 break; 2902 case BluetoothProfile.GATT: 2903 BluetoothGatt gatt = (BluetoothGatt) proxy; 2904 gatt.close(); 2905 break; 2906 case BluetoothProfile.GATT_SERVER: 2907 BluetoothGattServer gattServer = (BluetoothGattServer) proxy; 2908 gattServer.close(); 2909 break; 2910 case BluetoothProfile.MAP: 2911 BluetoothMap map = (BluetoothMap) proxy; 2912 map.close(); 2913 break; 2914 case BluetoothProfile.HEADSET_CLIENT: 2915 BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient) proxy; 2916 headsetClient.close(); 2917 break; 2918 case BluetoothProfile.SAP: 2919 BluetoothSap sap = (BluetoothSap) proxy; 2920 sap.close(); 2921 break; 2922 case BluetoothProfile.PBAP_CLIENT: 2923 BluetoothPbapClient pbapClient = (BluetoothPbapClient) proxy; 2924 pbapClient.close(); 2925 break; 2926 case BluetoothProfile.MAP_CLIENT: 2927 BluetoothMapClient mapClient = (BluetoothMapClient) proxy; 2928 mapClient.close(); 2929 break; 2930 case BluetoothProfile.HID_DEVICE: 2931 BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy; 2932 hidDevice.close(); 2933 break; 2934 case BluetoothProfile.HEARING_AID: 2935 BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy; 2936 hearingAid.close(); 2937 } 2938 } 2939 2940 private final IBluetoothManagerCallback mManagerCallback = 2941 new IBluetoothManagerCallback.Stub() { 2942 public void onBluetoothServiceUp(IBluetooth bluetoothService) { 2943 if (DBG) { 2944 Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); 2945 } 2946 2947 mServiceLock.writeLock().lock(); 2948 mService = bluetoothService; 2949 mServiceLock.writeLock().unlock(); 2950 2951 synchronized (mProxyServiceStateCallbacks) { 2952 for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) { 2953 try { 2954 if (cb != null) { 2955 cb.onBluetoothServiceUp(bluetoothService); 2956 } else { 2957 Log.d(TAG, "onBluetoothServiceUp: cb is null!"); 2958 } 2959 } catch (Exception e) { 2960 Log.e(TAG, "", e); 2961 } 2962 } 2963 } 2964 synchronized (sMetadataListeners) { 2965 sMetadataListeners.forEach((device, pair) -> { 2966 try { 2967 mService.registerMetadataListener(sBluetoothMetadataListener, 2968 device); 2969 } catch (RemoteException e) { 2970 Log.e(TAG, "Failed to register metadata listener", e); 2971 } 2972 }); 2973 } 2974 } 2975 2976 public void onBluetoothServiceDown() { 2977 if (DBG) { 2978 Log.d(TAG, "onBluetoothServiceDown: " + mService); 2979 } 2980 2981 try { 2982 mServiceLock.writeLock().lock(); 2983 mService = null; 2984 if (mLeScanClients != null) { 2985 mLeScanClients.clear(); 2986 } 2987 if (sBluetoothLeAdvertiser != null) { 2988 sBluetoothLeAdvertiser.cleanup(); 2989 } 2990 if (sBluetoothLeScanner != null) { 2991 sBluetoothLeScanner.cleanup(); 2992 } 2993 } finally { 2994 mServiceLock.writeLock().unlock(); 2995 } 2996 2997 synchronized (mProxyServiceStateCallbacks) { 2998 for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) { 2999 try { 3000 if (cb != null) { 3001 cb.onBluetoothServiceDown(); 3002 } else { 3003 Log.d(TAG, "onBluetoothServiceDown: cb is null!"); 3004 } 3005 } catch (Exception e) { 3006 Log.e(TAG, "", e); 3007 } 3008 } 3009 } 3010 } 3011 3012 public void onBrEdrDown() { 3013 if (VDBG) { 3014 Log.i(TAG, "onBrEdrDown: " + mService); 3015 } 3016 } 3017 }; 3018 3019 /** 3020 * Enable the Bluetooth Adapter, but don't auto-connect devices 3021 * and don't persist state. Only for use by system applications. 3022 * 3023 * @hide 3024 */ 3025 @SystemApi 3026 @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) enableNoAutoConnect()3027 public boolean enableNoAutoConnect() { 3028 if (isEnabled()) { 3029 if (DBG) { 3030 Log.d(TAG, "enableNoAutoConnect(): BT already enabled!"); 3031 } 3032 return true; 3033 } 3034 try { 3035 return mManagerService.enableNoAutoConnect(ActivityThread.currentPackageName()); 3036 } catch (RemoteException e) { 3037 Log.e(TAG, "", e); 3038 } 3039 return false; 3040 } 3041 3042 /** 3043 * Enable control of the Bluetooth Adapter for a single application. 3044 * 3045 * <p>Some applications need to use Bluetooth for short periods of time to 3046 * transfer data but don't want all the associated implications like 3047 * automatic connection to headsets etc. 3048 * 3049 * <p> Multiple applications can call this. This is reference counted and 3050 * Bluetooth disabled only when no one else is using it. There will be no UI 3051 * shown to the user while bluetooth is being enabled. Any user action will 3052 * override this call. For example, if user wants Bluetooth on and the last 3053 * user of this API wanted to disable Bluetooth, Bluetooth will not be 3054 * turned off. 3055 * 3056 * <p> This API is only meant to be used by internal applications. Third 3057 * party applications but use {@link #enable} and {@link #disable} APIs. 3058 * 3059 * <p> If this API returns true, it means the callback will be called. 3060 * The callback will be called with the current state of Bluetooth. 3061 * If the state is not what was requested, an internal error would be the 3062 * reason. If Bluetooth is already on and if this function is called to turn 3063 * it on, the api will return true and a callback will be called. 3064 * 3065 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 3066 * 3067 * @param on True for on, false for off. 3068 * @param callback The callback to notify changes to the state. 3069 * @hide 3070 */ changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback)3071 public boolean changeApplicationBluetoothState(boolean on, 3072 BluetoothStateChangeCallback callback) { 3073 return false; 3074 } 3075 3076 /** 3077 * @hide 3078 */ 3079 public interface BluetoothStateChangeCallback { 3080 /** 3081 * @hide 3082 */ onBluetoothStateChange(boolean on)3083 void onBluetoothStateChange(boolean on); 3084 } 3085 3086 /** 3087 * @hide 3088 */ 3089 public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub { 3090 private BluetoothStateChangeCallback mCallback; 3091 StateChangeCallbackWrapper(BluetoothStateChangeCallback callback)3092 StateChangeCallbackWrapper(BluetoothStateChangeCallback callback) { 3093 mCallback = callback; 3094 } 3095 3096 @Override onBluetoothStateChange(boolean on)3097 public void onBluetoothStateChange(boolean on) { 3098 mCallback.onBluetoothStateChange(on); 3099 } 3100 } 3101 toDeviceSet(BluetoothDevice[] devices)3102 private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) { 3103 Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(Arrays.asList(devices)); 3104 return Collections.unmodifiableSet(deviceSet); 3105 } 3106 finalize()3107 protected void finalize() throws Throwable { 3108 try { 3109 mManagerService.unregisterAdapter(mManagerCallback); 3110 } catch (RemoteException e) { 3111 Log.e(TAG, "", e); 3112 } finally { 3113 super.finalize(); 3114 } 3115 } 3116 3117 3118 /** 3119 * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0" 3120 * <p>Alphabetic characters must be uppercase to be valid. 3121 * 3122 * @param address Bluetooth address as string 3123 * @return true if the address is valid, false otherwise 3124 */ checkBluetoothAddress(String address)3125 public static boolean checkBluetoothAddress(String address) { 3126 if (address == null || address.length() != ADDRESS_LENGTH) { 3127 return false; 3128 } 3129 for (int i = 0; i < ADDRESS_LENGTH; i++) { 3130 char c = address.charAt(i); 3131 switch (i % 3) { 3132 case 0: 3133 case 1: 3134 if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { 3135 // hex character, OK 3136 break; 3137 } 3138 return false; 3139 case 2: 3140 if (c == ':') { 3141 break; // OK 3142 } 3143 return false; 3144 } 3145 } 3146 return true; 3147 } 3148 3149 @UnsupportedAppUsage getBluetoothManager()3150 /*package*/ IBluetoothManager getBluetoothManager() { 3151 return mManagerService; 3152 } 3153 3154 private final ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = 3155 new ArrayList<IBluetoothManagerCallback>(); 3156 3157 @UnsupportedAppUsage getBluetoothService(IBluetoothManagerCallback cb)3158 /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { 3159 synchronized (mProxyServiceStateCallbacks) { 3160 if (cb == null) { 3161 Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback"); 3162 } else if (!mProxyServiceStateCallbacks.contains(cb)) { 3163 mProxyServiceStateCallbacks.add(cb); 3164 } 3165 } 3166 return mService; 3167 } 3168 removeServiceStateCallback(IBluetoothManagerCallback cb)3169 /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) { 3170 synchronized (mProxyServiceStateCallbacks) { 3171 mProxyServiceStateCallbacks.remove(cb); 3172 } 3173 } 3174 3175 /** 3176 * Callback interface used to deliver LE scan results. 3177 * 3178 * @see #startLeScan(LeScanCallback) 3179 * @see #startLeScan(UUID[], LeScanCallback) 3180 */ 3181 public interface LeScanCallback { 3182 /** 3183 * Callback reporting an LE device found during a device scan initiated 3184 * by the {@link BluetoothAdapter#startLeScan} function. 3185 * 3186 * @param device Identifies the remote device 3187 * @param rssi The RSSI value for the remote device as reported by the Bluetooth hardware. 0 3188 * if no RSSI value is available. 3189 * @param scanRecord The content of the advertisement record offered by the remote device. 3190 */ onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)3191 void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); 3192 } 3193 3194 /** 3195 * Starts a scan for Bluetooth LE devices. 3196 * 3197 * <p>Results of the scan are reported using the 3198 * {@link LeScanCallback#onLeScan} callback. 3199 * 3200 * @param callback the callback LE scan results are delivered 3201 * @return true, if the scan was started successfully 3202 * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)} 3203 * instead. 3204 */ 3205 @Deprecated 3206 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) startLeScan(LeScanCallback callback)3207 public boolean startLeScan(LeScanCallback callback) { 3208 return startLeScan(null, callback); 3209 } 3210 3211 /** 3212 * Starts a scan for Bluetooth LE devices, looking for devices that 3213 * advertise given services. 3214 * 3215 * <p>Devices which advertise all specified services are reported using the 3216 * {@link LeScanCallback#onLeScan} callback. 3217 * 3218 * @param serviceUuids Array of services to look for 3219 * @param callback the callback LE scan results are delivered 3220 * @return true, if the scan was started successfully 3221 * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)} 3222 * instead. 3223 */ 3224 @Deprecated 3225 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) startLeScan(final UUID[] serviceUuids, final LeScanCallback callback)3226 public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) { 3227 if (DBG) { 3228 Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids)); 3229 } 3230 if (callback == null) { 3231 if (DBG) { 3232 Log.e(TAG, "startLeScan: null callback"); 3233 } 3234 return false; 3235 } 3236 BluetoothLeScanner scanner = getBluetoothLeScanner(); 3237 if (scanner == null) { 3238 if (DBG) { 3239 Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner"); 3240 } 3241 return false; 3242 } 3243 3244 synchronized (mLeScanClients) { 3245 if (mLeScanClients.containsKey(callback)) { 3246 if (DBG) { 3247 Log.e(TAG, "LE Scan has already started"); 3248 } 3249 return false; 3250 } 3251 3252 try { 3253 IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); 3254 if (iGatt == null) { 3255 // BLE is not supported 3256 return false; 3257 } 3258 3259 ScanCallback scanCallback = new ScanCallback() { 3260 @Override 3261 public void onScanResult(int callbackType, ScanResult result) { 3262 if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { 3263 // Should not happen. 3264 Log.e(TAG, "LE Scan has already started"); 3265 return; 3266 } 3267 ScanRecord scanRecord = result.getScanRecord(); 3268 if (scanRecord == null) { 3269 return; 3270 } 3271 if (serviceUuids != null) { 3272 List<ParcelUuid> uuids = new ArrayList<ParcelUuid>(); 3273 for (UUID uuid : serviceUuids) { 3274 uuids.add(new ParcelUuid(uuid)); 3275 } 3276 List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids(); 3277 if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) { 3278 if (DBG) { 3279 Log.d(TAG, "uuids does not match"); 3280 } 3281 return; 3282 } 3283 } 3284 callback.onLeScan(result.getDevice(), result.getRssi(), 3285 scanRecord.getBytes()); 3286 } 3287 }; 3288 ScanSettings settings = new ScanSettings.Builder().setCallbackType( 3289 ScanSettings.CALLBACK_TYPE_ALL_MATCHES) 3290 .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) 3291 .build(); 3292 3293 List<ScanFilter> filters = new ArrayList<ScanFilter>(); 3294 if (serviceUuids != null && serviceUuids.length > 0) { 3295 // Note scan filter does not support matching an UUID array so we put one 3296 // UUID to hardware and match the whole array in callback. 3297 ScanFilter filter = 3298 new ScanFilter.Builder().setServiceUuid(new ParcelUuid(serviceUuids[0])) 3299 .build(); 3300 filters.add(filter); 3301 } 3302 scanner.startScan(filters, settings, scanCallback); 3303 3304 mLeScanClients.put(callback, scanCallback); 3305 return true; 3306 3307 } catch (RemoteException e) { 3308 Log.e(TAG, "", e); 3309 } 3310 } 3311 return false; 3312 } 3313 3314 /** 3315 * Stops an ongoing Bluetooth LE device scan. 3316 * 3317 * @param callback used to identify which scan to stop must be the same handle used to start the 3318 * scan 3319 * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead. 3320 */ 3321 @Deprecated 3322 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) stopLeScan(LeScanCallback callback)3323 public void stopLeScan(LeScanCallback callback) { 3324 if (DBG) { 3325 Log.d(TAG, "stopLeScan()"); 3326 } 3327 BluetoothLeScanner scanner = getBluetoothLeScanner(); 3328 if (scanner == null) { 3329 return; 3330 } 3331 synchronized (mLeScanClients) { 3332 ScanCallback scanCallback = mLeScanClients.remove(callback); 3333 if (scanCallback == null) { 3334 if (DBG) { 3335 Log.d(TAG, "scan not started yet"); 3336 } 3337 return; 3338 } 3339 scanner.stopScan(scanCallback); 3340 } 3341 } 3342 3343 /** 3344 * Create a secure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and 3345 * assign a dynamic protocol/service multiplexer (PSM) value. This socket can be used to listen 3346 * for incoming connections. The supported Bluetooth transport is LE only. 3347 * <p>A remote device connecting to this socket will be authenticated and communication on this 3348 * socket will be encrypted. 3349 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening 3350 * {@link BluetoothServerSocket}. 3351 * <p>The system will assign a dynamic PSM value. This PSM value can be read from the {@link 3352 * BluetoothServerSocket#getPsm()} and this value will be released when this server socket is 3353 * closed, Bluetooth is turned off, or the application exits unexpectedly. 3354 * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is 3355 * defined and performed by the application. 3356 * <p>Use {@link BluetoothDevice#createL2capChannel(int)} to connect to this server 3357 * socket from another Android device that is given the PSM value. 3358 * 3359 * @return an L2CAP CoC BluetoothServerSocket 3360 * @throws IOException on error, for example Bluetooth not available, or insufficient 3361 * permissions, or unable to start this CoC 3362 */ 3363 @RequiresPermission(Manifest.permission.BLUETOOTH) listenUsingL2capChannel()3364 public @NonNull BluetoothServerSocket listenUsingL2capChannel() 3365 throws IOException { 3366 BluetoothServerSocket socket = 3367 new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true, 3368 SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false); 3369 int errno = socket.mSocket.bindListen(); 3370 if (errno != 0) { 3371 throw new IOException("Error: " + errno); 3372 } 3373 3374 int assignedPsm = socket.mSocket.getPort(); 3375 if (assignedPsm == 0) { 3376 throw new IOException("Error: Unable to assign PSM value"); 3377 } 3378 if (DBG) { 3379 Log.d(TAG, "listenUsingL2capChannel: set assigned PSM to " 3380 + assignedPsm); 3381 } 3382 socket.setChannel(assignedPsm); 3383 3384 return socket; 3385 } 3386 3387 /** 3388 * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and 3389 * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The 3390 * supported Bluetooth transport is LE only. 3391 * <p>The link key is not required to be authenticated, i.e the communication may be vulnerable 3392 * to man-in-the-middle attacks. Use {@link #listenUsingL2capChannel}, if an encrypted and 3393 * authenticated communication channel is desired. 3394 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening 3395 * {@link BluetoothServerSocket}. 3396 * <p>The system will assign a dynamic protocol/service multiplexer (PSM) value. This PSM value 3397 * can be read from the {@link BluetoothServerSocket#getPsm()} and this value will be released 3398 * when this server socket is closed, Bluetooth is turned off, or the application exits 3399 * unexpectedly. 3400 * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is 3401 * defined and performed by the application. 3402 * <p>Use {@link BluetoothDevice#createInsecureL2capChannel(int)} to connect to this server 3403 * socket from another Android device that is given the PSM value. 3404 * 3405 * @return an L2CAP CoC BluetoothServerSocket 3406 * @throws IOException on error, for example Bluetooth not available, or insufficient 3407 * permissions, or unable to start this CoC 3408 */ 3409 @RequiresPermission(Manifest.permission.BLUETOOTH) listenUsingInsecureL2capChannel()3410 public @NonNull BluetoothServerSocket listenUsingInsecureL2capChannel() 3411 throws IOException { 3412 BluetoothServerSocket socket = 3413 new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false, 3414 SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false); 3415 int errno = socket.mSocket.bindListen(); 3416 if (errno != 0) { 3417 throw new IOException("Error: " + errno); 3418 } 3419 3420 int assignedPsm = socket.mSocket.getPort(); 3421 if (assignedPsm == 0) { 3422 throw new IOException("Error: Unable to assign PSM value"); 3423 } 3424 if (DBG) { 3425 Log.d(TAG, "listenUsingInsecureL2capChannel: set assigned PSM to " 3426 + assignedPsm); 3427 } 3428 socket.setChannel(assignedPsm); 3429 3430 return socket; 3431 } 3432 3433 /** 3434 * Register a {@link #OnMetadataChangedListener} to receive update about metadata 3435 * changes for this {@link BluetoothDevice}. 3436 * Registration must be done when Bluetooth is ON and will last until 3437 * {@link #removeOnMetadataChangedListener(BluetoothDevice)} is called, even when Bluetooth 3438 * restarted in the middle. 3439 * All input parameters should not be null or {@link NullPointerException} will be triggered. 3440 * The same {@link BluetoothDevice} and {@link #OnMetadataChangedListener} pair can only be 3441 * registered once, double registration would cause {@link IllegalArgumentException}. 3442 * 3443 * @param device {@link BluetoothDevice} that will be registered 3444 * @param executor the executor for listener callback 3445 * @param listener {@link #OnMetadataChangedListener} that will receive asynchronous callbacks 3446 * @return true on success, false on error 3447 * @throws NullPointerException If one of {@code listener}, {@code device} or {@code executor} 3448 * is null. 3449 * @throws IllegalArgumentException The same {@link #OnMetadataChangedListener} and 3450 * {@link BluetoothDevice} are registered twice. 3451 * @hide 3452 */ 3453 @SystemApi 3454 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) addOnMetadataChangedListener(@onNull BluetoothDevice device, @NonNull Executor executor, @NonNull OnMetadataChangedListener listener)3455 public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device, 3456 @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) { 3457 if (DBG) Log.d(TAG, "addOnMetadataChangedListener()"); 3458 3459 final IBluetooth service = mService; 3460 if (service == null) { 3461 Log.e(TAG, "Bluetooth is not enabled. Cannot register metadata listener"); 3462 return false; 3463 } 3464 if (listener == null) { 3465 throw new NullPointerException("listener is null"); 3466 } 3467 if (device == null) { 3468 throw new NullPointerException("device is null"); 3469 } 3470 if (executor == null) { 3471 throw new NullPointerException("executor is null"); 3472 } 3473 3474 synchronized (sMetadataListeners) { 3475 List<Pair<OnMetadataChangedListener, Executor>> listenerList = 3476 sMetadataListeners.get(device); 3477 if (listenerList == null) { 3478 // Create new listener/executor list for registeration 3479 listenerList = new ArrayList<>(); 3480 sMetadataListeners.put(device, listenerList); 3481 } else { 3482 // Check whether this device was already registed by the lisenter 3483 if (listenerList.stream().anyMatch((pair) -> (pair.first.equals(listener)))) { 3484 throw new IllegalArgumentException("listener was already regestered" 3485 + " for the device"); 3486 } 3487 } 3488 3489 Pair<OnMetadataChangedListener, Executor> listenerPair = new Pair(listener, executor); 3490 listenerList.add(listenerPair); 3491 3492 boolean ret = false; 3493 try { 3494 ret = service.registerMetadataListener(sBluetoothMetadataListener, device); 3495 } catch (RemoteException e) { 3496 Log.e(TAG, "registerMetadataListener fail", e); 3497 } finally { 3498 if (!ret) { 3499 // Remove listener registered earlier when fail. 3500 listenerList.remove(listenerPair); 3501 if (listenerList.isEmpty()) { 3502 // Remove the device if its listener list is empty 3503 sMetadataListeners.remove(device); 3504 } 3505 } 3506 } 3507 return ret; 3508 } 3509 } 3510 3511 /** 3512 * Unregister a {@link #OnMetadataChangedListener} from a registered {@link BluetoothDevice}. 3513 * Unregistration can be done when Bluetooth is either ON or OFF. 3514 * {@link #addOnMetadataChangedListener(OnMetadataChangedListener, BluetoothDevice, Executor)} 3515 * must be called before unregisteration. 3516 * 3517 * @param device {@link BluetoothDevice} that will be unregistered. It 3518 * should not be null or {@link NullPointerException} will be triggered. 3519 * @param listener {@link OnMetadataChangedListener} that will be unregistered. It 3520 * should not be null or {@link NullPointerException} will be triggered. 3521 * @return true on success, false on error 3522 * @throws NullPointerException If {@code listener} or {@code device} is null. 3523 * @throws IllegalArgumentException If {@code device} has not been registered before. 3524 * @hide 3525 */ 3526 @SystemApi 3527 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) removeOnMetadataChangedListener(@onNull BluetoothDevice device, @NonNull OnMetadataChangedListener listener)3528 public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device, 3529 @NonNull OnMetadataChangedListener listener) { 3530 if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()"); 3531 if (device == null) { 3532 throw new NullPointerException("device is null"); 3533 } 3534 if (listener == null) { 3535 throw new NullPointerException("listener is null"); 3536 } 3537 3538 synchronized (sMetadataListeners) { 3539 if (!sMetadataListeners.containsKey(device)) { 3540 throw new IllegalArgumentException("device was not registered"); 3541 } 3542 // Remove issued listener from the registered device 3543 sMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener))); 3544 3545 if (sMetadataListeners.get(device).isEmpty()) { 3546 // Unregister to Bluetooth service if all listeners are removed from 3547 // the registered device 3548 sMetadataListeners.remove(device); 3549 final IBluetooth service = mService; 3550 if (service == null) { 3551 // Bluetooth is OFF, do nothing to Bluetooth service. 3552 return true; 3553 } 3554 try { 3555 return service.unregisterMetadataListener(device); 3556 } catch (RemoteException e) { 3557 Log.e(TAG, "unregisterMetadataListener fail", e); 3558 return false; 3559 } 3560 } 3561 } 3562 return true; 3563 } 3564 3565 /** 3566 * This interface is used to implement {@link BluetoothAdapter} metadata listener. 3567 * @hide 3568 */ 3569 @SystemApi 3570 public interface OnMetadataChangedListener { 3571 /** 3572 * Callback triggered if the metadata of {@link BluetoothDevice} registered in 3573 * {@link #addOnMetadataChangedListener}. 3574 * 3575 * @param device changed {@link BluetoothDevice}. 3576 * @param key changed metadata key, one of BluetoothDevice.METADATA_*. 3577 * @param value the new value of metadata as byte array. 3578 */ onMetadataChanged(@onNull BluetoothDevice device, int key, @Nullable byte[] value)3579 void onMetadataChanged(@NonNull BluetoothDevice device, int key, 3580 @Nullable byte[] value); 3581 } 3582 3583 /** 3584 * Converts old constant of priority to the new for connection policy 3585 * 3586 * @param priority is the priority to convert to connection policy 3587 * @return the equivalent connection policy constant to the priority 3588 * 3589 * @hide 3590 */ priorityToConnectionPolicy(int priority)3591 public static @ConnectionPolicy int priorityToConnectionPolicy(int priority) { 3592 switch(priority) { 3593 case BluetoothProfile.PRIORITY_AUTO_CONNECT: 3594 return BluetoothProfile.CONNECTION_POLICY_ALLOWED; 3595 case BluetoothProfile.PRIORITY_ON: 3596 return BluetoothProfile.CONNECTION_POLICY_ALLOWED; 3597 case BluetoothProfile.PRIORITY_OFF: 3598 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; 3599 case BluetoothProfile.PRIORITY_UNDEFINED: 3600 return BluetoothProfile.CONNECTION_POLICY_UNKNOWN; 3601 default: 3602 Log.e(TAG, "setPriority: Invalid priority: " + priority); 3603 return BluetoothProfile.CONNECTION_POLICY_UNKNOWN; 3604 } 3605 } 3606 3607 /** 3608 * Converts new constant of connection policy to the old for priority 3609 * 3610 * @param connectionPolicy is the connection policy to convert to priority 3611 * @return the equivalent priority constant to the connectionPolicy 3612 * 3613 * @hide 3614 */ connectionPolicyToPriority(@onnectionPolicy int connectionPolicy)3615 public static int connectionPolicyToPriority(@ConnectionPolicy int connectionPolicy) { 3616 switch(connectionPolicy) { 3617 case BluetoothProfile.CONNECTION_POLICY_ALLOWED: 3618 return BluetoothProfile.PRIORITY_ON; 3619 case BluetoothProfile.CONNECTION_POLICY_FORBIDDEN: 3620 return BluetoothProfile.PRIORITY_OFF; 3621 case BluetoothProfile.CONNECTION_POLICY_UNKNOWN: 3622 return BluetoothProfile.PRIORITY_UNDEFINED; 3623 } 3624 return BluetoothProfile.PRIORITY_UNDEFINED; 3625 } 3626 } 3627