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