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