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