1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.bluetooth; 18 19 import android.annotation.SdkConstant; 20 import android.annotation.SdkConstant.SdkConstantType; 21 import android.content.Context; 22 import android.os.Binder; 23 import android.os.IBinder; 24 import android.os.Message; 25 import android.os.ParcelUuid; 26 import android.os.RemoteException; 27 import android.os.ServiceManager; 28 import android.util.Log; 29 import android.util.Pair; 30 31 import java.io.IOException; 32 import java.lang.ref.WeakReference; 33 import java.util.ArrayList; 34 import java.util.Arrays; 35 import java.util.Collections; 36 import java.util.HashSet; 37 import java.util.HashMap; 38 import java.util.LinkedList; 39 import java.util.Map; 40 import java.util.Random; 41 import java.util.Set; 42 import java.util.UUID; 43 44 /** 45 * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter} 46 * lets you perform fundamental Bluetooth tasks, such as initiate 47 * device discovery, query a list of bonded (paired) devices, 48 * instantiate a {@link BluetoothDevice} using a known MAC address, and create 49 * a {@link BluetoothServerSocket} to listen for connection requests from other 50 * devices, and start a scan for Bluetooth LE devices. 51 * 52 * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth 53 * adapter, when running on JELLY_BEAN_MR1 and below, call the 54 * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and 55 * higher, retrieve it through 56 * {@link android.content.Context#getSystemService} with 57 * {@link android.content.Context#BLUETOOTH_SERVICE}. 58 * Fundamentally, this is your starting point for all 59 * Bluetooth actions. Once you have the local adapter, you can get a set of 60 * {@link BluetoothDevice} objects representing all paired devices with 61 * {@link #getBondedDevices()}; start device discovery with 62 * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to 63 * listen for incoming connection requests with 64 * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}; or start a scan for 65 * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}. 66 * 67 * <p class="note"><strong>Note:</strong> 68 * Most methods require the {@link android.Manifest.permission#BLUETOOTH} 69 * permission and some also require the 70 * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 71 * 72 * <div class="special reference"> 73 * <h3>Developer Guides</h3> 74 * <p>For more information about using Bluetooth, read the 75 * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p> 76 * </div> 77 * 78 * {@see BluetoothDevice} 79 * {@see BluetoothServerSocket} 80 */ 81 public final class BluetoothAdapter { 82 private static final String TAG = "BluetoothAdapter"; 83 private static final boolean DBG = true; 84 private static final boolean VDBG = false; 85 86 /** 87 * Sentinel error value for this class. Guaranteed to not equal any other 88 * integer constant in this class. Provided as a convenience for functions 89 * that require a sentinel error value, for example: 90 * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 91 * BluetoothAdapter.ERROR)</code> 92 */ 93 public static final int ERROR = Integer.MIN_VALUE; 94 95 /** 96 * Broadcast Action: The state of the local Bluetooth adapter has been 97 * changed. 98 * <p>For example, Bluetooth has been turned on or off. 99 * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link 100 * #EXTRA_PREVIOUS_STATE} containing the new and old states 101 * respectively. 102 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 103 */ 104 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 105 public static final String ACTION_STATE_CHANGED = 106 "android.bluetooth.adapter.action.STATE_CHANGED"; 107 108 /** 109 * Used as an int extra field in {@link #ACTION_STATE_CHANGED} 110 * intents to request the current power state. Possible values are: 111 * {@link #STATE_OFF}, 112 * {@link #STATE_TURNING_ON}, 113 * {@link #STATE_ON}, 114 * {@link #STATE_TURNING_OFF}, 115 */ 116 public static final String EXTRA_STATE = 117 "android.bluetooth.adapter.extra.STATE"; 118 /** 119 * Used as an int extra field in {@link #ACTION_STATE_CHANGED} 120 * intents to request the previous power state. Possible values are: 121 * {@link #STATE_OFF}, 122 * {@link #STATE_TURNING_ON}, 123 * {@link #STATE_ON}, 124 * {@link #STATE_TURNING_OFF}, 125 */ 126 public static final String EXTRA_PREVIOUS_STATE = 127 "android.bluetooth.adapter.extra.PREVIOUS_STATE"; 128 129 /** 130 * Indicates the local Bluetooth adapter is off. 131 */ 132 public static final int STATE_OFF = 10; 133 /** 134 * Indicates the local Bluetooth adapter is turning on. However local 135 * clients should wait for {@link #STATE_ON} before attempting to 136 * use the adapter. 137 */ 138 public static final int STATE_TURNING_ON = 11; 139 /** 140 * Indicates the local Bluetooth adapter is on, and ready for use. 141 */ 142 public static final int STATE_ON = 12; 143 /** 144 * Indicates the local Bluetooth adapter is turning off. Local clients 145 * should immediately attempt graceful disconnection of any remote links. 146 */ 147 public static final int STATE_TURNING_OFF = 13; 148 149 /** 150 * Activity Action: Show a system activity that requests discoverable mode. 151 * This activity will also request the user to turn on Bluetooth if it 152 * is not currently enabled. 153 * <p>Discoverable mode is equivalent to {@link 154 * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see 155 * this Bluetooth adapter when they perform a discovery. 156 * <p>For privacy, Android is not discoverable by default. 157 * <p>The sender of this Intent can optionally use extra field {@link 158 * #EXTRA_DISCOVERABLE_DURATION} to request the duration of 159 * discoverability. Currently the default duration is 120 seconds, and 160 * maximum duration is capped at 300 seconds for each request. 161 * <p>Notification of the result of this activity is posted using the 162 * {@link android.app.Activity#onActivityResult} callback. The 163 * <code>resultCode</code> 164 * will be the duration (in seconds) of discoverability or 165 * {@link android.app.Activity#RESULT_CANCELED} if the user rejected 166 * discoverability or an error has occurred. 167 * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED} 168 * for global notification whenever the scan mode changes. For example, an 169 * application can be notified when the device has ended discoverability. 170 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 171 */ 172 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 173 public static final String ACTION_REQUEST_DISCOVERABLE = 174 "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE"; 175 176 /** 177 * Used as an optional int extra field in {@link 178 * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration 179 * for discoverability in seconds. The current default is 120 seconds, and 180 * requests over 300 seconds will be capped. These values could change. 181 */ 182 public static final String EXTRA_DISCOVERABLE_DURATION = 183 "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION"; 184 185 /** 186 * Activity Action: Show a system activity that allows the user to turn on 187 * Bluetooth. 188 * <p>This system activity will return once Bluetooth has completed turning 189 * on, or the user has decided not to turn Bluetooth on. 190 * <p>Notification of the result of this activity is posted using the 191 * {@link android.app.Activity#onActivityResult} callback. The 192 * <code>resultCode</code> 193 * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been 194 * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user 195 * has rejected the request or an error has occurred. 196 * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED} 197 * for global notification whenever Bluetooth is turned on or off. 198 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 199 */ 200 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 201 public static final String ACTION_REQUEST_ENABLE = 202 "android.bluetooth.adapter.action.REQUEST_ENABLE"; 203 204 /** 205 * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter 206 * has changed. 207 * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link 208 * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes 209 * respectively. 210 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 211 */ 212 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 213 public static final String ACTION_SCAN_MODE_CHANGED = 214 "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; 215 216 /** 217 * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} 218 * intents to request the current scan mode. Possible values are: 219 * {@link #SCAN_MODE_NONE}, 220 * {@link #SCAN_MODE_CONNECTABLE}, 221 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, 222 */ 223 public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE"; 224 /** 225 * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} 226 * intents to request the previous scan mode. Possible values are: 227 * {@link #SCAN_MODE_NONE}, 228 * {@link #SCAN_MODE_CONNECTABLE}, 229 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, 230 */ 231 public static final String EXTRA_PREVIOUS_SCAN_MODE = 232 "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE"; 233 234 /** 235 * Indicates that both inquiry scan and page scan are disabled on the local 236 * Bluetooth adapter. Therefore this device is neither discoverable 237 * nor connectable from remote Bluetooth devices. 238 */ 239 public static final int SCAN_MODE_NONE = 20; 240 /** 241 * Indicates that inquiry scan is disabled, but page scan is enabled on the 242 * local Bluetooth adapter. Therefore this device is not discoverable from 243 * remote Bluetooth devices, but is connectable from remote devices that 244 * have previously discovered this device. 245 */ 246 public static final int SCAN_MODE_CONNECTABLE = 21; 247 /** 248 * Indicates that both inquiry scan and page scan are enabled on the local 249 * Bluetooth adapter. Therefore this device is both discoverable and 250 * connectable from remote Bluetooth devices. 251 */ 252 public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; 253 254 255 /** 256 * Broadcast Action: The local Bluetooth adapter has started the remote 257 * device discovery process. 258 * <p>This usually involves an inquiry scan of about 12 seconds, followed 259 * by a page scan of each new device to retrieve its Bluetooth name. 260 * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as 261 * remote Bluetooth devices are found. 262 * <p>Device discovery is a heavyweight procedure. New connections to 263 * remote Bluetooth devices should not be attempted while discovery is in 264 * progress, and existing connections will experience limited bandwidth 265 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing 266 * discovery. 267 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 268 */ 269 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 270 public static final String ACTION_DISCOVERY_STARTED = 271 "android.bluetooth.adapter.action.DISCOVERY_STARTED"; 272 /** 273 * Broadcast Action: The local Bluetooth adapter has finished the device 274 * discovery process. 275 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 276 */ 277 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 278 public static final String ACTION_DISCOVERY_FINISHED = 279 "android.bluetooth.adapter.action.DISCOVERY_FINISHED"; 280 281 /** 282 * Broadcast Action: The local Bluetooth adapter has changed its friendly 283 * Bluetooth name. 284 * <p>This name is visible to remote Bluetooth devices. 285 * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing 286 * the name. 287 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 288 */ 289 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 290 public static final String ACTION_LOCAL_NAME_CHANGED = 291 "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED"; 292 /** 293 * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED} 294 * intents to request the local Bluetooth name. 295 */ 296 public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME"; 297 298 /** 299 * Intent used to broadcast the change in connection state of the local 300 * Bluetooth adapter to a profile of the remote device. When the adapter is 301 * not connected to any profiles of any remote devices and it attempts a 302 * connection to a profile this intent will sent. Once connected, this intent 303 * will not be sent for any more connection attempts to any profiles of any 304 * remote device. When the adapter disconnects from the last profile its 305 * connected to of any remote device, this intent will be sent. 306 * 307 * <p> This intent is useful for applications that are only concerned about 308 * whether the local adapter is connected to any profile of any device and 309 * are not really concerned about which profile. For example, an application 310 * which displays an icon to display whether Bluetooth is connected or not 311 * can use this intent. 312 * 313 * <p>This intent will have 3 extras: 314 * {@link #EXTRA_CONNECTION_STATE} - The current connection state. 315 * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state. 316 * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. 317 * 318 * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE} 319 * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, 320 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. 321 * 322 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. 323 */ 324 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 325 public static final String ACTION_CONNECTION_STATE_CHANGED = 326 "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED"; 327 328 /** 329 * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} 330 * 331 * This extra represents the current connection state. 332 */ 333 public static final String EXTRA_CONNECTION_STATE = 334 "android.bluetooth.adapter.extra.CONNECTION_STATE"; 335 336 /** 337 * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED} 338 * 339 * This extra represents the previous connection state. 340 */ 341 public static final String EXTRA_PREVIOUS_CONNECTION_STATE = 342 "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE"; 343 344 /** The profile is in disconnected state */ 345 public static final int STATE_DISCONNECTED = 0; 346 /** The profile is in connecting state */ 347 public static final int STATE_CONNECTING = 1; 348 /** The profile is in connected state */ 349 public static final int STATE_CONNECTED = 2; 350 /** The profile is in disconnecting state */ 351 public static final int STATE_DISCONNECTING = 3; 352 353 /** @hide */ 354 public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; 355 356 private static final int ADDRESS_LENGTH = 17; 357 358 /** 359 * Lazily initialized singleton. Guaranteed final after first object 360 * constructed. 361 */ 362 private static BluetoothAdapter sAdapter; 363 364 private final IBluetoothManager mManagerService; 365 private IBluetooth mService; 366 367 private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients; 368 369 /** 370 * Get a handle to the default local Bluetooth adapter. 371 * <p>Currently Android only supports one Bluetooth adapter, but the API 372 * could be extended to support more. This will always return the default 373 * adapter. 374 * @return the default local adapter, or null if Bluetooth is not supported 375 * on this hardware platform 376 */ 377 public static synchronized BluetoothAdapter getDefaultAdapter() { 378 if (sAdapter == null) { 379 IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE); 380 if (b != null) { 381 IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b); 382 sAdapter = new BluetoothAdapter(managerService); 383 } else { 384 Log.e(TAG, "Bluetooth binder is null"); 385 } 386 } 387 return sAdapter; 388 } 389 390 /** 391 * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. 392 */ 393 BluetoothAdapter(IBluetoothManager managerService) { 394 395 if (managerService == null) { 396 throw new IllegalArgumentException("bluetooth manager service is null"); 397 } 398 try { 399 mService = managerService.registerAdapter(mManagerCallback); 400 } catch (RemoteException e) {Log.e(TAG, "", e);} 401 mManagerService = managerService; 402 mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>(); 403 } 404 405 /** 406 * Get a {@link BluetoothDevice} object for the given Bluetooth hardware 407 * address. 408 * <p>Valid Bluetooth hardware addresses must be upper case, in a format 409 * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is 410 * available to validate a Bluetooth address. 411 * <p>A {@link BluetoothDevice} will always be returned for a valid 412 * hardware address, even if this adapter has never seen that device. 413 * 414 * @param address valid Bluetooth MAC address 415 * @throws IllegalArgumentException if address is invalid 416 */ 417 public BluetoothDevice getRemoteDevice(String address) { 418 return new BluetoothDevice(address); 419 } 420 421 /** 422 * Get a {@link BluetoothDevice} object for the given Bluetooth hardware 423 * address. 424 * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method 425 * expects the address in network byte order (MSB first). 426 * <p>A {@link BluetoothDevice} will always be returned for a valid 427 * hardware address, even if this adapter has never seen that device. 428 * 429 * @param address Bluetooth MAC address (6 bytes) 430 * @throws IllegalArgumentException if address is invalid 431 */ 432 public BluetoothDevice getRemoteDevice(byte[] address) { 433 if (address == null || address.length != 6) { 434 throw new IllegalArgumentException("Bluetooth address must have 6 bytes"); 435 } 436 return new BluetoothDevice(String.format("%02X:%02X:%02X:%02X:%02X:%02X", 437 address[0], address[1], address[2], address[3], address[4], address[5])); 438 } 439 440 /** 441 * Return true if Bluetooth is currently enabled and ready for use. 442 * <p>Equivalent to: 443 * <code>getBluetoothState() == STATE_ON</code> 444 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 445 * 446 * @return true if the local adapter is turned on 447 */ 448 public boolean isEnabled() { 449 450 try { 451 synchronized(mManagerCallback) { 452 if (mService != null) return mService.isEnabled(); 453 } 454 } catch (RemoteException e) {Log.e(TAG, "", e);} 455 return false; 456 } 457 458 /** 459 * Get the current state of the local Bluetooth adapter. 460 * <p>Possible return values are 461 * {@link #STATE_OFF}, 462 * {@link #STATE_TURNING_ON}, 463 * {@link #STATE_ON}, 464 * {@link #STATE_TURNING_OFF}. 465 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 466 * 467 * @return current state of Bluetooth adapter 468 */ 469 public int getState() { 470 try { 471 synchronized(mManagerCallback) { 472 if (mService != null) 473 { 474 int state= mService.getState(); 475 if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state); 476 return state; 477 } 478 // TODO(BT) there might be a small gap during STATE_TURNING_ON that 479 // mService is null, handle that case 480 } 481 } catch (RemoteException e) {Log.e(TAG, "", e);} 482 if (DBG) Log.d(TAG, "" + hashCode() + ": getState() : mService = null. Returning STATE_OFF"); 483 return STATE_OFF; 484 } 485 486 /** 487 * Turn on the local Bluetooth adapter—do not use without explicit 488 * user action to turn on Bluetooth. 489 * <p>This powers on the underlying Bluetooth hardware, and starts all 490 * Bluetooth system services. 491 * <p class="caution"><strong>Bluetooth should never be enabled without 492 * direct user consent</strong>. If you want to turn on Bluetooth in order 493 * to create a wireless connection, you should use the {@link 494 * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests 495 * user permission to turn on Bluetooth. The {@link #enable()} method is 496 * provided only for applications that include a user interface for changing 497 * system settings, such as a "power manager" app.</p> 498 * <p>This is an asynchronous call: it will return immediately, and 499 * clients should listen for {@link #ACTION_STATE_CHANGED} 500 * to be notified of subsequent adapter state changes. If this call returns 501 * true, then the adapter state will immediately transition from {@link 502 * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time 503 * later transition to either {@link #STATE_OFF} or {@link 504 * #STATE_ON}. If this call returns false then there was an 505 * immediate problem that will prevent the adapter from being turned on - 506 * such as Airplane mode, or the adapter is already turned on. 507 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} 508 * permission 509 * 510 * @return true to indicate adapter startup has begun, or false on 511 * immediate error 512 */ 513 public boolean enable() { 514 if (isEnabled() == true){ 515 if (DBG) Log.d(TAG, "enable(): BT is already enabled..!"); 516 return true; 517 } 518 try { 519 return mManagerService.enable(); 520 } catch (RemoteException e) {Log.e(TAG, "", e);} 521 return false; 522 } 523 524 /** 525 * Turn off the local Bluetooth adapter—do not use without explicit 526 * user action to turn off Bluetooth. 527 * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth 528 * system services, and powers down the underlying Bluetooth hardware. 529 * <p class="caution"><strong>Bluetooth should never be disabled without 530 * direct user consent</strong>. The {@link #disable()} method is 531 * provided only for applications that include a user interface for changing 532 * system settings, such as a "power manager" app.</p> 533 * <p>This is an asynchronous call: it will return immediately, and 534 * clients should listen for {@link #ACTION_STATE_CHANGED} 535 * to be notified of subsequent adapter state changes. If this call returns 536 * true, then the adapter state will immediately transition from {@link 537 * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time 538 * later transition to either {@link #STATE_OFF} or {@link 539 * #STATE_ON}. If this call returns false then there was an 540 * immediate problem that will prevent the adapter from being turned off - 541 * such as the adapter already being turned off. 542 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} 543 * permission 544 * 545 * @return true to indicate adapter shutdown has begun, or false on 546 * immediate error 547 */ 548 public boolean disable() { 549 try { 550 return mManagerService.disable(true); 551 } catch (RemoteException e) {Log.e(TAG, "", e);} 552 return false; 553 } 554 555 /** 556 * Turn off the local Bluetooth adapter and don't persist the setting. 557 * 558 * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} 559 * permission 560 * 561 * @return true to indicate adapter shutdown has begun, or false on 562 * immediate error 563 * @hide 564 */ 565 public boolean disable(boolean persist) { 566 567 try { 568 return mManagerService.disable(persist); 569 } catch (RemoteException e) {Log.e(TAG, "", e);} 570 return false; 571 } 572 573 /** 574 * Returns the hardware address of the local Bluetooth adapter. 575 * <p>For example, "00:11:22:AA:BB:CC". 576 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 577 * 578 * @return Bluetooth hardware address as string 579 */ 580 public String getAddress() { 581 try { 582 return mManagerService.getAddress(); 583 } catch (RemoteException e) {Log.e(TAG, "", e);} 584 return null; 585 } 586 587 /** 588 * Get the friendly Bluetooth name of the local Bluetooth adapter. 589 * <p>This name is visible to remote Bluetooth devices. 590 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 591 * 592 * @return the Bluetooth name, or null on error 593 */ 594 public String getName() { 595 try { 596 return mManagerService.getName(); 597 } catch (RemoteException e) {Log.e(TAG, "", e);} 598 return null; 599 } 600 601 /** 602 * Get the UUIDs supported by the local Bluetooth adapter. 603 * 604 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 605 * 606 * @return the UUIDs supported by the local Bluetooth Adapter. 607 * @hide 608 */ 609 public ParcelUuid[] getUuids() { 610 if (getState() != STATE_ON) return null; 611 try { 612 synchronized(mManagerCallback) { 613 if (mService != null) return mService.getUuids(); 614 } 615 } catch (RemoteException e) {Log.e(TAG, "", e);} 616 return null; 617 } 618 619 /** 620 * Set the friendly Bluetooth name of the local Bluetooth adapter. 621 * <p>This name is visible to remote Bluetooth devices. 622 * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8 623 * encoding, although many remote devices can only display the first 624 * 40 characters, and some may be limited to just 20. 625 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 626 * will return false. After turning on Bluetooth, 627 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 628 * to get the updated value. 629 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 630 * 631 * @param name a valid Bluetooth name 632 * @return true if the name was set, false otherwise 633 */ 634 public boolean setName(String name) { 635 if (getState() != STATE_ON) return false; 636 try { 637 synchronized(mManagerCallback) { 638 if (mService != null) return mService.setName(name); 639 } 640 } catch (RemoteException e) {Log.e(TAG, "", e);} 641 return false; 642 } 643 644 /** 645 * Get the current Bluetooth scan mode of the local Bluetooth adapter. 646 * <p>The Bluetooth scan mode determines if the local adapter is 647 * connectable and/or discoverable from remote Bluetooth devices. 648 * <p>Possible values are: 649 * {@link #SCAN_MODE_NONE}, 650 * {@link #SCAN_MODE_CONNECTABLE}, 651 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. 652 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 653 * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth, 654 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 655 * to get the updated value. 656 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 657 * 658 * @return scan mode 659 */ 660 public int getScanMode() { 661 if (getState() != STATE_ON) return SCAN_MODE_NONE; 662 try { 663 synchronized(mManagerCallback) { 664 if (mService != null) return mService.getScanMode(); 665 } 666 } catch (RemoteException e) {Log.e(TAG, "", e);} 667 return SCAN_MODE_NONE; 668 } 669 670 /** 671 * Set the Bluetooth scan mode of the local Bluetooth adapter. 672 * <p>The Bluetooth scan mode determines if the local adapter is 673 * connectable and/or discoverable from remote Bluetooth devices. 674 * <p>For privacy reasons, discoverable mode is automatically turned off 675 * after <code>duration</code> seconds. For example, 120 seconds should be 676 * enough for a remote device to initiate and complete its discovery 677 * process. 678 * <p>Valid scan mode values are: 679 * {@link #SCAN_MODE_NONE}, 680 * {@link #SCAN_MODE_CONNECTABLE}, 681 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. 682 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 683 * will return false. After turning on Bluetooth, 684 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 685 * to get the updated value. 686 * <p>Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} 687 * <p>Applications cannot set the scan mode. They should use 688 * <code>startActivityForResult( 689 * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE}) 690 * </code>instead. 691 * 692 * @param mode valid scan mode 693 * @param duration time in seconds to apply scan mode, only used for 694 * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE} 695 * @return true if the scan mode was set, false otherwise 696 * @hide 697 */ 698 public boolean setScanMode(int mode, int duration) { 699 if (getState() != STATE_ON) return false; 700 try { 701 synchronized(mManagerCallback) { 702 if (mService != null) return mService.setScanMode(mode, duration); 703 } 704 } catch (RemoteException e) {Log.e(TAG, "", e);} 705 return false; 706 } 707 708 /** @hide */ 709 public boolean setScanMode(int mode) { 710 if (getState() != STATE_ON) return false; 711 /* getDiscoverableTimeout() to use the latest from NV than use 0 */ 712 return setScanMode(mode, getDiscoverableTimeout()); 713 } 714 715 /** @hide */ 716 public int getDiscoverableTimeout() { 717 if (getState() != STATE_ON) return -1; 718 try { 719 synchronized(mManagerCallback) { 720 if (mService != null) return mService.getDiscoverableTimeout(); 721 } 722 } catch (RemoteException e) {Log.e(TAG, "", e);} 723 return -1; 724 } 725 726 /** @hide */ 727 public void setDiscoverableTimeout(int timeout) { 728 if (getState() != STATE_ON) return; 729 try { 730 synchronized(mManagerCallback) { 731 if (mService != null) mService.setDiscoverableTimeout(timeout); 732 } 733 } catch (RemoteException e) {Log.e(TAG, "", e);} 734 } 735 736 /** 737 * Start the remote device discovery process. 738 * <p>The discovery process usually involves an inquiry scan of about 12 739 * seconds, followed by a page scan of each new device to retrieve its 740 * Bluetooth name. 741 * <p>This is an asynchronous call, it will return immediately. Register 742 * for {@link #ACTION_DISCOVERY_STARTED} and {@link 743 * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the 744 * discovery starts and completes. Register for {@link 745 * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices 746 * are found. 747 * <p>Device discovery is a heavyweight procedure. New connections to 748 * remote Bluetooth devices should not be attempted while discovery is in 749 * progress, and existing connections will experience limited bandwidth 750 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing 751 * discovery. Discovery is not managed by the Activity, 752 * but is run as a system service, so an application should always call 753 * {@link BluetoothAdapter#cancelDiscovery()} even if it 754 * did not directly request a discovery, just to be sure. 755 * <p>Device discovery will only find remote devices that are currently 756 * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are 757 * not discoverable by default, and need to be entered into a special mode. 758 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 759 * will return false. After turning on Bluetooth, 760 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 761 * to get the updated value. 762 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 763 * 764 * @return true on success, false on error 765 */ 766 public boolean startDiscovery() { 767 if (getState() != STATE_ON) return false; 768 try { 769 synchronized(mManagerCallback) { 770 if (mService != null) return mService.startDiscovery(); 771 } 772 } catch (RemoteException e) {Log.e(TAG, "", e);} 773 return false; 774 } 775 776 /** 777 * Cancel the current device discovery process. 778 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. 779 * <p>Because discovery is a heavyweight procedure for the Bluetooth 780 * adapter, this method should always be called before attempting to connect 781 * to a remote device with {@link 782 * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by 783 * the Activity, but is run as a system service, so an application should 784 * always call cancel discovery even if it did not directly request a 785 * discovery, just to be sure. 786 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 787 * will return false. After turning on Bluetooth, 788 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 789 * to get the updated value. 790 * 791 * @return true on success, false on error 792 */ 793 public boolean cancelDiscovery() { 794 if (getState() != STATE_ON) return false; 795 try { 796 synchronized(mManagerCallback) { 797 if (mService != null) return mService.cancelDiscovery(); 798 } 799 } catch (RemoteException e) {Log.e(TAG, "", e);} 800 return false; 801 } 802 803 /** 804 * Return true if the local Bluetooth adapter is currently in the device 805 * discovery process. 806 * <p>Device discovery is a heavyweight procedure. New connections to 807 * remote Bluetooth devices should not be attempted while discovery is in 808 * progress, and existing connections will experience limited bandwidth 809 * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing 810 * discovery. 811 * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED} 812 * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery 813 * starts or completes. 814 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 815 * will return false. After turning on Bluetooth, 816 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 817 * to get the updated value. 818 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 819 * 820 * @return true if discovering 821 */ 822 public boolean isDiscovering() { 823 if (getState() != STATE_ON) return false; 824 try { 825 synchronized(mManagerCallback) { 826 if (mService != null ) return mService.isDiscovering(); 827 } 828 } catch (RemoteException e) {Log.e(TAG, "", e);} 829 return false; 830 } 831 832 /** 833 * Return the set of {@link BluetoothDevice} objects that are bonded 834 * (paired) to the local adapter. 835 * <p>If Bluetooth state is not {@link #STATE_ON}, this API 836 * will return an empty set. After turning on Bluetooth, 837 * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} 838 * to get the updated value. 839 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 840 * 841 * @return unmodifiable set of {@link BluetoothDevice}, or null on error 842 */ 843 public Set<BluetoothDevice> getBondedDevices() { 844 if (getState() != STATE_ON) { 845 return toDeviceSet(new BluetoothDevice[0]); 846 } 847 try { 848 synchronized(mManagerCallback) { 849 if (mService != null) return toDeviceSet(mService.getBondedDevices()); 850 } 851 return toDeviceSet(new BluetoothDevice[0]); 852 } catch (RemoteException e) {Log.e(TAG, "", e);} 853 return null; 854 } 855 856 /** 857 * Get the current connection state of the local Bluetooth adapter. 858 * This can be used to check whether the local Bluetooth adapter is connected 859 * to any profile of any other remote Bluetooth Device. 860 * 861 * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED} 862 * intent to get the connection state of the adapter. 863 * 864 * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED}, 865 * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED} 866 * 867 * @hide 868 */ 869 public int getConnectionState() { 870 if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED; 871 try { 872 synchronized(mManagerCallback) { 873 if (mService != null) return mService.getAdapterConnectionState(); 874 } 875 } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);} 876 return BluetoothAdapter.STATE_DISCONNECTED; 877 } 878 879 /** 880 * Get the current connection state of a profile. 881 * This function can be used to check whether the local Bluetooth adapter 882 * is connected to any remote device for a specific profile. 883 * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, 884 * {@link BluetoothProfile#A2DP}. 885 * 886 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. 887 * 888 * <p> Return value can be one of 889 * {@link BluetoothProfile#STATE_DISCONNECTED}, 890 * {@link BluetoothProfile#STATE_CONNECTING}, 891 * {@link BluetoothProfile#STATE_CONNECTED}, 892 * {@link BluetoothProfile#STATE_DISCONNECTING} 893 */ 894 public int getProfileConnectionState(int profile) { 895 if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED; 896 try { 897 synchronized(mManagerCallback) { 898 if (mService != null) return mService.getProfileConnectionState(profile); 899 } 900 } catch (RemoteException e) { 901 Log.e(TAG, "getProfileConnectionState:", e); 902 } 903 return BluetoothProfile.STATE_DISCONNECTED; 904 } 905 906 /** 907 * Create a listening, secure RFCOMM Bluetooth socket. 908 * <p>A remote device connecting to this socket will be authenticated and 909 * communication on this socket will be encrypted. 910 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 911 * connections from a listening {@link BluetoothServerSocket}. 912 * <p>Valid RFCOMM channels are in range 1 to 30. 913 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 914 * @param channel RFCOMM channel to listen on 915 * @return a listening RFCOMM BluetoothServerSocket 916 * @throws IOException on error, for example Bluetooth not available, or 917 * insufficient permissions, or channel in use. 918 * @hide 919 */ 920 public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException { 921 BluetoothServerSocket socket = new BluetoothServerSocket( 922 BluetoothSocket.TYPE_RFCOMM, true, true, channel); 923 int errno = socket.mSocket.bindListen(); 924 if (errno != 0) { 925 //TODO(BT): Throw the same exception error code 926 // that the previous code was using. 927 //socket.mSocket.throwErrnoNative(errno); 928 throw new IOException("Error: " + errno); 929 } 930 return socket; 931 } 932 933 /** 934 * Create a listening, secure RFCOMM Bluetooth socket with Service Record. 935 * <p>A remote device connecting to this socket will be authenticated and 936 * communication on this socket will be encrypted. 937 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 938 * connections from a listening {@link BluetoothServerSocket}. 939 * <p>The system will assign an unused RFCOMM channel to listen on. 940 * <p>The system will also register a Service Discovery 941 * Protocol (SDP) record with the local SDP server containing the specified 942 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices 943 * can use the same UUID to query our SDP server and discover which channel 944 * to connect to. This SDP record will be removed when this socket is 945 * closed, or if this application closes unexpectedly. 946 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to 947 * connect to this socket from another device using the same {@link UUID}. 948 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 949 * @param name service name for SDP record 950 * @param uuid uuid for SDP record 951 * @return a listening RFCOMM BluetoothServerSocket 952 * @throws IOException on error, for example Bluetooth not available, or 953 * insufficient permissions, or channel in use. 954 */ 955 public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid) 956 throws IOException { 957 return createNewRfcommSocketAndRecord(name, uuid, true, true); 958 } 959 960 /** 961 * Create a listening, insecure RFCOMM Bluetooth socket with Service Record. 962 * <p>The link key is not required to be authenticated, i.e the communication may be 963 * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices, 964 * the link will be encrypted, as encryption is mandartory. 965 * For legacy devices (pre Bluetooth 2.1 devices) the link will not 966 * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an 967 * encrypted and authenticated communication channel is desired. 968 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 969 * connections from a listening {@link BluetoothServerSocket}. 970 * <p>The system will assign an unused RFCOMM channel to listen on. 971 * <p>The system will also register a Service Discovery 972 * Protocol (SDP) record with the local SDP server containing the specified 973 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices 974 * can use the same UUID to query our SDP server and discover which channel 975 * to connect to. This SDP record will be removed when this socket is 976 * closed, or if this application closes unexpectedly. 977 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to 978 * connect to this socket from another device using the same {@link UUID}. 979 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 980 * @param name service name for SDP record 981 * @param uuid uuid for SDP record 982 * @return a listening RFCOMM BluetoothServerSocket 983 * @throws IOException on error, for example Bluetooth not available, or 984 * insufficient permissions, or channel in use. 985 */ 986 public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid) 987 throws IOException { 988 return createNewRfcommSocketAndRecord(name, uuid, false, false); 989 } 990 991 /** 992 * Create a listening, encrypted, 993 * RFCOMM Bluetooth socket with Service Record. 994 * <p>The link will be encrypted, but the link key is not required to be authenticated 995 * i.e the communication is vulnerable to Man In the Middle attacks. Use 996 * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key. 997 * <p> Use this socket if authentication of link key is not possible. 998 * For example, for Bluetooth 2.1 devices, if any of the devices does not have 999 * an input and output capability or just has the ability to display a numeric key, 1000 * a secure socket connection is not possible and this socket can be used. 1001 * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required. 1002 * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory. 1003 * For more details, refer to the Security Model section 5.2 (vol 3) of 1004 * Bluetooth Core Specification version 2.1 + EDR. 1005 * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming 1006 * connections from a listening {@link BluetoothServerSocket}. 1007 * <p>The system will assign an unused RFCOMM channel to listen on. 1008 * <p>The system will also register a Service Discovery 1009 * Protocol (SDP) record with the local SDP server containing the specified 1010 * UUID, service name, and auto-assigned channel. Remote Bluetooth devices 1011 * can use the same UUID to query our SDP server and discover which channel 1012 * to connect to. This SDP record will be removed when this socket is 1013 * closed, or if this application closes unexpectedly. 1014 * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to 1015 * connect to this socket from another device using the same {@link UUID}. 1016 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1017 * @param name service name for SDP record 1018 * @param uuid uuid for SDP record 1019 * @return a listening RFCOMM BluetoothServerSocket 1020 * @throws IOException on error, for example Bluetooth not available, or 1021 * insufficient permissions, or channel in use. 1022 * @hide 1023 */ 1024 public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord( 1025 String name, UUID uuid) throws IOException { 1026 return createNewRfcommSocketAndRecord(name, uuid, false, true); 1027 } 1028 1029 1030 private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid, 1031 boolean auth, boolean encrypt) throws IOException { 1032 BluetoothServerSocket socket; 1033 socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, 1034 encrypt, new ParcelUuid(uuid)); 1035 socket.setServiceName(name); 1036 int errno = socket.mSocket.bindListen(); 1037 if (errno != 0) { 1038 //TODO(BT): Throw the same exception error code 1039 // that the previous code was using. 1040 //socket.mSocket.throwErrnoNative(errno); 1041 throw new IOException("Error: " + errno); 1042 } 1043 return socket; 1044 } 1045 1046 /** 1047 * Construct an unencrypted, unauthenticated, RFCOMM server socket. 1048 * Call #accept to retrieve connections to this socket. 1049 * @return An RFCOMM BluetoothServerSocket 1050 * @throws IOException On error, for example Bluetooth not available, or 1051 * insufficient permissions. 1052 * @hide 1053 */ 1054 public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException { 1055 BluetoothServerSocket socket = new BluetoothServerSocket( 1056 BluetoothSocket.TYPE_RFCOMM, false, false, port); 1057 int errno = socket.mSocket.bindListen(); 1058 if (errno != 0) { 1059 //TODO(BT): Throw the same exception error code 1060 // that the previous code was using. 1061 //socket.mSocket.throwErrnoNative(errno); 1062 throw new IOException("Error: " + errno); 1063 } 1064 return socket; 1065 } 1066 1067 /** 1068 * Construct an encrypted, RFCOMM server socket. 1069 * Call #accept to retrieve connections to this socket. 1070 * @return An RFCOMM BluetoothServerSocket 1071 * @throws IOException On error, for example Bluetooth not available, or 1072 * insufficient permissions. 1073 * @hide 1074 */ 1075 public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port) 1076 throws IOException { 1077 BluetoothServerSocket socket = new BluetoothServerSocket( 1078 BluetoothSocket.TYPE_RFCOMM, false, true, port); 1079 int errno = socket.mSocket.bindListen(); 1080 if (errno < 0) { 1081 //TODO(BT): Throw the same exception error code 1082 // that the previous code was using. 1083 //socket.mSocket.throwErrnoNative(errno); 1084 throw new IOException("Error: " + errno); 1085 } 1086 return socket; 1087 } 1088 1089 /** 1090 * Construct a SCO server socket. 1091 * Call #accept to retrieve connections to this socket. 1092 * @return A SCO BluetoothServerSocket 1093 * @throws IOException On error, for example Bluetooth not available, or 1094 * insufficient permissions. 1095 * @hide 1096 */ 1097 public static BluetoothServerSocket listenUsingScoOn() throws IOException { 1098 BluetoothServerSocket socket = new BluetoothServerSocket( 1099 BluetoothSocket.TYPE_SCO, false, false, -1); 1100 int errno = socket.mSocket.bindListen(); 1101 if (errno < 0) { 1102 //TODO(BT): Throw the same exception error code 1103 // that the previous code was using. 1104 //socket.mSocket.throwErrnoNative(errno); 1105 } 1106 return socket; 1107 } 1108 1109 /** 1110 * Read the local Out of Band Pairing Data 1111 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1112 * 1113 * @return Pair<byte[], byte[]> of Hash and Randomizer 1114 * 1115 * @hide 1116 */ 1117 public Pair<byte[], byte[]> readOutOfBandData() { 1118 if (getState() != STATE_ON) return null; 1119 //TODO(BT 1120 /* 1121 try { 1122 byte[] hash; 1123 byte[] randomizer; 1124 1125 byte[] ret = mService.readOutOfBandData(); 1126 1127 if (ret == null || ret.length != 32) return null; 1128 1129 hash = Arrays.copyOfRange(ret, 0, 16); 1130 randomizer = Arrays.copyOfRange(ret, 16, 32); 1131 1132 if (DBG) { 1133 Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) + 1134 ":" + Arrays.toString(randomizer)); 1135 } 1136 return new Pair<byte[], byte[]>(hash, randomizer); 1137 1138 } catch (RemoteException e) {Log.e(TAG, "", e);}*/ 1139 return null; 1140 } 1141 1142 /** 1143 * Get the profile proxy object associated with the profile. 1144 * 1145 * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET}, 1146 * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or 1147 * {@link BluetoothProfile#GATT_SERVER}. Clients must implement 1148 * {@link BluetoothProfile.ServiceListener} to get notified of 1149 * the connection status and to get the proxy object. 1150 * 1151 * @param context Context of the application 1152 * @param listener The service Listener for connection callbacks. 1153 * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH}, 1154 * {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}. 1155 * @return true on success, false on error 1156 */ 1157 public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, 1158 int profile) { 1159 if (context == null || listener == null) return false; 1160 1161 if (profile == BluetoothProfile.HEADSET) { 1162 BluetoothHeadset headset = new BluetoothHeadset(context, listener); 1163 return true; 1164 } else if (profile == BluetoothProfile.A2DP) { 1165 BluetoothA2dp a2dp = new BluetoothA2dp(context, listener); 1166 return true; 1167 } else if (profile == BluetoothProfile.INPUT_DEVICE) { 1168 BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener); 1169 return true; 1170 } else if (profile == BluetoothProfile.PAN) { 1171 BluetoothPan pan = new BluetoothPan(context, listener); 1172 return true; 1173 } else if (profile == BluetoothProfile.HEALTH) { 1174 BluetoothHealth health = new BluetoothHealth(context, listener); 1175 return true; 1176 } else { 1177 return false; 1178 } 1179 } 1180 1181 /** 1182 * Close the connection of the profile proxy to the Service. 1183 * 1184 * <p> Clients should call this when they are no longer using 1185 * the proxy obtained from {@link #getProfileProxy}. 1186 * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or 1187 * {@link BluetoothProfile#A2DP} 1188 * 1189 * @param profile 1190 * @param proxy Profile proxy object 1191 */ 1192 public void closeProfileProxy(int profile, BluetoothProfile proxy) { 1193 if (proxy == null) return; 1194 1195 switch (profile) { 1196 case BluetoothProfile.HEADSET: 1197 BluetoothHeadset headset = (BluetoothHeadset)proxy; 1198 headset.close(); 1199 break; 1200 case BluetoothProfile.A2DP: 1201 BluetoothA2dp a2dp = (BluetoothA2dp)proxy; 1202 a2dp.close(); 1203 break; 1204 case BluetoothProfile.INPUT_DEVICE: 1205 BluetoothInputDevice iDev = (BluetoothInputDevice)proxy; 1206 iDev.close(); 1207 break; 1208 case BluetoothProfile.PAN: 1209 BluetoothPan pan = (BluetoothPan)proxy; 1210 pan.close(); 1211 break; 1212 case BluetoothProfile.HEALTH: 1213 BluetoothHealth health = (BluetoothHealth)proxy; 1214 health.close(); 1215 break; 1216 case BluetoothProfile.GATT: 1217 BluetoothGatt gatt = (BluetoothGatt)proxy; 1218 gatt.close(); 1219 break; 1220 case BluetoothProfile.GATT_SERVER: 1221 BluetoothGattServer gattServer = (BluetoothGattServer)proxy; 1222 gattServer.close(); 1223 break; 1224 } 1225 } 1226 1227 final private IBluetoothManagerCallback mManagerCallback = 1228 new IBluetoothManagerCallback.Stub() { 1229 public void onBluetoothServiceUp(IBluetooth bluetoothService) { 1230 if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService); 1231 synchronized (mManagerCallback) { 1232 mService = bluetoothService; 1233 for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ 1234 try { 1235 if (cb != null) { 1236 cb.onBluetoothServiceUp(bluetoothService); 1237 } else { 1238 Log.d(TAG, "onBluetoothServiceUp: cb is null!!!"); 1239 } 1240 } catch (Exception e) { Log.e(TAG,"",e);} 1241 } 1242 } 1243 } 1244 1245 public void onBluetoothServiceDown() { 1246 if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); 1247 synchronized (mManagerCallback) { 1248 mService = null; 1249 for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ 1250 try { 1251 if (cb != null) { 1252 cb.onBluetoothServiceDown(); 1253 } else { 1254 Log.d(TAG, "onBluetoothServiceDown: cb is null!!!"); 1255 } 1256 } catch (Exception e) { Log.e(TAG,"",e);} 1257 } 1258 } 1259 } 1260 }; 1261 1262 /** 1263 * Enable the Bluetooth Adapter, but don't auto-connect devices 1264 * and don't persist state. Only for use by system applications. 1265 * @hide 1266 */ 1267 public boolean enableNoAutoConnect() { 1268 if (isEnabled() == true){ 1269 if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT is already enabled..!"); 1270 return true; 1271 } 1272 try { 1273 return mManagerService.enableNoAutoConnect(); 1274 } catch (RemoteException e) {Log.e(TAG, "", e);} 1275 return false; 1276 } 1277 1278 /** 1279 * Enable control of the Bluetooth Adapter for a single application. 1280 * 1281 * <p>Some applications need to use Bluetooth for short periods of time to 1282 * transfer data but don't want all the associated implications like 1283 * automatic connection to headsets etc. 1284 * 1285 * <p> Multiple applications can call this. This is reference counted and 1286 * Bluetooth disabled only when no one else is using it. There will be no UI 1287 * shown to the user while bluetooth is being enabled. Any user action will 1288 * override this call. For example, if user wants Bluetooth on and the last 1289 * user of this API wanted to disable Bluetooth, Bluetooth will not be 1290 * turned off. 1291 * 1292 * <p> This API is only meant to be used by internal applications. Third 1293 * party applications but use {@link #enable} and {@link #disable} APIs. 1294 * 1295 * <p> If this API returns true, it means the callback will be called. 1296 * The callback will be called with the current state of Bluetooth. 1297 * If the state is not what was requested, an internal error would be the 1298 * reason. If Bluetooth is already on and if this function is called to turn 1299 * it on, the api will return true and a callback will be called. 1300 * 1301 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} 1302 * 1303 * @param on True for on, false for off. 1304 * @param callback The callback to notify changes to the state. 1305 * @hide 1306 */ 1307 public boolean changeApplicationBluetoothState(boolean on, 1308 BluetoothStateChangeCallback callback) { 1309 if (callback == null) return false; 1310 1311 //TODO(BT) 1312 /* 1313 try { 1314 return mService.changeApplicationBluetoothState(on, new 1315 StateChangeCallbackWrapper(callback), new Binder()); 1316 } catch (RemoteException e) { 1317 Log.e(TAG, "changeBluetoothState", e); 1318 }*/ 1319 return false; 1320 } 1321 1322 /** 1323 * @hide 1324 */ 1325 public interface BluetoothStateChangeCallback { 1326 public void onBluetoothStateChange(boolean on); 1327 } 1328 1329 /** 1330 * @hide 1331 */ 1332 public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub { 1333 private BluetoothStateChangeCallback mCallback; 1334 1335 StateChangeCallbackWrapper(BluetoothStateChangeCallback 1336 callback) { 1337 mCallback = callback; 1338 } 1339 1340 @Override 1341 public void onBluetoothStateChange(boolean on) { 1342 mCallback.onBluetoothStateChange(on); 1343 } 1344 } 1345 1346 private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) { 1347 Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(Arrays.asList(devices)); 1348 return Collections.unmodifiableSet(deviceSet); 1349 } 1350 1351 protected void finalize() throws Throwable { 1352 try { 1353 mManagerService.unregisterAdapter(mManagerCallback); 1354 } catch (RemoteException e) { 1355 Log.e(TAG, "", e); 1356 } finally { 1357 super.finalize(); 1358 } 1359 } 1360 1361 1362 /** 1363 * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0" 1364 * <p>Alphabetic characters must be uppercase to be valid. 1365 * 1366 * @param address Bluetooth address as string 1367 * @return true if the address is valid, false otherwise 1368 */ 1369 public static boolean checkBluetoothAddress(String address) { 1370 if (address == null || address.length() != ADDRESS_LENGTH) { 1371 return false; 1372 } 1373 for (int i = 0; i < ADDRESS_LENGTH; i++) { 1374 char c = address.charAt(i); 1375 switch (i % 3) { 1376 case 0: 1377 case 1: 1378 if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { 1379 // hex character, OK 1380 break; 1381 } 1382 return false; 1383 case 2: 1384 if (c == ':') { 1385 break; // OK 1386 } 1387 return false; 1388 } 1389 } 1390 return true; 1391 } 1392 1393 /*package*/ IBluetoothManager getBluetoothManager() { 1394 return mManagerService; 1395 } 1396 1397 private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>(); 1398 1399 /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) { 1400 synchronized (mManagerCallback) { 1401 if (cb == null) { 1402 Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback"); 1403 } else if (!mProxyServiceStateCallbacks.contains(cb)) { 1404 mProxyServiceStateCallbacks.add(cb); 1405 } 1406 } 1407 return mService; 1408 } 1409 1410 /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) { 1411 synchronized (mManagerCallback) { 1412 mProxyServiceStateCallbacks.remove(cb); 1413 } 1414 } 1415 1416 /** 1417 * Callback interface used to deliver LE scan results. 1418 * 1419 * @see #startLeScan(LeScanCallback) 1420 * @see #startLeScan(UUID[], LeScanCallback) 1421 */ 1422 public interface LeScanCallback { 1423 /** 1424 * Callback reporting an LE device found during a device scan initiated 1425 * by the {@link BluetoothAdapter#startLeScan} function. 1426 * 1427 * @param device Identifies the remote device 1428 * @param rssi The RSSI value for the remote device as reported by the 1429 * Bluetooth hardware. 0 if no RSSI value is available. 1430 * @param scanRecord The content of the advertisement record offered by 1431 * the remote device. 1432 */ 1433 public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord); 1434 } 1435 1436 /** 1437 * Starts a scan for Bluetooth LE devices. 1438 * 1439 * <p>Results of the scan are reported using the 1440 * {@link LeScanCallback#onLeScan} callback. 1441 * 1442 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 1443 * 1444 * @param callback the callback LE scan results are delivered 1445 * @return true, if the scan was started successfully 1446 */ 1447 public boolean startLeScan(LeScanCallback callback) { 1448 return startLeScan(null, callback); 1449 } 1450 1451 /** 1452 * Starts a scan for Bluetooth LE devices, looking for devices that 1453 * advertise given services. 1454 * 1455 * <p>Devices which advertise all specified services are reported using the 1456 * {@link LeScanCallback#onLeScan} callback. 1457 * 1458 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 1459 * 1460 * @param serviceUuids Array of services to look for 1461 * @param callback the callback LE scan results are delivered 1462 * @return true, if the scan was started successfully 1463 */ 1464 public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) { 1465 if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids); 1466 1467 if (callback == null) { 1468 if (DBG) Log.e(TAG, "startLeScan: null callback"); 1469 return false; 1470 } 1471 1472 synchronized(mLeScanClients) { 1473 if (mLeScanClients.containsKey(callback)) { 1474 if (DBG) Log.e(TAG, "LE Scan has already started"); 1475 return false; 1476 } 1477 1478 try { 1479 IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); 1480 if (iGatt == null) { 1481 // BLE is not supported 1482 return false; 1483 } 1484 1485 UUID uuid = UUID.randomUUID(); 1486 GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids); 1487 iGatt.registerClient(new ParcelUuid(uuid), wrapper); 1488 if (wrapper.scanStarted()) { 1489 mLeScanClients.put(callback, wrapper); 1490 return true; 1491 } 1492 } catch (RemoteException e) { 1493 Log.e(TAG,"",e); 1494 } 1495 } 1496 return false; 1497 } 1498 1499 /** 1500 * Stops an ongoing Bluetooth LE device scan. 1501 * 1502 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 1503 * 1504 * @param callback used to identify which scan to stop 1505 * must be the same handle used to start the scan 1506 */ 1507 public void stopLeScan(LeScanCallback callback) { 1508 if (DBG) Log.d(TAG, "stopLeScan()"); 1509 GattCallbackWrapper wrapper; 1510 synchronized(mLeScanClients) { 1511 wrapper = mLeScanClients.remove(callback); 1512 if (wrapper == null) return; 1513 } 1514 wrapper.stopLeScan(); 1515 } 1516 1517 /** 1518 * Bluetooth GATT interface callbacks 1519 */ 1520 private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub { 1521 private static final int LE_CALLBACK_REG_TIMEOUT = 2000; 1522 private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; 1523 1524 private final LeScanCallback mLeScanCb; 1525 // mLeHandle 0: not registered 1526 // -1: scan stopped 1527 // >0: registered and scan started 1528 private int mLeHandle; 1529 private final UUID[] mScanFilter; 1530 private WeakReference<BluetoothAdapter> mBluetoothAdapter; 1531 1532 public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, 1533 LeScanCallback leScanCb, UUID[] uuid) { 1534 mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter); 1535 mLeScanCb = leScanCb; 1536 mScanFilter = uuid; 1537 mLeHandle = 0; 1538 } 1539 1540 public boolean scanStarted() { 1541 boolean started = false; 1542 synchronized(this) { 1543 if (mLeHandle == -1) return false; 1544 1545 int count = 0; 1546 // wait for callback registration and LE scan to start 1547 while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) { 1548 try { 1549 wait(LE_CALLBACK_REG_TIMEOUT); 1550 } catch (InterruptedException e) { 1551 Log.e(TAG, "Callback reg wait interrupted: " + e); 1552 } 1553 count++; 1554 } 1555 started = (mLeHandle > 0); 1556 } 1557 return started; 1558 } 1559 1560 public void stopLeScan() { 1561 synchronized(this) { 1562 if (mLeHandle <= 0) { 1563 Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); 1564 return; 1565 } 1566 BluetoothAdapter adapter = mBluetoothAdapter.get(); 1567 if (adapter != null) { 1568 try { 1569 IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); 1570 iGatt.stopScan(mLeHandle, false); 1571 iGatt.unregisterClient(mLeHandle); 1572 } catch (RemoteException e) { 1573 Log.e(TAG, "Failed to stop scan and unregister" + e); 1574 } 1575 } else { 1576 Log.e(TAG, "stopLeScan, BluetoothAdapter is null"); 1577 } 1578 mLeHandle = -1; 1579 notifyAll(); 1580 } 1581 } 1582 1583 /** 1584 * Application interface registered - app is ready to go 1585 */ 1586 public void onClientRegistered(int status, int clientIf) { 1587 if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status + 1588 " clientIf=" + clientIf); 1589 synchronized(this) { 1590 if (mLeHandle == -1) { 1591 if (DBG) Log.d(TAG, "onClientRegistered LE scan canceled"); 1592 } 1593 1594 if (status == BluetoothGatt.GATT_SUCCESS) { 1595 mLeHandle = clientIf; 1596 IBluetoothGatt iGatt = null; 1597 try { 1598 BluetoothAdapter adapter = mBluetoothAdapter.get(); 1599 if (adapter != null) { 1600 iGatt = adapter.getBluetoothManager().getBluetoothGatt(); 1601 if (mScanFilter == null) { 1602 iGatt.startScan(mLeHandle, false); 1603 } else { 1604 ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; 1605 for(int i = 0; i != uuids.length; ++i) { 1606 uuids[i] = new ParcelUuid(mScanFilter[i]); 1607 } 1608 iGatt.startScanWithUuids(mLeHandle, false, uuids); 1609 } 1610 } else { 1611 Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); 1612 mLeHandle = -1; 1613 } 1614 } catch (RemoteException e) { 1615 Log.e(TAG, "fail to start le scan: " + e); 1616 mLeHandle = -1; 1617 } 1618 if (mLeHandle == -1) { 1619 // registration succeeded but start scan failed 1620 if (iGatt != null) { 1621 try { 1622 iGatt.unregisterClient(mLeHandle); 1623 } catch (RemoteException e) { 1624 Log.e(TAG, "fail to unregister callback: " + mLeHandle + 1625 " error: " + e); 1626 } 1627 } 1628 } 1629 } else { 1630 // registration failed 1631 mLeHandle = -1; 1632 } 1633 notifyAll(); 1634 } 1635 } 1636 1637 public void onClientConnectionState(int status, int clientIf, 1638 boolean connected, String address) { 1639 // no op 1640 } 1641 1642 /** 1643 * Callback reporting an LE scan result. 1644 * @hide 1645 */ 1646 public void onScanResult(String address, int rssi, byte[] advData) { 1647 if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); 1648 1649 // Check null in case the scan has been stopped 1650 synchronized(this) { 1651 if (mLeHandle <= 0) return; 1652 } 1653 try { 1654 BluetoothAdapter adapter = mBluetoothAdapter.get(); 1655 if (adapter == null) { 1656 Log.d(TAG, "onScanResult, BluetoothAdapter null"); 1657 return; 1658 } 1659 mLeScanCb.onLeScan(adapter.getRemoteDevice(address), rssi, advData); 1660 } catch (Exception ex) { 1661 Log.w(TAG, "Unhandled exception: " + ex); 1662 } 1663 } 1664 1665 public void onGetService(String address, int srvcType, 1666 int srvcInstId, ParcelUuid srvcUuid) { 1667 // no op 1668 } 1669 1670 public void onGetIncludedService(String address, int srvcType, 1671 int srvcInstId, ParcelUuid srvcUuid, 1672 int inclSrvcType, int inclSrvcInstId, 1673 ParcelUuid inclSrvcUuid) { 1674 // no op 1675 } 1676 1677 public void onGetCharacteristic(String address, int srvcType, 1678 int srvcInstId, ParcelUuid srvcUuid, 1679 int charInstId, ParcelUuid charUuid, 1680 int charProps) { 1681 // no op 1682 } 1683 1684 public void onGetDescriptor(String address, int srvcType, 1685 int srvcInstId, ParcelUuid srvcUuid, 1686 int charInstId, ParcelUuid charUuid, 1687 ParcelUuid descUuid) { 1688 // no op 1689 } 1690 1691 public void onSearchComplete(String address, int status) { 1692 // no op 1693 } 1694 1695 public void onCharacteristicRead(String address, int status, int srvcType, 1696 int srvcInstId, ParcelUuid srvcUuid, 1697 int charInstId, ParcelUuid charUuid, byte[] value) { 1698 // no op 1699 } 1700 1701 public void onCharacteristicWrite(String address, int status, int srvcType, 1702 int srvcInstId, ParcelUuid srvcUuid, 1703 int charInstId, ParcelUuid charUuid) { 1704 // no op 1705 } 1706 1707 public void onNotify(String address, int srvcType, 1708 int srvcInstId, ParcelUuid srvcUuid, 1709 int charInstId, ParcelUuid charUuid, 1710 byte[] value) { 1711 // no op 1712 } 1713 1714 public void onDescriptorRead(String address, int status, int srvcType, 1715 int srvcInstId, ParcelUuid srvcUuid, 1716 int charInstId, ParcelUuid charUuid, 1717 ParcelUuid descrUuid, byte[] value) { 1718 // no op 1719 } 1720 1721 public void onDescriptorWrite(String address, int status, int srvcType, 1722 int srvcInstId, ParcelUuid srvcUuid, 1723 int charInstId, ParcelUuid charUuid, 1724 ParcelUuid descrUuid) { 1725 // no op 1726 } 1727 1728 public void onExecuteWrite(String address, int status) { 1729 // no op 1730 } 1731 1732 public void onReadRemoteRssi(String address, int rssi, int status) { 1733 // no op 1734 } 1735 } 1736 1737 } 1738