1 /* 2 * Copyright (C) 2009-2015 The Android Open Source Project 3 * Copyright (C) 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.RequiresPermission; 23 import android.annotation.SdkConstant; 24 import android.annotation.SdkConstant.SdkConstantType; 25 import android.annotation.SystemApi; 26 import android.bluetooth.le.BluetoothLeAdvertiser; 27 import android.bluetooth.le.BluetoothLeScanner; 28 import android.bluetooth.le.ScanCallback; 29 import android.bluetooth.le.ScanFilter; 30 import android.bluetooth.le.ScanRecord; 31 import android.bluetooth.le.ScanResult; 32 import android.bluetooth.le.ScanSettings; 33 import android.content.Context; 34 import android.os.Binder; 35 import android.os.IBinder; 36 import android.os.ParcelUuid; 37 import android.os.RemoteException; 38 import android.os.ServiceManager; 39 import android.util.Log; 40 import android.util.Pair; 41 42 import java.io.IOException; 43 import java.lang.annotation.Retention; 44 import java.lang.annotation.RetentionPolicy; 45 import java.util.ArrayList; 46 import java.util.Arrays; 47 import java.util.Collections; 48 import java.util.HashMap; 49 import java.util.HashSet; 50 import java.util.List; 51 import java.util.Locale; 52 import java.util.Map; 53 import java.util.Set; 54 import java.util.UUID; 55 56 /** 57 * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter} 58 * lets you perform fundamental Bluetooth tasks, such as initiate 59 * device discovery, query a list of bonded (paired) devices, 60 * instantiate a {@link BluetoothDevice} using a known MAC address, and create 61 * a {@link BluetoothServerSocket} to listen for connection requests from other 62 * devices, and start a scan for Bluetooth LE devices. 63 * 64 * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth 65 * adapter, when running on JELLY_BEAN_MR1 and below, call the 66 * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and 67 * higher, retrieve it through 68 * {@link android.content.Context#getSystemService} with 69 * {@link android.content.Context#BLUETOOTH_SERVICE}. 70 * Fundamentally, this is your starting point for all 71 * Bluetooth actions. Once you have the local adapter, you can get a set of 72 * {@link BluetoothDevice} objects representing all paired devices with 73 * {@link #getBondedDevices()}; start device discovery with 74 * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to 75 * listen for incoming connection requests with 76 * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}; or start a scan for 77 * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. 78 * 79 * <p class="note"><strong>Note:</strong> 80 * Most methods require the {@link android.Manifest.permission#BLUETOOTH} 81 * permission and some also require the 82 * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 83 * 84 * <div class="special reference"> 85 * <h3>Developer Guides</h3> 86 * <p>For more information about using Bluetooth, read the 87 * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p> 88 * </div> 89 * 90 * {@see BluetoothDevice} 91 * {@see BluetoothServerSocket} 92 */ 93 public final class BluetoothAdapter { 94 private static final String TAG = "BluetoothAdapter"; 95 private static final boolean DBG = true; 96 private static final boolean VDBG = false; 97 98 /** 99 * Default MAC address reported to a client that does not have the 100 * android.permission.LOCAL_MAC_ADDRESS permission. 101 * 102 * @hide 103 */ 104 public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; 105 106 /** 107 * Sentinel error value for this class. Guaranteed to not equal any other 108 * integer constant in this class. Provided as a convenience for functions 109 * that require a sentinel error value, for example: 110 * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 111 * BluetoothAdapter.ERROR)</code> 112 */ 113 public static final int ERROR = Integer.MIN_VALUE; 114 115 /** 116 * Broadcast Action: The state of the local Bluetooth adapter has been 117 * changed. 118 * <p>For example, Bluetooth has been turned on or off. 119 * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link 120 * #EXTRA_PREVIOUS_STATE} containing the new and old states 121 * respectively. 122 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 123 */ 124 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 125 public static final String ACTION_STATE_CHANGED = 126 "android.bluetooth.adapter.action.STATE_CHANGED"; 127 128 /** 129 * Used as an int extra field in {@link #ACTION_STATE_CHANGED} 130 * intents to request the current power state. Possible values are: 131 * {@link #STATE_OFF}, 132 * {@link #STATE_TURNING_ON}, 133 * {@link #STATE_ON}, 134 * {@link #STATE_TURNING_OFF}, 135 */ 136 public static final String EXTRA_STATE = 137 "android.bluetooth.adapter.extra.STATE"; 138 /** 139 * Used as an int extra field in {@link #ACTION_STATE_CHANGED} 140 * intents to request the previous power state. Possible values are: 141 * {@link #STATE_OFF}, 142 * {@link #STATE_TURNING_ON}, 143 * {@link #STATE_ON}, 144 * {@link #STATE_TURNING_OFF} 145 */ 146 public static final String EXTRA_PREVIOUS_STATE = 147 "android.bluetooth.adapter.extra.PREVIOUS_STATE"; 148 149 /** @hide */ 150 @IntDef({STATE_OFF, STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, STATE_BLE_TURNING_ON, 151 STATE_BLE_ON, STATE_BLE_TURNING_OFF}) 152 @Retention(RetentionPolicy.SOURCE) 153 public @interface AdapterState {} 154 155 /** 156 * Indicates the local Bluetooth adapter is off. 157 */ 158 public static final int STATE_OFF = 10; 159 /** 160 * Indicates the local Bluetooth adapter is turning on. However local 161 * clients should wait for {@link #STATE_ON} before attempting to 162 * use the adapter. 163 */ 164 public static final int STATE_TURNING_ON = 11; 165 /** 166 * Indicates the local Bluetooth adapter is on, and ready for use. 167 */ 168 public static final int STATE_ON = 12; 169 /** 170 * Indicates the local Bluetooth adapter is turning off. Local clients 171 * should immediately attempt graceful disconnection of any remote links. 172 */ 173 public static final int STATE_TURNING_OFF = 13; 174 175 /** 176 * Indicates the local Bluetooth adapter is turning Bluetooth LE mode on. 177 * @hide 178 */ 179 public static final int STATE_BLE_TURNING_ON = 14; 180 181 /** 182 * Indicates the local Bluetooth adapter is in LE only mode. 183 * @hide 184 */ 185 public static final int STATE_BLE_ON = 15; 186 187 /** 188 * Indicates the local Bluetooth adapter is turning off LE only mode. 189 * @hide 190 */ 191 public static final int STATE_BLE_TURNING_OFF = 16; 192 193 /** 194 * Activity Action: Show a system activity that requests discoverable mode. 195 * This activity will also request the user to turn on Bluetooth if it 196 * is not currently enabled. 197 * <p>Discoverable mode is equivalent to {@link 198 * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see 199 * this Bluetooth adapter when they perform a discovery. 200 * <p>For privacy, Android is not discoverable by default. 201 * <p>The sender of this Intent can optionally use extra field {@link 202 * #EXTRA_DISCOVERABLE_DURATION} to request the duration of 203 * discoverability. Currently the default duration is 120 seconds, and 204 * maximum duration is capped at 300 seconds for each request. 205 * <p>Notification of the result of this activity is posted using the 206 * {@link android.app.Activity#onActivityResult} callback. The 207 * <code>resultCode</code> 208 * will be the duration (in seconds) of discoverability or 209 * {@link android.app.Activity#RESULT_CANCELED} if the user rejected 210 * discoverability or an error has occurred. 211 * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED} 212 * for global notification whenever the scan mode changes. For example, an 213 * application can be notified when the device has ended discoverability. 214 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 215 */ 216 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 217 public static final String ACTION_REQUEST_DISCOVERABLE = 218 "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"; 219 220 /** 221 * Used as an optional int extra field in {@link 222 * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration 223 * for discoverability in seconds. The current default is 120 seconds, and 224 * requests over 300 seconds will be capped. These values could change. 225 */ 226 public static final String EXTRA_DISCOVERABLE_DURATION = 227 "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; 228 229 /** 230 * Activity Action: Show a system activity that allows the user to turn on 231 * Bluetooth. 232 * <p>This system activity will return once Bluetooth has completed turning 233 * on, or the user has decided not to turn Bluetooth on. 234 * <p>Notification of the result of this activity is posted using the 235 * {@link android.app.Activity#onActivityResult} callback. The 236 * <code>resultCode</code> 237 * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been 238 * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user 239 * has rejected the request or an error has occurred. 240 * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED} 241 * for global notification whenever Bluetooth is turned on or off. 242 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 243 */ 244 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 245 public static final String ACTION_REQUEST_ENABLE = 246 "android.bluetooth.adapter.action.REQUEST_ENABLE"; 247 248 /** 249 * Activity Action: Show a system activity that allows user to enable BLE scans even when 250 * Bluetooth is turned off.<p> 251 * 252 * Notification of result of this activity is posted using 253 * {@link android.app.Activity#onActivityResult}. The <code>resultCode</code> will be 254 * {@link android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or 255 * {@link android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an 256 * error occurred. 257 * 258 * @hide 259 */ 260 @SystemApi 261 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 262 public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = 263 "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE"; 264 265 /** 266 * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter 267 * has changed. 268 * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link 269 * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes 270 * respectively. 271 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 272 */ 273 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 274 public static final String ACTION_SCAN_MODE_CHANGED = 275 "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; 276 277 /** 278 * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} 279 * intents to request the current scan mode. Possible values are: 280 * {@link #SCAN_MODE_NONE}, 281 * {@link #SCAN_MODE_CONNECTABLE}, 282 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, 283 */ 284 public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE"; 285 /** 286 * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} 287 * intents to request the previous scan mode. Possible values are: 288 * {@link #SCAN_MODE_NONE}, 289 * {@link #SCAN_MODE_CONNECTABLE}, 290 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, 291 */ 292 public static final String EXTRA_PREVIOUS_SCAN_MODE = 293 "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE"; 294 295 /** @hide */ 296 @IntDef({SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE}) 297 @Retention(RetentionPolicy.SOURCE) 298 public @interface ScanMode {} 299 300 /** 301 * Indicates that both inquiry scan and page scan are disabled on the local 302 * Bluetooth adapter. Therefore this device is neither discoverable 303 * nor connectable from remote Bluetooth devices. 304 */ 305 public static final int SCAN_MODE_NONE = 20; 306 /** 307 * Indicates that inquiry scan is disabled, but page scan is enabled on the 308 * local Bluetooth adapter. Therefore this device is not discoverable from 309 * remote Bluetooth devices, but is connectable from remote devices that 310 * have previously discovered this device. 311 */ 312 public static final int SCAN_MODE_CONNECTABLE = 21; 313 /** 314 * Indicates that both inquiry scan and page scan are enabled on the local 315 * Bluetooth adapter. Therefore this device is both discoverable and 316 * connectable from remote Bluetooth devices. 317 */ 318 public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; 319 320 /** 321 * Broadcast Action: The local Bluetooth adapter has started the remote 322 * device discovery process. 323 * <p>This usually involves an inquiry scan of about 12 seconds, followed 324 * by a page scan of each new device to retrieve its Bluetooth name. 325 * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as 326 * remote Bluetooth devices are found. 327 * <p>Device discovery is a heavyweight procedure. New connections to 328 * remote Bluetooth devices should not be attempted while discovery is in 329 * progress, and existing connections will experience limited bandwidth 330 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing 331 * discovery. 332 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 333 */ 334 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 335 public static final String ACTION_DISCOVERY_STARTED = 336 "android.bluetooth.adapter.action.DISCOVERY_STARTED"; 337 /** 338 * Broadcast Action: The local Bluetooth adapter has finished the device 339 * discovery process. 340 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 341 */ 342 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 343 public static final String ACTION_DISCOVERY_FINISHED = 344 "android.bluetooth.adapter.action.DISCOVERY_FINISHED"; 345 346 /** 347 * Broadcast Action: The local Bluetooth adapter has changed its friendly 348 * Bluetooth name. 349 * <p>This name is visible to remote Bluetooth devices. 350 * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing 351 * the name. 352 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 353 */ 354 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 355 public static final String ACTION_LOCAL_NAME_CHANGED = 356 "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED"; 357 /** 358 * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED} 359 * intents to request the local Bluetooth name. 360 */ 361 public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME"; 362 363 /** 364 * Intent used to broadcast the change in connection state of the local 365 * Bluetooth adapter to a profile of the remote device. When the adapter is 366 * not connected to any profiles of any remote devices and it attempts a 367 * connection to a profile this intent will sent. Once connected, this intent 368 * will not be sent for any more connection attempts to any profiles of any 369 * remote device. When the adapter disconnects from the last profile its 370 * connected to of any remote device, this intent will be sent. 371 * 372 * <p> This intent is useful for applications that are only concerned about 373 * whether the local adapter is connected to any profile of any device and 374 * are not really concerned about which profile. For example, an application 375 * which displays an icon to display whether Bluetooth is connected or not 376 * can use this intent. 377 * 378 * <p>This intent will have 3 extras: 379 * {@link #EXTRA_CONNECTION_STATE} - The current connection state. 380 * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state. 381 * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. 382 * 383 * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE} 384 * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, 385 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. 386 * 387 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 388 */ 389 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 390 public static final String ACTION_CONNECTION_STATE_CHANGED = 391 "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"; 392 393 /** 394 * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} 395 * 396 * This extra represents the current connection state. 397 */ 398 public static final String EXTRA_CONNECTION_STATE = 399 "android.bluetooth.adapter.extra.CONNECTION_STATE"; 400 401 /** 402 * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} 403 * 404 * This extra represents the previous connection state. 405 */ 406 public static final String EXTRA_PREVIOUS_CONNECTION_STATE = 407 "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE"; 408 409 /** 410 * Broadcast Action: The Bluetooth adapter state has changed in LE only mode. 411 * @hide 412 */ 413 @SystemApi 414 public static final String ACTION_BLE_STATE_CHANGED = 415 "android.bluetooth.adapter.action.BLE_STATE_CHANGED"; 416 417 /** 418 * Broadcast Action: The notifys Bluetooth ACL connected event. This will be 419 * by BLE Always on enabled application to know the ACL_CONNECTED event 420 * when Bluetooth state in STATE_BLE_ON. This denotes GATT connection 421 * as Bluetooth LE is the only feature available in STATE_BLE_ON 422 * 423 * This is counterpart of {@link BluetoothDevice#ACTION_ACL_CONNECTED} which 424 * works in Bluetooth state STATE_ON 425 * @hide 426 */ 427 public static final String ACTION_BLE_ACL_CONNECTED = 428 "android.bluetooth.adapter.action.BLE_ACL_CONNECTED"; 429 430 /** 431 * Broadcast Action: The notifys Bluetooth ACL connected event. This will be 432 * by BLE Always on enabled application to know the ACL_DISCONNECTED event 433 * when Bluetooth state in STATE_BLE_ON. This denotes GATT disconnection as Bluetooth 434 * LE is the only feature available in STATE_BLE_ON 435 * 436 * This is counterpart of {@link BluetoothDevice#ACTION_ACL_DISCONNECTED} which 437 * works in Bluetooth state STATE_ON 438 * @hide 439 */ 440 public static final String ACTION_BLE_ACL_DISCONNECTED = 441 "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED"; 442 443 /** The profile is in disconnected state */ 444 public static final int STATE_DISCONNECTED = 0; 445 /** The profile is in connecting state */ 446 public static final int STATE_CONNECTING = 1; 447 /** The profile is in connected state */ 448 public static final int STATE_CONNECTED = 2; 449 /** The profile is in disconnecting state */ 450 public static final int STATE_DISCONNECTING = 3; 451 452 /** @hide */ 453 public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; 454 private final IBinder mToken; 455 456 457 /** When creating a ServerSocket using listenUsingRfcommOn() or 458 * listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create 459 * a ServerSocket that auto assigns a channel number to the first 460 * bluetooth socket. 461 * The channel number assigned to this first Bluetooth Socket will 462 * be stored in the ServerSocket, and reused for subsequent Bluetooth 463 * sockets. 464 * @hide */ 465 public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2; 466 467 468 private static final int ADDRESS_LENGTH = 17; 469 470 private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30; 471 /** @hide */ 472 public static final int ACTIVITY_ENERGY_INFO_CACHED = 0; 473 /** @hide */ 474 public static final int ACTIVITY_ENERGY_INFO_REFRESHED = 1; 475 476 /** 477 * Lazily initialized singleton. Guaranteed final after first object 478 * constructed. 479 */ 480 private static BluetoothAdapter sAdapter; 481 482 private static BluetoothLeScanner sBluetoothLeScanner; 483 private static BluetoothLeAdvertiser sBluetoothLeAdvertiser; 484 485 private final IBluetoothManager mManagerService; 486 private IBluetooth mService; 487 488 private final Object mLock = new Object(); 489 private final Map<LeScanCallback, ScanCallback> mLeScanClients; 490 491 /** 492 * Get a handle to the default local Bluetooth adapter. 493 * <p>Currently Android only supports one Bluetooth adapter, but the API 494 * could be extended to support more. This will always return the default 495 * adapter. 496 * @return the default local adapter, or null if Bluetooth is not supported 497 * on this hardware platform 498 */ getDefaultAdapter()499 public static synchronized BluetoothAdapter getDefaultAdapter() { 500 if (sAdapter == null) { 501 IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE); 502 if (b != null) { 503 IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b); 504 sAdapter = new BluetoothAdapter(managerService); 505 } else { 506 Log.e(TAG, "Bluetooth binder is null"); 507 } 508 } 509 return sAdapter; 510 } 511 512 /** 513 * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. 514 */ BluetoothAdapter(IBluetoothManager managerService)515 BluetoothAdapter(IBluetoothManager managerService) { 516 517 if (managerService == null) { 518 throw new IllegalArgumentException("bluetooth manager service is null"); 519 } 520 try { 521 mService = managerService.registerAdapter(mManagerCallback); 522 } catch (RemoteException e) {Log.e(TAG, "", e);} 523 mManagerService = managerService; 524 mLeScanClients = new HashMap<LeScanCallback, ScanCallback>(); 525 mToken = new Binder(); 526 } 527 528 /** 529 * Get a {@link BluetoothDevice} object for the given Bluetooth hardware 530 * address. 531 * <p>Valid Bluetooth hardware addresses must be upper case, in a format 532 * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is 533 * available to validate a Bluetooth address. 534 * <p>A {@link BluetoothDevice} will always be returned for a valid 535 * hardware address, even if this adapter has never seen that device. 536 * 537 * @param address valid Bluetooth MAC address 538 * @throws IllegalArgumentException if address is invalid 539 */ getRemoteDevice(String address)540 public BluetoothDevice getRemoteDevice(String address) { 541 return new BluetoothDevice(address); 542 } 543 544 /** 545 * Get a {@link BluetoothDevice} object for the given Bluetooth hardware 546 * address. 547 * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method 548 * expects the address in network byte order (MSB first). 549 * <p>A {@link BluetoothDevice} will always be returned for a valid 550 * hardware address, even if this adapter has never seen that device. 551 * 552 * @param address Bluetooth MAC address (6 bytes) 553 * @throws IllegalArgumentException if address is invalid 554 */ getRemoteDevice(byte[] address)555 public BluetoothDevice getRemoteDevice(byte[] address) { 556 if (address == null || address.length != 6) { 557 throw new IllegalArgumentException("Bluetooth address must have 6 bytes"); 558 } 559 return new BluetoothDevice(String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", 560 address[0], address[1], address[2], address[3], address[4], address[5])); 561 } 562 563 /** 564 * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations. 565 * Will return null if Bluetooth is turned off or if Bluetooth LE Advertising is not 566 * supported on this device. 567 * <p> 568 * Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported 569 * on this device before calling this method. 570 */ getBluetoothLeAdvertiser()571 public BluetoothLeAdvertiser getBluetoothLeAdvertiser() { 572 if (!getLeAccess()) return null; 573 if (!isMultipleAdvertisementSupported() && !isPeripheralModeSupported()) { 574 Log.e(TAG, "Bluetooth LE advertising not supported"); 575 return null; 576 } 577 synchronized(mLock) { 578 if (sBluetoothLeAdvertiser == null) { 579 sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService); 580 } 581 } 582 return sBluetoothLeAdvertiser; 583 } 584 585 /** 586 * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. 587 */ getBluetoothLeScanner()588 public BluetoothLeScanner getBluetoothLeScanner() { 589 if (!getLeAccess()) return null; 590 synchronized(mLock) { 591 if (sBluetoothLeScanner == null) { 592 sBluetoothLeScanner = new BluetoothLeScanner(mManagerService); 593 } 594 } 595 return sBluetoothLeScanner; 596 } 597 598 /** 599 * Return true if Bluetooth is currently enabled and ready for use. 600 * <p>Equivalent to: 601 * <code>getBluetoothState() == STATE_ON</code> 602 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 603 * 604 * @return true if the local adapter is turned on 605 */ 606 @RequiresPermission(Manifest.permission.BLUETOOTH) isEnabled()607 public boolean isEnabled() { 608 try { 609 synchronized(mManagerCallback) { 610 if (mService != null) return mService.isEnabled(); 611 } 612 } catch (RemoteException e) {Log.e(TAG, "", e);} 613 return false; 614 } 615 616 /** 617 * Return true if Bluetooth LE(Always BLE On feature) is currently 618 * enabled and ready for use 619 * <p>This returns true if current state is either STATE_ON or STATE_BLE_ON 620 * 621 * @return true if the local Bluetooth LE adapter is turned on 622 * @hide 623 */ 624 @SystemApi isLeEnabled()625 public boolean isLeEnabled() { 626 final int state = getLeState(); 627 if (state == BluetoothAdapter.STATE_ON) { 628 if (DBG) Log.d (TAG, "STATE_ON"); 629 } else if (state == BluetoothAdapter.STATE_BLE_ON) { 630 if (DBG) Log.d (TAG, "STATE_BLE_ON"); 631 } else { 632 if (DBG) Log.d (TAG, "STATE_OFF"); 633 return false; 634 } 635 return true; 636 } 637 638 /** 639 * Performs action based on user action to turn BT ON 640 * or OFF if BT is in BLE_ON state 641 */ notifyUserAction(boolean enable)642 private void notifyUserAction(boolean enable) { 643 if (mService == null) { 644 Log.e(TAG, "mService is null"); 645 return; 646 } 647 648 try { 649 if (enable) { 650 mService.onLeServiceUp(); //NA:TODO implementation pending 651 } else { 652 mService.onBrEdrDown(); //NA:TODO implementation pending 653 } 654 } catch (RemoteException e) { 655 Log.e(TAG, "", e); 656 } 657 } 658 659 /** 660 * Turns off Bluetooth LE which was earlier turned on by calling EnableBLE(). 661 * 662 * <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition 663 * to STATE_OFF and completely shut-down Bluetooth 664 * 665 * <p> If the Adapter state is STATE_ON, This would unregister the existance of 666 * special Bluetooth LE application and hence the further turning off of Bluetooth 667 * from UI would ensure the complete turn-off of Bluetooth rather than staying back 668 * BLE only state 669 * 670 * <p>This is an asynchronous call: it will return immediately, and 671 * clients should listen for {@link #ACTION_BLE_STATE_CHANGED} 672 * to be notified of subsequent adapter state changes If this call returns 673 * true, then the adapter state will immediately transition from {@link 674 * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time 675 * later transition to either {@link #STATE_BLE_ON} or {@link 676 * #STATE_OFF} based on the existance of the further Always BLE ON enabled applications 677 * If this call returns false then there was an 678 * immediate problem that will prevent the QAdapter from being turned off - 679 * such as the QAadapter already being turned off. 680 * 681 * @return true to indicate success, or false on 682 * immediate error 683 * @hide 684 */ 685 @SystemApi disableBLE()686 public boolean disableBLE() { 687 if (!isBleScanAlwaysAvailable()) return false; 688 689 int state = getLeState(); 690 if (state == BluetoothAdapter.STATE_ON) { 691 if (DBG) Log.d (TAG, "STATE_ON: shouldn't disable"); 692 try { 693 mManagerService.updateBleAppCount(mToken, false); 694 } catch (RemoteException e) { 695 Log.e(TAG, "", e); 696 } 697 return true; 698 699 } else if (state == BluetoothAdapter.STATE_BLE_ON) { 700 if (DBG) Log.d (TAG, "STATE_BLE_ON"); 701 int bleAppCnt = 0; 702 try { 703 bleAppCnt = mManagerService.updateBleAppCount(mToken, false); 704 } catch (RemoteException e) { 705 Log.e(TAG, "", e); 706 } 707 if (bleAppCnt == 0) { 708 // Disable only if there are no other clients 709 notifyUserAction(false); 710 } 711 return true; 712 } 713 714 if (DBG) Log.d (TAG, "STATE_OFF: Already disabled"); 715 return false; 716 } 717 718 /** 719 * Special Applications who want to only turn on Bluetooth Low Energy (BLE) would 720 * EnableBLE, EnableBLE brings-up Bluetooth so that application can access 721 * only LE related feature (Bluetooth GATT layers interfaces using the respective class) 722 * EnableBLE in turn registers the existance of a special App which wants to 723 * turn on Bluetooth Low enrgy part without making it visible at the settings UI 724 * as Bluetooth ON. 725 * <p>Invoking EnableBLE when Bluetooth is already in ON state, would just registers 726 * the existance of special Application and doesn't do anything to current BT state. 727 * when user turn OFF Bluetooth from UI, if there is an existance of special app, Bluetooth 728 * would stay in BLE_ON state so that LE features are still acessible to the special 729 * Applications. 730 * 731 * <p>This is an asynchronous call: it will return immediately, and 732 * clients should listen for {@link #ACTION_BLE_STATE_CHANGED} 733 * to be notified of subsequent adapter state changes. If this call returns 734 * true, then the adapter state will immediately transition from {@link 735 * #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, and some time 736 * later transition to either {@link #STATE_OFF} or {@link 737 * #STATE_BLE_ON}. If this call returns false then there was an 738 * immediate problem that will prevent the adapter from being turned on - 739 * such as Airplane mode, or the adapter is already turned on. 740 * (@link #ACTION_BLE_STATE_CHANGED) returns the Bluetooth Adapter's various 741 * states, It includes all the classic Bluetooth Adapter states along with 742 * internal BLE only states 743 * 744 * @return true to indicate Bluetooth LE start-up has begun, or false on 745 * immediate error 746 * @hide 747 */ 748 @SystemApi enableBLE()749 public boolean enableBLE() { 750 if (!isBleScanAlwaysAvailable()) return false; 751 752 if (isLeEnabled() == true) { 753 if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!"); 754 try { 755 mManagerService.updateBleAppCount(mToken, true); 756 } catch (RemoteException e) { 757 Log.e(TAG, "", e); 758 } 759 return true; 760 } 761 762 try { 763 if (DBG) Log.d(TAG, "Calling enableBLE"); 764 mManagerService.updateBleAppCount(mToken, true); 765 return mManagerService.enable(); 766 } catch (RemoteException e) { 767 Log.e(TAG, "", e); 768 } 769 770 return false; 771 } 772 773 /** 774 * Get the current state of the local Bluetooth adapter. 775 * <p>Possible return values are 776 * {@link #STATE_OFF}, 777 * {@link #STATE_TURNING_ON}, 778 * {@link #STATE_ON}, 779 * {@link #STATE_TURNING_OFF}. 780 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 781 * 782 * @return current state of Bluetooth adapter 783 */ 784 @RequiresPermission(Manifest.permission.BLUETOOTH) 785 @AdapterState getState()786 public int getState() { 787 try { 788 synchronized(mManagerCallback) { 789 if (mService != null) 790 { 791 int state= mService.getState(); 792 if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state); 793 //consider all internal states as OFF 794 if (state == BluetoothAdapter.STATE_BLE_ON 795 || state == BluetoothAdapter.STATE_BLE_TURNING_ON 796 || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { 797 if (VDBG) Log.d(TAG, "Consider internal state as OFF"); 798 state = BluetoothAdapter.STATE_OFF; 799 } 800 return state; 801 } 802 // TODO(BT) there might be a small gap during STATE_TURNING_ON that 803 // mService is null, handle that case 804 } 805 } catch (RemoteException e) {Log.e(TAG, "", e);} 806 return STATE_OFF; 807 } 808 809 /** 810 * Get the current state of the local Bluetooth adapter 811 * <p>This returns current internal state of Adapter including LE ON/OFF 812 * 813 * <p>Possible return values are 814 * {@link #STATE_OFF}, 815 * {@link #STATE_BLE_TURNING_ON}, 816 * {@link #STATE_BLE_ON}, 817 * {@link #STATE_TURNING_ON}, 818 * {@link #STATE_ON}, 819 * {@link #STATE_TURNING_OFF}, 820 * {@link #STATE_BLE_TURNING_OFF}. 821 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 822 * 823 * @return current state of Bluetooth adapter 824 * @hide 825 */ 826 @RequiresPermission(Manifest.permission.BLUETOOTH) 827 @AdapterState getLeState()828 public int getLeState() { 829 try { 830 synchronized(mManagerCallback) { 831 if (mService != null) 832 { 833 int state= mService.getState(); 834 if (VDBG) Log.d(TAG,"getLeState() returning " + state); 835 return state; 836 } 837 } 838 } catch (RemoteException e) { 839 Log.e(TAG, "", e); 840 } 841 return BluetoothAdapter.STATE_OFF; 842 } 843 getLeAccess()844 boolean getLeAccess() { 845 if(getLeState() == STATE_ON) 846 return true; 847 848 else if (getLeState() == STATE_BLE_ON) 849 return true; // TODO: FILTER SYSTEM APPS HERE <-- 850 851 return false; 852 } 853 854 /** 855 * Turn on the local Bluetooth adapter—do not use without explicit 856 * user action to turn on Bluetooth. 857 * <p>This powers on the underlying Bluetooth hardware, and starts all 858 * Bluetooth system services. 859 * <p class="caution"><strong>Bluetooth should never be enabled without 860 * direct user consent</strong>. If you want to turn on Bluetooth in order 861 * to create a wireless connection, you should use the {@link 862 * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests 863 * user permission to turn on Bluetooth. The {@link #enable()} method is 864 * provided only for applications that include a user interface for changing 865 * system settings, such as a "power manager" app.</p> 866 * <p>This is an asynchronous call: it will return immediately, and 867 * clients should listen for {@link #ACTION_STATE_CHANGED} 868 * to be notified of subsequent adapter state changes. If this call returns 869 * true, then the adapter state will immediately transition from {@link 870 * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time 871 * later transition to either {@link #STATE_OFF} or {@link 872 * #STATE_ON}. If this call returns false then there was an 873 * immediate problem that will prevent the adapter from being turned on - 874 * such as Airplane mode, or the adapter is already turned on. 875 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} 876 * permission 877 * 878 * @return true to indicate adapter startup has begun, or false on 879 * immediate error 880 */ 881 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) enable()882 public boolean enable() { 883 int state = STATE_OFF; 884 if (isEnabled() == true){ 885 if (DBG) Log.d(TAG, "enable(): BT is already enabled..!"); 886 return true; 887 } 888 //Use service interface to get the exact state 889 if (mService != null) { 890 try { 891 state = mService.getState(); 892 } catch (RemoteException e) {Log.e(TAG, "", e);} 893 } 894 895 if (state == BluetoothAdapter.STATE_BLE_ON) { 896 Log.e(TAG, "BT is in BLE_ON State"); 897 notifyUserAction(true); 898 return true; 899 } 900 try { 901 return mManagerService.enable(); 902 } catch (RemoteException e) {Log.e(TAG, "", e);} 903 return false; 904 } 905 906 /** 907 * Turn off the local Bluetooth adapter—do not use without explicit 908 * user action to turn off Bluetooth. 909 * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth 910 * system services, and powers down the underlying Bluetooth hardware. 911 * <p class="caution"><strong>Bluetooth should never be disabled without 912 * direct user consent</strong>. The {@link #disable()} method is 913 * provided only for applications that include a user interface for changing 914 * system settings, such as a "power manager" app.</p> 915 * <p>This is an asynchronous call: it will return immediately, and 916 * clients should listen for {@link #ACTION_STATE_CHANGED} 917 * to be notified of subsequent adapter state changes. If this call returns 918 * true, then the adapter state will immediately transition from {@link 919 * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time 920 * later transition to either {@link #STATE_OFF} or {@link 921 * #STATE_ON}. If this call returns false then there was an 922 * immediate problem that will prevent the adapter from being turned off - 923 * such as the adapter already being turned off. 924 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} 925 * permission 926 * 927 * @return true to indicate adapter shutdown has begun, or false on 928 * immediate error 929 */ 930 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) disable()931 public boolean disable() { 932 try { 933 return mManagerService.disable(true); 934 } catch (RemoteException e) {Log.e(TAG, "", e);} 935 return false; 936 } 937 938 /** 939 * Turn off the local Bluetooth adapter and don't persist the setting. 940 * 941 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} 942 * permission 943 * 944 * @return true to indicate adapter shutdown has begun, or false on 945 * immediate error 946 * @hide 947 */ disable(boolean persist)948 public boolean disable(boolean persist) { 949 950 try { 951 return mManagerService.disable(persist); 952 } catch (RemoteException e) {Log.e(TAG, "", e);} 953 return false; 954 } 955 956 /** 957 * Returns the hardware address of the local Bluetooth adapter. 958 * <p>For example, "00:11:22:AA:BB:CC". 959 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 960 * 961 * @return Bluetooth hardware address as string 962 */ 963 @RequiresPermission(Manifest.permission.BLUETOOTH) getAddress()964 public String getAddress() { 965 try { 966 return mManagerService.getAddress(); 967 } catch (RemoteException e) {Log.e(TAG, "", e);} 968 return null; 969 } 970 971 /** 972 * Get the friendly Bluetooth name of the local Bluetooth adapter. 973 * <p>This name is visible to remote Bluetooth devices. 974 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 975 * 976 * @return the Bluetooth name, or null on error 977 */ getName()978 public String getName() { 979 try { 980 return mManagerService.getName(); 981 } catch (RemoteException e) {Log.e(TAG, "", e);} 982 return null; 983 } 984 985 /** 986 * enable or disable Bluetooth HCI snoop log. 987 * 988 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} 989 * permission 990 * 991 * @return true to indicate configure HCI log successfully, or false on 992 * immediate error 993 * @hide 994 */ configHciSnoopLog(boolean enable)995 public boolean configHciSnoopLog(boolean enable) { 996 try { 997 synchronized(mManagerCallback) { 998 if (mService != null) return mService.configHciSnoopLog(enable); 999 } 1000 } catch (RemoteException e) {Log.e(TAG, "", e);} 1001 return false; 1002 } 1003 1004 /** 1005 * Factory reset bluetooth settings. 1006 * 1007 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} 1008 * permission 1009 * 1010 * @return true to indicate that the config file was successfully cleared 1011 * 1012 * @hide 1013 */ factoryReset()1014 public boolean factoryReset() { 1015 try { 1016 if (mService != null) { 1017 return mService.factoryReset(); 1018 } 1019 } catch (RemoteException e) {Log.e(TAG, "", e);} 1020 return false; 1021 } 1022 1023 /** 1024 * Get the UUIDs supported by the local Bluetooth adapter. 1025 * 1026 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1027 * 1028 * @return the UUIDs supported by the local Bluetooth Adapter. 1029 * @hide 1030 */ getUuids()1031 public ParcelUuid[] getUuids() { 1032 if (getState() != STATE_ON) return null; 1033 try { 1034 synchronized(mManagerCallback) { 1035 if (mService != null) return mService.getUuids(); 1036 } 1037 } catch (RemoteException e) {Log.e(TAG, "", e);} 1038 return null; 1039 } 1040 1041 /** 1042 * Set the friendly Bluetooth name of the local Bluetooth adapter. 1043 * <p>This name is visible to remote Bluetooth devices. 1044 * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8 1045 * encoding, although many remote devices can only display the first 1046 * 40 characters, and some may be limited to just 20. 1047 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1048 * will return false. After turning on Bluetooth, 1049 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1050 * to get the updated value. 1051 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 1052 * 1053 * @param name a valid Bluetooth name 1054 * @return true if the name was set, false otherwise 1055 */ 1056 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) setName(String name)1057 public boolean setName(String name) { 1058 if (getState() != STATE_ON) return false; 1059 try { 1060 synchronized(mManagerCallback) { 1061 if (mService != null) return mService.setName(name); 1062 } 1063 } catch (RemoteException e) {Log.e(TAG, "", e);} 1064 return false; 1065 } 1066 1067 /** 1068 * Get the current Bluetooth scan mode of the local Bluetooth adapter. 1069 * <p>The Bluetooth scan mode determines if the local adapter is 1070 * connectable and/or discoverable from remote Bluetooth devices. 1071 * <p>Possible values are: 1072 * {@link #SCAN_MODE_NONE}, 1073 * {@link #SCAN_MODE_CONNECTABLE}, 1074 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. 1075 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1076 * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth, 1077 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1078 * to get the updated value. 1079 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1080 * 1081 * @return scan mode 1082 */ 1083 @RequiresPermission(Manifest.permission.BLUETOOTH) 1084 @ScanMode getScanMode()1085 public int getScanMode() { 1086 if (getState() != STATE_ON) return SCAN_MODE_NONE; 1087 try { 1088 synchronized(mManagerCallback) { 1089 if (mService != null) return mService.getScanMode(); 1090 } 1091 } catch (RemoteException e) {Log.e(TAG, "", e);} 1092 return SCAN_MODE_NONE; 1093 } 1094 1095 /** 1096 * Set the Bluetooth scan mode of the local Bluetooth adapter. 1097 * <p>The Bluetooth scan mode determines if the local adapter is 1098 * connectable and/or discoverable from remote Bluetooth devices. 1099 * <p>For privacy reasons, discoverable mode is automatically turned off 1100 * after <code>duration</code> seconds. For example, 120 seconds should be 1101 * enough for a remote device to initiate and complete its discovery 1102 * process. 1103 * <p>Valid scan mode values are: 1104 * {@link #SCAN_MODE_NONE}, 1105 * {@link #SCAN_MODE_CONNECTABLE}, 1106 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. 1107 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1108 * will return false. After turning on Bluetooth, 1109 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1110 * to get the updated value. 1111 * <p>Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} 1112 * <p>Applications cannot set the scan mode. They should use 1113 * <code>startActivityForResult( 1114 * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) 1115 * </code>instead. 1116 * 1117 * @param mode valid scan mode 1118 * @param duration time in seconds to apply scan mode, only used for 1119 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE} 1120 * @return true if the scan mode was set, false otherwise 1121 * @hide 1122 */ setScanMode(@canMode int mode, int duration)1123 public boolean setScanMode(@ScanMode int mode, int duration) { 1124 if (getState() != STATE_ON) return false; 1125 try { 1126 synchronized(mManagerCallback) { 1127 if (mService != null) return mService.setScanMode(mode, duration); 1128 } 1129 } catch (RemoteException e) {Log.e(TAG, "", e);} 1130 return false; 1131 } 1132 1133 /** @hide */ setScanMode(int mode)1134 public boolean setScanMode(int mode) { 1135 if (getState() != STATE_ON) return false; 1136 /* getDiscoverableTimeout() to use the latest from NV than use 0 */ 1137 return setScanMode(mode, getDiscoverableTimeout()); 1138 } 1139 1140 /** @hide */ getDiscoverableTimeout()1141 public int getDiscoverableTimeout() { 1142 if (getState() != STATE_ON) return -1; 1143 try { 1144 synchronized(mManagerCallback) { 1145 if (mService != null) return mService.getDiscoverableTimeout(); 1146 } 1147 } catch (RemoteException e) {Log.e(TAG, "", e);} 1148 return -1; 1149 } 1150 1151 /** @hide */ setDiscoverableTimeout(int timeout)1152 public void setDiscoverableTimeout(int timeout) { 1153 if (getState() != STATE_ON) return; 1154 try { 1155 synchronized(mManagerCallback) { 1156 if (mService != null) mService.setDiscoverableTimeout(timeout); 1157 } 1158 } catch (RemoteException e) {Log.e(TAG, "", e);} 1159 } 1160 1161 /** 1162 * Start the remote device discovery process. 1163 * <p>The discovery process usually involves an inquiry scan of about 12 1164 * seconds, followed by a page scan of each new device to retrieve its 1165 * Bluetooth name. 1166 * <p>This is an asynchronous call, it will return immediately. Register 1167 * for {@link #ACTION_DISCOVERY_STARTED} and {@link 1168 * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the 1169 * discovery starts and completes. Register for {@link 1170 * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices 1171 * are found. 1172 * <p>Device discovery is a heavyweight procedure. New connections to 1173 * remote Bluetooth devices should not be attempted while discovery is in 1174 * progress, and existing connections will experience limited bandwidth 1175 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing 1176 * discovery. Discovery is not managed by the Activity, 1177 * but is run as a system service, so an application should always call 1178 * {@link BluetoothAdapter#cancelDiscovery()} even if it 1179 * did not directly request a discovery, just to be sure. 1180 * <p>Device discovery will only find remote devices that are currently 1181 * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are 1182 * not discoverable by default, and need to be entered into a special mode. 1183 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1184 * will return false. After turning on Bluetooth, 1185 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1186 * to get the updated value. 1187 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 1188 * 1189 * @return true on success, false on error 1190 */ 1191 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) startDiscovery()1192 public boolean startDiscovery() { 1193 if (getState() != STATE_ON) return false; 1194 try { 1195 synchronized(mManagerCallback) { 1196 if (mService != null) return mService.startDiscovery(); 1197 } 1198 } catch (RemoteException e) {Log.e(TAG, "", e);} 1199 return false; 1200 } 1201 1202 /** 1203 * Cancel the current device discovery process. 1204 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 1205 * <p>Because discovery is a heavyweight procedure for the Bluetooth 1206 * adapter, this method should always be called before attempting to connect 1207 * to a remote device with {@link 1208 * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by 1209 * the Activity, but is run as a system service, so an application should 1210 * always call cancel discovery even if it did not directly request a 1211 * discovery, just to be sure. 1212 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1213 * will return false. After turning on Bluetooth, 1214 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1215 * to get the updated value. 1216 * 1217 * @return true on success, false on error 1218 */ 1219 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) cancelDiscovery()1220 public boolean cancelDiscovery() { 1221 if (getState() != STATE_ON) return false; 1222 try { 1223 synchronized(mManagerCallback) { 1224 if (mService != null) return mService.cancelDiscovery(); 1225 } 1226 } catch (RemoteException e) {Log.e(TAG, "", e);} 1227 return false; 1228 } 1229 1230 /** 1231 * Return true if the local Bluetooth adapter is currently in the device 1232 * discovery process. 1233 * <p>Device discovery is a heavyweight procedure. New connections to 1234 * remote Bluetooth devices should not be attempted while discovery is in 1235 * progress, and existing connections will experience limited bandwidth 1236 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing 1237 * discovery. 1238 * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED} 1239 * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery 1240 * starts or completes. 1241 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1242 * will return false. After turning on Bluetooth, 1243 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1244 * to get the updated value. 1245 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 1246 * 1247 * @return true if discovering 1248 */ 1249 @RequiresPermission(Manifest.permission.BLUETOOTH) isDiscovering()1250 public boolean isDiscovering() { 1251 if (getState() != STATE_ON) return false; 1252 try { 1253 synchronized(mManagerCallback) { 1254 if (mService != null ) return mService.isDiscovering(); 1255 } 1256 } catch (RemoteException e) {Log.e(TAG, "", e);} 1257 return false; 1258 } 1259 1260 /** 1261 * Return true if the multi advertisement is supported by the chipset 1262 * 1263 * @return true if Multiple Advertisement feature is supported 1264 */ isMultipleAdvertisementSupported()1265 public boolean isMultipleAdvertisementSupported() { 1266 if (getState() != STATE_ON) return false; 1267 try { 1268 return mService.isMultiAdvertisementSupported(); 1269 } catch (RemoteException e) { 1270 Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e); 1271 } 1272 return false; 1273 } 1274 1275 /** 1276 * Returns {@code true} if BLE scan is always available, {@code false} otherwise. <p> 1277 * 1278 * If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan} and 1279 * fetch scan results even when Bluetooth is turned off.<p> 1280 * 1281 * To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}. 1282 * 1283 * @hide 1284 */ 1285 @SystemApi isBleScanAlwaysAvailable()1286 public boolean isBleScanAlwaysAvailable() { 1287 try { 1288 return mManagerService.isBleScanAlwaysAvailable(); 1289 } catch (RemoteException e) { 1290 Log.e(TAG, "remote expection when calling isBleScanAlwaysAvailable", e); 1291 return false; 1292 } 1293 } 1294 1295 /** 1296 * Returns whether peripheral mode is supported. 1297 * 1298 * @hide 1299 */ isPeripheralModeSupported()1300 public boolean isPeripheralModeSupported() { 1301 if (getState() != STATE_ON) return false; 1302 try { 1303 return mService.isPeripheralModeSupported(); 1304 } catch (RemoteException e) { 1305 Log.e(TAG, "failed to get peripheral mode capability: ", e); 1306 } 1307 return false; 1308 } 1309 1310 /** 1311 * Return true if offloaded filters are supported 1312 * 1313 * @return true if chipset supports on-chip filtering 1314 */ isOffloadedFilteringSupported()1315 public boolean isOffloadedFilteringSupported() { 1316 if (!getLeAccess()) return false; 1317 try { 1318 return mService.isOffloadedFilteringSupported(); 1319 } catch (RemoteException e) { 1320 Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e); 1321 } 1322 return false; 1323 } 1324 1325 /** 1326 * Return true if offloaded scan batching is supported 1327 * 1328 * @return true if chipset supports on-chip scan batching 1329 */ isOffloadedScanBatchingSupported()1330 public boolean isOffloadedScanBatchingSupported() { 1331 if (!getLeAccess()) return false; 1332 try { 1333 return mService.isOffloadedScanBatchingSupported(); 1334 } catch (RemoteException e) { 1335 Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e); 1336 } 1337 return false; 1338 } 1339 1340 /** 1341 * Return true if hardware has entries available for matching beacons 1342 * 1343 * @return true if there are hw entries available for matching beacons 1344 * @hide 1345 */ isHardwareTrackingFiltersAvailable()1346 public boolean isHardwareTrackingFiltersAvailable() { 1347 if (!getLeAccess()) return false; 1348 try { 1349 IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); 1350 if (iGatt == null) { 1351 // BLE is not supported 1352 return false; 1353 } 1354 return (iGatt.numHwTrackFiltersAvailable() != 0); 1355 } catch (RemoteException e) { 1356 Log.e(TAG, "", e); 1357 } 1358 return false; 1359 } 1360 1361 /** 1362 * Return the record of {@link BluetoothActivityEnergyInfo} object that 1363 * has the activity and energy info. This can be used to ascertain what 1364 * the controller has been up to, since the last sample. 1365 * @param updateType Type of info, cached vs refreshed. 1366 * 1367 * @return a record with {@link BluetoothActivityEnergyInfo} or null if 1368 * report is unavailable or unsupported 1369 * @hide 1370 */ getControllerActivityEnergyInfo(int updateType)1371 public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) { 1372 if (getState() != STATE_ON) return null; 1373 try { 1374 BluetoothActivityEnergyInfo record; 1375 if (!mService.isActivityAndEnergyReportingSupported()) { 1376 return null; 1377 } 1378 synchronized(this) { 1379 if (updateType == ACTIVITY_ENERGY_INFO_REFRESHED) { 1380 mService.getActivityEnergyInfoFromController(); 1381 wait(CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS); 1382 } 1383 record = mService.reportActivityInfo(); 1384 if (record.isValid()) { 1385 return record; 1386 } else { 1387 return null; 1388 } 1389 } 1390 } catch (InterruptedException e) { 1391 Log.e(TAG, "getControllerActivityEnergyInfoCallback wait interrupted: " + e); 1392 } catch (RemoteException e) { 1393 Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e); 1394 } 1395 return null; 1396 } 1397 1398 /** 1399 * Return the set of {@link BluetoothDevice} objects that are bonded 1400 * (paired) to the local adapter. 1401 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 1402 * will return an empty set. After turning on Bluetooth, 1403 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 1404 * to get the updated value. 1405 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 1406 * 1407 * @return unmodifiable set of {@link BluetoothDevice}, or null on error 1408 */ 1409 @RequiresPermission(Manifest.permission.BLUETOOTH) getBondedDevices()1410 public Set<BluetoothDevice> getBondedDevices() { 1411 if (getState() != STATE_ON) { 1412 return toDeviceSet(new BluetoothDevice[0]); 1413 } 1414 try { 1415 synchronized(mManagerCallback) { 1416 if (mService != null) return toDeviceSet(mService.getBondedDevices()); 1417 } 1418 return toDeviceSet(new BluetoothDevice[0]); 1419 } catch (RemoteException e) {Log.e(TAG, "", e);} 1420 return null; 1421 } 1422 1423 /** 1424 * Get the current connection state of the local Bluetooth adapter. 1425 * This can be used to check whether the local Bluetooth adapter is connected 1426 * to any profile of any other remote Bluetooth Device. 1427 * 1428 * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED} 1429 * intent to get the connection state of the adapter. 1430 * 1431 * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED}, 1432 * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED} 1433 * 1434 * @hide 1435 */ getConnectionState()1436 public int getConnectionState() { 1437 if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED; 1438 try { 1439 synchronized(mManagerCallback) { 1440 if (mService != null) return mService.getAdapterConnectionState(); 1441 } 1442 } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);} 1443 return BluetoothAdapter.STATE_DISCONNECTED; 1444 } 1445 1446 /** 1447 * Get the current connection state of a profile. 1448 * This function can be used to check whether the local Bluetooth adapter 1449 * is connected to any remote device for a specific profile. 1450 * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, 1451 * {@link BluetoothProfile#A2DP}. 1452 * 1453 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 1454 * 1455 * <p> Return value can be one of 1456 * {@link BluetoothProfile#STATE_DISCONNECTED}, 1457 * {@link BluetoothProfile#STATE_CONNECTING}, 1458 * {@link BluetoothProfile#STATE_CONNECTED}, 1459 * {@link BluetoothProfile#STATE_DISCONNECTING} 1460 */ 1461 @RequiresPermission(Manifest.permission.BLUETOOTH) getProfileConnectionState(int profile)1462 public int getProfileConnectionState(int profile) { 1463 if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED; 1464 try { 1465 synchronized(mManagerCallback) { 1466 if (mService != null) return mService.getProfileConnectionState(profile); 1467 } 1468 } catch (RemoteException e) { 1469 Log.e(TAG, "getProfileConnectionState:", e); 1470 } 1471 return BluetoothProfile.STATE_DISCONNECTED; 1472 } 1473 1474 /** 1475 * Create a listening, secure RFCOMM Bluetooth socket. 1476 * <p>A remote device connecting to this socket will be authenticated and 1477 * communication on this socket will be encrypted. 1478 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 1479 * connections from a listening {@link BluetoothServerSocket}. 1480 * <p>Valid RFCOMM channels are in range 1 to 30. 1481 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 1482 * @param channel RFCOMM channel to listen on 1483 * @return a listening RFCOMM BluetoothServerSocket 1484 * @throws IOException on error, for example Bluetooth not available, or 1485 * insufficient permissions, or channel in use. 1486 * @hide 1487 */ listenUsingRfcommOn(int channel)1488 public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException { 1489 return listenUsingRfcommOn(channel, false, false); 1490 } 1491 1492 /** 1493 * Create a listening, secure RFCOMM Bluetooth socket. 1494 * <p>A remote device connecting to this socket will be authenticated and 1495 * communication on this socket will be encrypted. 1496 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 1497 * connections from a listening {@link BluetoothServerSocket}. 1498 * <p>Valid RFCOMM channels are in range 1 to 30. 1499 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 1500 * <p>To auto assign a channel without creating a SDP record use 1501 * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number. 1502 * @param channel RFCOMM channel to listen on 1503 * @param mitm enforce man-in-the-middle protection for authentication. 1504 * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 connections. 1505 * @return a listening RFCOMM BluetoothServerSocket 1506 * @throws IOException on error, for example Bluetooth not available, or 1507 * insufficient permissions, or channel in use. 1508 * @hide 1509 */ listenUsingRfcommOn(int channel, boolean mitm, boolean min16DigitPin)1510 public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm, 1511 boolean min16DigitPin) 1512 throws IOException { 1513 BluetoothServerSocket socket = new BluetoothServerSocket( 1514 BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm, min16DigitPin); 1515 int errno = socket.mSocket.bindListen(); 1516 if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 1517 socket.setChannel(socket.mSocket.getPort()); 1518 } 1519 if (errno != 0) { 1520 //TODO(BT): Throw the same exception error code 1521 // that the previous code was using. 1522 //socket.mSocket.throwErrnoNative(errno); 1523 throw new IOException("Error: " + errno); 1524 } 1525 return socket; 1526 } 1527 1528 /** 1529 * Create a listening, secure RFCOMM Bluetooth socket with Service Record. 1530 * <p>A remote device connecting to this socket will be authenticated and 1531 * communication on this socket will be encrypted. 1532 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 1533 * connections from a listening {@link BluetoothServerSocket}. 1534 * <p>The system will assign an unused RFCOMM channel to listen on. 1535 * <p>The system will also register a Service Discovery 1536 * Protocol (SDP) record with the local SDP server containing the specified 1537 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices 1538 * can use the same UUID to query our SDP server and discover which channel 1539 * to connect to. This SDP record will be removed when this socket is 1540 * closed, or if this application closes unexpectedly. 1541 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to 1542 * connect to this socket from another device using the same {@link UUID}. 1543 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1544 * @param name service name for SDP record 1545 * @param uuid uuid for SDP record 1546 * @return a listening RFCOMM BluetoothServerSocket 1547 * @throws IOException on error, for example Bluetooth not available, or 1548 * insufficient permissions, or channel in use. 1549 */ 1550 @RequiresPermission(Manifest.permission.BLUETOOTH) listenUsingRfcommWithServiceRecord(String name, UUID uuid)1551 public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) 1552 throws IOException { 1553 return createNewRfcommSocketAndRecord(name, uuid, true, true); 1554 } 1555 1556 /** 1557 * Create a listening, insecure RFCOMM Bluetooth socket with Service Record. 1558 * <p>The link key is not required to be authenticated, i.e the communication may be 1559 * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices, 1560 * the link will be encrypted, as encryption is mandartory. 1561 * For legacy devices (pre Bluetooth 2.1 devices) the link will not 1562 * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an 1563 * encrypted and authenticated communication channel is desired. 1564 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 1565 * connections from a listening {@link BluetoothServerSocket}. 1566 * <p>The system will assign an unused RFCOMM channel to listen on. 1567 * <p>The system will also register a Service Discovery 1568 * Protocol (SDP) record with the local SDP server containing the specified 1569 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices 1570 * can use the same UUID to query our SDP server and discover which channel 1571 * to connect to. This SDP record will be removed when this socket is 1572 * closed, or if this application closes unexpectedly. 1573 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to 1574 * connect to this socket from another device using the same {@link UUID}. 1575 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1576 * @param name service name for SDP record 1577 * @param uuid uuid for SDP record 1578 * @return a listening RFCOMM BluetoothServerSocket 1579 * @throws IOException on error, for example Bluetooth not available, or 1580 * insufficient permissions, or channel in use. 1581 */ 1582 @RequiresPermission(Manifest.permission.BLUETOOTH) listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)1583 public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid) 1584 throws IOException { 1585 return createNewRfcommSocketAndRecord(name, uuid, false, false); 1586 } 1587 1588 /** 1589 * Create a listening, encrypted, 1590 * RFCOMM Bluetooth socket with Service Record. 1591 * <p>The link will be encrypted, but the link key is not required to be authenticated 1592 * i.e the communication is vulnerable to Man In the Middle attacks. Use 1593 * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key. 1594 * <p> Use this socket if authentication of link key is not possible. 1595 * For example, for Bluetooth 2.1 devices, if any of the devices does not have 1596 * an input and output capability or just has the ability to display a numeric key, 1597 * a secure socket connection is not possible and this socket can be used. 1598 * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required. 1599 * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory. 1600 * For more details, refer to the Security Model section 5.2 (vol 3) of 1601 * Bluetooth Core Specification version 2.1 + EDR. 1602 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 1603 * connections from a listening {@link BluetoothServerSocket}. 1604 * <p>The system will assign an unused RFCOMM channel to listen on. 1605 * <p>The system will also register a Service Discovery 1606 * Protocol (SDP) record with the local SDP server containing the specified 1607 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices 1608 * can use the same UUID to query our SDP server and discover which channel 1609 * to connect to. This SDP record will be removed when this socket is 1610 * closed, or if this application closes unexpectedly. 1611 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to 1612 * connect to this socket from another device using the same {@link UUID}. 1613 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1614 * @param name service name for SDP record 1615 * @param uuid uuid for SDP record 1616 * @return a listening RFCOMM BluetoothServerSocket 1617 * @throws IOException on error, for example Bluetooth not available, or 1618 * insufficient permissions, or channel in use. 1619 * @hide 1620 */ listenUsingEncryptedRfcommWithServiceRecord( String name, UUID uuid)1621 public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord( 1622 String name, UUID uuid) throws IOException { 1623 return createNewRfcommSocketAndRecord(name, uuid, false, true); 1624 } 1625 1626 createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt)1627 private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, 1628 boolean auth, boolean encrypt) throws IOException { 1629 BluetoothServerSocket socket; 1630 socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, 1631 encrypt, new ParcelUuid(uuid)); 1632 socket.setServiceName(name); 1633 int errno = socket.mSocket.bindListen(); 1634 if (errno != 0) { 1635 //TODO(BT): Throw the same exception error code 1636 // that the previous code was using. 1637 //socket.mSocket.throwErrnoNative(errno); 1638 throw new IOException("Error: " + errno); 1639 } 1640 return socket; 1641 } 1642 1643 /** 1644 * Construct an unencrypted, unauthenticated, RFCOMM server socket. 1645 * Call #accept to retrieve connections to this socket. 1646 * @return An RFCOMM BluetoothServerSocket 1647 * @throws IOException On error, for example Bluetooth not available, or 1648 * insufficient permissions. 1649 * @hide 1650 */ listenUsingInsecureRfcommOn(int port)1651 public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { 1652 BluetoothServerSocket socket = new BluetoothServerSocket( 1653 BluetoothSocket.TYPE_RFCOMM, false, false, port); 1654 int errno = socket.mSocket.bindListen(); 1655 if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 1656 socket.setChannel(socket.mSocket.getPort()); 1657 } 1658 if (errno != 0) { 1659 //TODO(BT): Throw the same exception error code 1660 // that the previous code was using. 1661 //socket.mSocket.throwErrnoNative(errno); 1662 throw new IOException("Error: " + errno); 1663 } 1664 return socket; 1665 } 1666 1667 /** 1668 * Construct an encrypted, RFCOMM server socket. 1669 * Call #accept to retrieve connections to this socket. 1670 * @return An RFCOMM BluetoothServerSocket 1671 * @throws IOException On error, for example Bluetooth not available, or 1672 * insufficient permissions. 1673 * @hide 1674 */ listenUsingEncryptedRfcommOn(int port)1675 public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) 1676 throws IOException { 1677 BluetoothServerSocket socket = new BluetoothServerSocket( 1678 BluetoothSocket.TYPE_RFCOMM, false, true, port); 1679 int errno = socket.mSocket.bindListen(); 1680 if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 1681 socket.setChannel(socket.mSocket.getPort()); 1682 } 1683 if (errno < 0) { 1684 //TODO(BT): Throw the same exception error code 1685 // that the previous code was using. 1686 //socket.mSocket.throwErrnoNative(errno); 1687 throw new IOException("Error: " + errno); 1688 } 1689 return socket; 1690 } 1691 1692 /** 1693 * Construct a SCO server socket. 1694 * Call #accept to retrieve connections to this socket. 1695 * @return A SCO BluetoothServerSocket 1696 * @throws IOException On error, for example Bluetooth not available, or 1697 * insufficient permissions. 1698 * @hide 1699 */ listenUsingScoOn()1700 public static BluetoothServerSocket listenUsingScoOn() throws IOException { 1701 BluetoothServerSocket socket = new BluetoothServerSocket( 1702 BluetoothSocket.TYPE_SCO, false, false, -1); 1703 int errno = socket.mSocket.bindListen(); 1704 if (errno < 0) { 1705 //TODO(BT): Throw the same exception error code 1706 // that the previous code was using. 1707 //socket.mSocket.throwErrnoNative(errno); 1708 } 1709 return socket; 1710 } 1711 1712 /** 1713 * Construct an encrypted, authenticated, L2CAP server socket. 1714 * Call #accept to retrieve connections to this socket. 1715 * <p>To auto assign a port without creating a SDP record use 1716 * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. 1717 * @param port the PSM to listen on 1718 * @param mitm enforce man-in-the-middle protection for authentication. 1719 * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 connections. 1720 * @return An L2CAP BluetoothServerSocket 1721 * @throws IOException On error, for example Bluetooth not available, or 1722 * insufficient permissions. 1723 * @hide 1724 */ listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)1725 public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin) 1726 throws IOException { 1727 BluetoothServerSocket socket = new BluetoothServerSocket( 1728 BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, min16DigitPin); 1729 int errno = socket.mSocket.bindListen(); 1730 if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) { 1731 socket.setChannel(socket.mSocket.getPort()); 1732 } 1733 if (errno != 0) { 1734 //TODO(BT): Throw the same exception error code 1735 // that the previous code was using. 1736 //socket.mSocket.throwErrnoNative(errno); 1737 throw new IOException("Error: " + errno); 1738 } 1739 return socket; 1740 } 1741 1742 /** 1743 * Construct an encrypted, authenticated, L2CAP server socket. 1744 * Call #accept to retrieve connections to this socket. 1745 * <p>To auto assign a port without creating a SDP record use 1746 * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number. 1747 * @param port the PSM to listen on 1748 * @return An L2CAP BluetoothServerSocket 1749 * @throws IOException On error, for example Bluetooth not available, or 1750 * insufficient permissions. 1751 * @hide 1752 */ listenUsingL2capOn(int port)1753 public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException { 1754 return listenUsingL2capOn(port, false, false); 1755 } 1756 1757 /** 1758 * Read the local Out of Band Pairing Data 1759 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1760 * 1761 * @return Pair<byte[], byte[]> of Hash and Randomizer 1762 * 1763 * @hide 1764 */ readOutOfBandData()1765 public Pair<byte[], byte[]> readOutOfBandData() { 1766 if (getState() != STATE_ON) return null; 1767 //TODO(BT 1768 /* 1769 try { 1770 byte[] hash; 1771 byte[] randomizer; 1772 1773 byte[] ret = mService.readOutOfBandData(); 1774 1775 if (ret == null || ret.length != 32) return null; 1776 1777 hash = Arrays.copyOfRange(ret, 0, 16); 1778 randomizer = Arrays.copyOfRange(ret, 16, 32); 1779 1780 if (DBG) { 1781 Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) + 1782 ":" + Arrays.toString(randomizer)); 1783 } 1784 return new Pair<byte[], byte[]>(hash, randomizer); 1785 1786 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 1787 return null; 1788 } 1789 1790 /** 1791 * Get the profile proxy object associated with the profile. 1792 * 1793 * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, 1794 * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or 1795 * {@link BluetoothProfile#GATT_SERVER}. Clients must implement 1796 * {@link BluetoothProfile.ServiceListener} to get notified of 1797 * the connection status and to get the proxy object. 1798 * 1799 * @param context Context of the application 1800 * @param listener The service Listener for connection callbacks. 1801 * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH}, 1802 * {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. 1803 * {@link BluetoothProfile#GATT} or {@link BluetoothProfile#GATT_SERVER}. 1804 * @return true on success, false on error 1805 */ getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile)1806 public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, 1807 int profile) { 1808 if (context == null || listener == null) return false; 1809 1810 if (profile == BluetoothProfile.HEADSET) { 1811 BluetoothHeadset headset = new BluetoothHeadset(context, listener); 1812 return true; 1813 } else if (profile == BluetoothProfile.A2DP) { 1814 BluetoothA2dp a2dp = new BluetoothA2dp(context, listener); 1815 return true; 1816 } else if (profile == BluetoothProfile.A2DP_SINK) { 1817 BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener); 1818 return true; 1819 } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) { 1820 BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener); 1821 return true; 1822 } else if (profile == BluetoothProfile.INPUT_DEVICE) { 1823 BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener); 1824 return true; 1825 } else if (profile == BluetoothProfile.PAN) { 1826 BluetoothPan pan = new BluetoothPan(context, listener); 1827 return true; 1828 } else if (profile == BluetoothProfile.HEALTH) { 1829 BluetoothHealth health = new BluetoothHealth(context, listener); 1830 return true; 1831 } else if (profile == BluetoothProfile.MAP) { 1832 BluetoothMap map = new BluetoothMap(context, listener); 1833 return true; 1834 } else if (profile == BluetoothProfile.HEADSET_CLIENT) { 1835 BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener); 1836 return true; 1837 } else if (profile == BluetoothProfile.SAP) { 1838 BluetoothSap sap = new BluetoothSap(context, listener); 1839 return true; 1840 } else { 1841 return false; 1842 } 1843 } 1844 1845 /** 1846 * Close the connection of the profile proxy to the Service. 1847 * 1848 * <p> Clients should call this when they are no longer using 1849 * the proxy obtained from {@link #getProfileProxy}. 1850 * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or 1851 * {@link BluetoothProfile#A2DP} 1852 * 1853 * @param profile 1854 * @param proxy Profile proxy object 1855 */ closeProfileProxy(int profile, BluetoothProfile proxy)1856 public void closeProfileProxy(int profile, BluetoothProfile proxy) { 1857 if (proxy == null) return; 1858 1859 switch (profile) { 1860 case BluetoothProfile.HEADSET: 1861 BluetoothHeadset headset = (BluetoothHeadset)proxy; 1862 headset.close(); 1863 break; 1864 case BluetoothProfile.A2DP: 1865 BluetoothA2dp a2dp = (BluetoothA2dp)proxy; 1866 a2dp.close(); 1867 break; 1868 case BluetoothProfile.A2DP_SINK: 1869 BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink)proxy; 1870 a2dpSink.close(); 1871 break; 1872 case BluetoothProfile.AVRCP_CONTROLLER: 1873 BluetoothAvrcpController avrcp = (BluetoothAvrcpController)proxy; 1874 avrcp.close(); 1875 break; 1876 case BluetoothProfile.INPUT_DEVICE: 1877 BluetoothInputDevice iDev = (BluetoothInputDevice)proxy; 1878 iDev.close(); 1879 break; 1880 case BluetoothProfile.PAN: 1881 BluetoothPan pan = (BluetoothPan)proxy; 1882 pan.close(); 1883 break; 1884 case BluetoothProfile.HEALTH: 1885 BluetoothHealth health = (BluetoothHealth)proxy; 1886 health.close(); 1887 break; 1888 case BluetoothProfile.GATT: 1889 BluetoothGatt gatt = (BluetoothGatt)proxy; 1890 gatt.close(); 1891 break; 1892 case BluetoothProfile.GATT_SERVER: 1893 BluetoothGattServer gattServer = (BluetoothGattServer)proxy; 1894 gattServer.close(); 1895 break; 1896 case BluetoothProfile.MAP: 1897 BluetoothMap map = (BluetoothMap)proxy; 1898 map.close(); 1899 break; 1900 case BluetoothProfile.HEADSET_CLIENT: 1901 BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy; 1902 headsetClient.close(); 1903 break; 1904 case BluetoothProfile.SAP: 1905 BluetoothSap sap = (BluetoothSap)proxy; 1906 sap.close(); 1907 break; 1908 } 1909 } 1910 1911 final private IBluetoothManagerCallback mManagerCallback = 1912 new IBluetoothManagerCallback.Stub() { 1913 public void onBluetoothServiceUp(IBluetooth bluetoothService) { 1914 if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); 1915 synchronized (mManagerCallback) { 1916 mService = bluetoothService; 1917 synchronized (mProxyServiceStateCallbacks) { 1918 for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ 1919 try { 1920 if (cb != null) { 1921 cb.onBluetoothServiceUp(bluetoothService); 1922 } else { 1923 Log.d(TAG, "onBluetoothServiceUp: cb is null!!!"); 1924 } 1925 } catch (Exception e) { Log.e(TAG,"",e);} 1926 } 1927 } 1928 } 1929 } 1930 1931 public void onBluetoothServiceDown() { 1932 if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); 1933 synchronized (mManagerCallback) { 1934 mService = null; 1935 if (mLeScanClients != null) mLeScanClients.clear(); 1936 if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup(); 1937 if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup(); 1938 synchronized (mProxyServiceStateCallbacks) { 1939 for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ 1940 try { 1941 if (cb != null) { 1942 cb.onBluetoothServiceDown(); 1943 } else { 1944 Log.d(TAG, "onBluetoothServiceDown: cb is null!!!"); 1945 } 1946 } catch (Exception e) { Log.e(TAG,"",e);} 1947 } 1948 } 1949 } 1950 } 1951 1952 public void onBrEdrDown() { 1953 if (VDBG) Log.i(TAG, "on QBrEdrDown: "); 1954 } 1955 }; 1956 1957 /** 1958 * Enable the Bluetooth Adapter, but don't auto-connect devices 1959 * and don't persist state. Only for use by system applications. 1960 * @hide 1961 */ enableNoAutoConnect()1962 public boolean enableNoAutoConnect() { 1963 if (isEnabled() == true){ 1964 if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT is already enabled..!"); 1965 return true; 1966 } 1967 try { 1968 return mManagerService.enableNoAutoConnect(); 1969 } catch (RemoteException e) {Log.e(TAG, "", e);} 1970 return false; 1971 } 1972 1973 /** 1974 * Enable control of the Bluetooth Adapter for a single application. 1975 * 1976 * <p>Some applications need to use Bluetooth for short periods of time to 1977 * transfer data but don't want all the associated implications like 1978 * automatic connection to headsets etc. 1979 * 1980 * <p> Multiple applications can call this. This is reference counted and 1981 * Bluetooth disabled only when no one else is using it. There will be no UI 1982 * shown to the user while bluetooth is being enabled. Any user action will 1983 * override this call. For example, if user wants Bluetooth on and the last 1984 * user of this API wanted to disable Bluetooth, Bluetooth will not be 1985 * turned off. 1986 * 1987 * <p> This API is only meant to be used by internal applications. Third 1988 * party applications but use {@link #enable} and {@link #disable} APIs. 1989 * 1990 * <p> If this API returns true, it means the callback will be called. 1991 * The callback will be called with the current state of Bluetooth. 1992 * If the state is not what was requested, an internal error would be the 1993 * reason. If Bluetooth is already on and if this function is called to turn 1994 * it on, the api will return true and a callback will be called. 1995 * 1996 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1997 * 1998 * @param on True for on, false for off. 1999 * @param callback The callback to notify changes to the state. 2000 * @hide 2001 */ changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback)2002 public boolean changeApplicationBluetoothState(boolean on, 2003 BluetoothStateChangeCallback callback) { 2004 if (callback == null) return false; 2005 2006 //TODO(BT) 2007 /* 2008 try { 2009 return mService.changeApplicationBluetoothState(on, new 2010 StateChangeCallbackWrapper(callback), new Binder()); 2011 } catch (RemoteException e) { 2012 Log.e(TAG, "changeBluetoothState", e); 2013 }*/ 2014 return false; 2015 } 2016 2017 /** 2018 * @hide 2019 */ 2020 public interface BluetoothStateChangeCallback { onBluetoothStateChange(boolean on)2021 public void onBluetoothStateChange(boolean on); 2022 } 2023 2024 /** 2025 * @hide 2026 */ 2027 public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub { 2028 private BluetoothStateChangeCallback mCallback; 2029 StateChangeCallbackWrapper(BluetoothStateChangeCallback callback)2030 StateChangeCallbackWrapper(BluetoothStateChangeCallback 2031 callback) { 2032 mCallback = callback; 2033 } 2034 2035 @Override onBluetoothStateChange(boolean on)2036 public void onBluetoothStateChange(boolean on) { 2037 mCallback.onBluetoothStateChange(on); 2038 } 2039 } 2040 toDeviceSet(BluetoothDevice[] devices)2041 private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) { 2042 Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(Arrays.asList(devices)); 2043 return Collections.unmodifiableSet(deviceSet); 2044 } 2045 finalize()2046 protected void finalize() throws Throwable { 2047 try { 2048 mManagerService.unregisterAdapter(mManagerCallback); 2049 } catch (RemoteException e) { 2050 Log.e(TAG, "", e); 2051 } finally { 2052 super.finalize(); 2053 } 2054 } 2055 2056 2057 /** 2058 * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0" 2059 * <p>Alphabetic characters must be uppercase to be valid. 2060 * 2061 * @param address Bluetooth address as string 2062 * @return true if the address is valid, false otherwise 2063 */ checkBluetoothAddress(String address)2064 public static boolean checkBluetoothAddress(String address) { 2065 if (address == null || address.length() != ADDRESS_LENGTH) { 2066 return false; 2067 } 2068 for (int i = 0; i < ADDRESS_LENGTH; i++) { 2069 char c = address.charAt(i); 2070 switch (i % 3) { 2071 case 0: 2072 case 1: 2073 if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { 2074 // hex character, OK 2075 break; 2076 } 2077 return false; 2078 case 2: 2079 if (c == ':') { 2080 break; // OK 2081 } 2082 return false; 2083 } 2084 } 2085 return true; 2086 } 2087 getBluetoothManager()2088 /*package*/ IBluetoothManager getBluetoothManager() { 2089 return mManagerService; 2090 } 2091 2092 final private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>(); 2093 getBluetoothService(IBluetoothManagerCallback cb)2094 /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { 2095 synchronized (mProxyServiceStateCallbacks) { 2096 if (cb == null) { 2097 Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback"); 2098 } else if (!mProxyServiceStateCallbacks.contains(cb)) { 2099 mProxyServiceStateCallbacks.add(cb); 2100 } 2101 } 2102 return mService; 2103 } 2104 removeServiceStateCallback(IBluetoothManagerCallback cb)2105 /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) { 2106 synchronized (mProxyServiceStateCallbacks) { 2107 mProxyServiceStateCallbacks.remove(cb); 2108 } 2109 } 2110 2111 /** 2112 * Callback interface used to deliver LE scan results. 2113 * 2114 * @see #startLeScan(LeScanCallback) 2115 * @see #startLeScan(UUID[], LeScanCallback) 2116 */ 2117 public interface LeScanCallback { 2118 /** 2119 * Callback reporting an LE device found during a device scan initiated 2120 * by the {@link BluetoothAdapter#startLeScan} function. 2121 * 2122 * @param device Identifies the remote device 2123 * @param rssi The RSSI value for the remote device as reported by the 2124 * Bluetooth hardware. 0 if no RSSI value is available. 2125 * @param scanRecord The content of the advertisement record offered by 2126 * the remote device. 2127 */ onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)2128 public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); 2129 } 2130 2131 /** 2132 * Starts a scan for Bluetooth LE devices. 2133 * 2134 * <p>Results of the scan are reported using the 2135 * {@link LeScanCallback#onLeScan} callback. 2136 * 2137 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 2138 * 2139 * @param callback the callback LE scan results are delivered 2140 * @return true, if the scan was started successfully 2141 * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)} 2142 * instead. 2143 */ 2144 @Deprecated 2145 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) startLeScan(LeScanCallback callback)2146 public boolean startLeScan(LeScanCallback callback) { 2147 return startLeScan(null, callback); 2148 } 2149 2150 /** 2151 * Starts a scan for Bluetooth LE devices, looking for devices that 2152 * advertise given services. 2153 * 2154 * <p>Devices which advertise all specified services are reported using the 2155 * {@link LeScanCallback#onLeScan} callback. 2156 * 2157 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 2158 * 2159 * @param serviceUuids Array of services to look for 2160 * @param callback the callback LE scan results are delivered 2161 * @return true, if the scan was started successfully 2162 * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)} 2163 * instead. 2164 */ 2165 @Deprecated 2166 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) startLeScan(final UUID[] serviceUuids, final LeScanCallback callback)2167 public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) { 2168 if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids); 2169 if (callback == null) { 2170 if (DBG) Log.e(TAG, "startLeScan: null callback"); 2171 return false; 2172 } 2173 BluetoothLeScanner scanner = getBluetoothLeScanner(); 2174 if (scanner == null) { 2175 if (DBG) Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner"); 2176 return false; 2177 } 2178 2179 synchronized(mLeScanClients) { 2180 if (mLeScanClients.containsKey(callback)) { 2181 if (DBG) Log.e(TAG, "LE Scan has already started"); 2182 return false; 2183 } 2184 2185 try { 2186 IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); 2187 if (iGatt == null) { 2188 // BLE is not supported 2189 return false; 2190 } 2191 2192 ScanCallback scanCallback = new ScanCallback() { 2193 @Override 2194 public void onScanResult(int callbackType, ScanResult result) { 2195 if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { 2196 // Should not happen. 2197 Log.e(TAG, "LE Scan has already started"); 2198 return; 2199 } 2200 ScanRecord scanRecord = result.getScanRecord(); 2201 if (scanRecord == null) { 2202 return; 2203 } 2204 if (serviceUuids != null) { 2205 List<ParcelUuid> uuids = new ArrayList<ParcelUuid>(); 2206 for (UUID uuid : serviceUuids) { 2207 uuids.add(new ParcelUuid(uuid)); 2208 } 2209 List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids(); 2210 if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) { 2211 if (DBG) Log.d(TAG, "uuids does not match"); 2212 return; 2213 } 2214 } 2215 callback.onLeScan(result.getDevice(), result.getRssi(), 2216 scanRecord.getBytes()); 2217 } 2218 }; 2219 ScanSettings settings = new ScanSettings.Builder() 2220 .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) 2221 .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); 2222 2223 List<ScanFilter> filters = new ArrayList<ScanFilter>(); 2224 if (serviceUuids != null && serviceUuids.length > 0) { 2225 // Note scan filter does not support matching an UUID array so we put one 2226 // UUID to hardware and match the whole array in callback. 2227 ScanFilter filter = new ScanFilter.Builder().setServiceUuid( 2228 new ParcelUuid(serviceUuids[0])).build(); 2229 filters.add(filter); 2230 } 2231 scanner.startScan(filters, settings, scanCallback); 2232 2233 mLeScanClients.put(callback, scanCallback); 2234 return true; 2235 2236 } catch (RemoteException e) { 2237 Log.e(TAG,"",e); 2238 } 2239 } 2240 return false; 2241 } 2242 2243 /** 2244 * Stops an ongoing Bluetooth LE device scan. 2245 * 2246 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 2247 * 2248 * @param callback used to identify which scan to stop 2249 * must be the same handle used to start the scan 2250 * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead. 2251 */ 2252 @Deprecated 2253 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) stopLeScan(LeScanCallback callback)2254 public void stopLeScan(LeScanCallback callback) { 2255 if (DBG) Log.d(TAG, "stopLeScan()"); 2256 BluetoothLeScanner scanner = getBluetoothLeScanner(); 2257 if (scanner == null) { 2258 return; 2259 } 2260 synchronized (mLeScanClients) { 2261 ScanCallback scanCallback = mLeScanClients.remove(callback); 2262 if (scanCallback == null) { 2263 if (DBG) Log.d(TAG, "scan not started yet"); 2264 return; 2265 } 2266 scanner.stopScan(scanCallback); 2267 } 2268 } 2269 } 2270