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