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 */ getDefaultAdapter()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 */ BluetoothAdapter(IBluetoothManager managerService)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 */ getRemoteDevice(String address)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 */ getRemoteDevice(byte[] address)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 */ isEnabled()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 */ getState()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 */ enable()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 */ disable()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 */ disable(boolean persist)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 */ getAddress()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 */ getName()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 */ getUuids()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 */ setName(String name)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 */ getScanMode()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 */ setScanMode(int mode, int duration)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 */ setScanMode(int mode)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 */ getDiscoverableTimeout()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 */ setDiscoverableTimeout(int timeout)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 */ startDiscovery()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 */ cancelDiscovery()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 */ isDiscovering()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 */ getBondedDevices()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 */ getConnectionState()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 */ getProfileConnectionState(int profile)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 */ listenUsingRfcommOn(int channel)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 */ listenUsingRfcommWithServiceRecord(String name, UUID uuid)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 */ listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)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 */ listenUsingEncryptedRfcommWithServiceRecord( String name, UUID uuid)1024 public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord( 1025 String name, UUID uuid) throws IOException { 1026 return createNewRfcommSocketAndRecord(name, uuid, false, true); 1027 } 1028 1029 createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt)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 */ listenUsingInsecureRfcommOn(int port)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 */ listenUsingEncryptedRfcommOn(int port)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 */ listenUsingScoOn()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 */ readOutOfBandData()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 */ getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile)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 */ closeProfileProxy(int profile, BluetoothProfile proxy)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 */ enableNoAutoConnect()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 */ changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback)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 { onBluetoothStateChange(boolean on)1326 public void onBluetoothStateChange(boolean on); 1327 } 1328 1329 /** 1330 * @hide 1331 */ 1332 public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub { 1333 private BluetoothStateChangeCallback mCallback; 1334 StateChangeCallbackWrapper(BluetoothStateChangeCallback callback)1335 StateChangeCallbackWrapper(BluetoothStateChangeCallback 1336 callback) { 1337 mCallback = callback; 1338 } 1339 1340 @Override onBluetoothStateChange(boolean on)1341 public void onBluetoothStateChange(boolean on) { 1342 mCallback.onBluetoothStateChange(on); 1343 } 1344 } 1345 toDeviceSet(BluetoothDevice[] devices)1346 private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) { 1347 Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(Arrays.asList(devices)); 1348 return Collections.unmodifiableSet(deviceSet); 1349 } 1350 finalize()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 */ checkBluetoothAddress(String address)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 getBluetoothManager()1393 /*package*/ IBluetoothManager getBluetoothManager() { 1394 return mManagerService; 1395 } 1396 1397 private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>(); 1398 getBluetoothService(IBluetoothManagerCallback cb)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 removeServiceStateCallback(IBluetoothManagerCallback cb)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 */ onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)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 */ startLeScan(LeScanCallback callback)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 */ startLeScan(UUID[] serviceUuids, LeScanCallback callback)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 */ stopLeScan(LeScanCallback callback)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 GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, LeScanCallback leScanCb, UUID[] uuid)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 scanStarted()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 stopLeScan()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 */ onClientRegistered(int status, int clientIf)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 onClientConnectionState(int status, int clientIf, boolean connected, String address)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 */ onScanResult(String address, int rssi, byte[] advData)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 onGetService(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid)1665 public void onGetService(String address, int srvcType, 1666 int srvcInstId, ParcelUuid srvcUuid) { 1667 // no op 1668 } 1669 onGetIncludedService(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int inclSrvcType, int inclSrvcInstId, ParcelUuid inclSrvcUuid)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 onGetCharacteristic(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, int charProps)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 onGetDescriptor(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, ParcelUuid descUuid)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 onSearchComplete(String address, int status)1691 public void onSearchComplete(String address, int status) { 1692 // no op 1693 } 1694 onCharacteristicRead(String address, int status, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, byte[] value)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 onCharacteristicWrite(String address, int status, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid)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 onNotify(String address, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, byte[] value)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 onDescriptorRead(String address, int status, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, ParcelUuid descrUuid, byte[] value)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 onDescriptorWrite(String address, int status, int srvcType, int srvcInstId, ParcelUuid srvcUuid, int charInstId, ParcelUuid charUuid, ParcelUuid descrUuid)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 onExecuteWrite(String address, int status)1728 public void onExecuteWrite(String address, int status) { 1729 // no op 1730 } 1731 onReadRemoteRssi(String address, int rssi, int status)1732 public void onReadRemoteRssi(String address, int rssi, int status) { 1733 // no op 1734 } 1735 } 1736 1737 } 1738