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