BluetoothDevice.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/* 2 * Copyright (C) 2008 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.os.RemoteException; 20import android.util.Log; 21 22import java.io.UnsupportedEncodingException; 23 24/** 25 * The Android Bluetooth API is not finalized, and *will* change. Use at your 26 * own risk. 27 * 28 * Manages the local Bluetooth device. Scan for devices, create bondings, 29 * power up and down the adapter. 30 * 31 * @hide 32 */ 33public class BluetoothDevice { 34 public static final int MODE_UNKNOWN = -1; 35 public static final int MODE_OFF = 0; 36 public static final int MODE_CONNECTABLE = 1; 37 public static final int MODE_DISCOVERABLE = 2; 38 39 public static final int RESULT_FAILURE = -1; 40 public static final int RESULT_SUCCESS = 0; 41 42 private static final String TAG = "BluetoothDevice"; 43 44 private final IBluetoothDevice mService; 45 /** 46 * @hide - hide this because it takes a parameter of type 47 * IBluetoothDevice, which is a System private class. 48 * Also note that Context.getSystemService is a factory that 49 * returns a BlueToothDevice. That is the right way to get 50 * a BluetoothDevice. 51 */ 52 public BluetoothDevice(IBluetoothDevice service) { 53 mService = service; 54 } 55 56 /** 57 * Get the current status of Bluetooth hardware. 58 * 59 * @return true if Bluetooth enabled, false otherwise. 60 */ 61 public boolean isEnabled() { 62 try { 63 return mService.isEnabled(); 64 } catch (RemoteException e) {Log.e(TAG, "", e);} 65 return false; 66 } 67 68 /** 69 * Enable the Bluetooth device. 70 * Turn on the underlying hardware. 71 * This is an asynchronous call, BluetoothIntent.ENABLED_ACTION will be 72 * sent if and when the device is successfully enabled. 73 * @return false if we cannot enable the Bluetooth device. True does not 74 * imply the device was enabled, it only implies that so far there were no 75 * problems. 76 */ 77 public boolean enable() { 78 return enable(null); 79 } 80 81 /** 82 * Enable the Bluetooth device. 83 * Turns on the underlying hardware. 84 * This is an asynchronous call. onEnableResult() of your callback will be 85 * called when the call is complete, with either RESULT_SUCCESS or 86 * RESULT_FAILURE. 87 * 88 * Your callback will be called from a binder thread, not the main thread. 89 * 90 * In addition to the callback, BluetoothIntent.ENABLED_ACTION will be 91 * broadcast if the device is successfully enabled. 92 * 93 * @param callback Your callback, null is ok. 94 * @return true if your callback was successfully registered, or false if 95 * there was an error, implying your callback will never be called. 96 */ 97 public boolean enable(IBluetoothDeviceCallback callback) { 98 try { 99 return mService.enable(callback); 100 } catch (RemoteException e) {Log.e(TAG, "", e);} 101 return false; 102 } 103 104 /** 105 * Disable the Bluetooth device. 106 * This turns off the underlying hardware. 107 * 108 * @return true if successful, false otherwise. 109 */ 110 public boolean disable() { 111 try { 112 return mService.disable(); 113 } catch (RemoteException e) {Log.e(TAG, "", e);} 114 return false; 115 } 116 117 public String getAddress() { 118 try { 119 return mService.getAddress(); 120 } catch (RemoteException e) {Log.e(TAG, "", e);} 121 return null; 122 } 123 124 /** 125 * Get the friendly Bluetooth name of this device. 126 * 127 * This name is visible to remote Bluetooth devices. Currently it is only 128 * possible to retrieve the Bluetooth name when Bluetooth is enabled. 129 * 130 * @return the Bluetooth name, or null if there was a problem. 131 */ 132 public String getName() { 133 try { 134 return mService.getName(); 135 } catch (RemoteException e) {Log.e(TAG, "", e);} 136 return null; 137 } 138 139 /** 140 * Set the friendly Bluetooth name of this device. 141 * 142 * This name is visible to remote Bluetooth devices. The Bluetooth Service 143 * is responsible for persisting this name. 144 * 145 * @param name the name to set 146 * @return true, if the name was successfully set. False otherwise. 147 */ 148 public boolean setName(String name) { 149 try { 150 return mService.setName(name); 151 } catch (RemoteException e) {Log.e(TAG, "", e);} 152 return false; 153 } 154 155 public String getMajorClass() { 156 try { 157 return mService.getMajorClass(); 158 } catch (RemoteException e) {Log.e(TAG, "", e);} 159 return null; 160 } 161 public String getMinorClass() { 162 try { 163 return mService.getMinorClass(); 164 } catch (RemoteException e) {Log.e(TAG, "", e);} 165 return null; 166 } 167 public String getVersion() { 168 try { 169 return mService.getVersion(); 170 } catch (RemoteException e) {Log.e(TAG, "", e);} 171 return null; 172 } 173 public String getRevision() { 174 try { 175 return mService.getRevision(); 176 } catch (RemoteException e) {Log.e(TAG, "", e);} 177 return null; 178 } 179 public String getManufacturer() { 180 try { 181 return mService.getManufacturer(); 182 } catch (RemoteException e) {Log.e(TAG, "", e);} 183 return null; 184 } 185 public String getCompany() { 186 try { 187 return mService.getCompany(); 188 } catch (RemoteException e) {Log.e(TAG, "", e);} 189 return null; 190 } 191 192 public int getMode() { 193 try { 194 return mService.getMode(); 195 } catch (RemoteException e) {Log.e(TAG, "", e);} 196 return MODE_UNKNOWN; 197 } 198 public void setMode(int mode) { 199 try { 200 mService.setMode(mode); 201 } catch (RemoteException e) {Log.e(TAG, "", e);} 202 } 203 204 public int getDiscoverableTimeout() { 205 try { 206 return mService.getDiscoverableTimeout(); 207 } catch (RemoteException e) {Log.e(TAG, "", e);} 208 return -1; 209 } 210 public void setDiscoverableTimeout(int timeout) { 211 try { 212 mService.setDiscoverableTimeout(timeout); 213 } catch (RemoteException e) {Log.e(TAG, "", e);} 214 } 215 216 public boolean startDiscovery() { 217 return startDiscovery(true); 218 } 219 public boolean startDiscovery(boolean resolveNames) { 220 try { 221 return mService.startDiscovery(resolveNames); 222 } catch (RemoteException e) {Log.e(TAG, "", e);} 223 return false; 224 } 225 226 public void cancelDiscovery() { 227 try { 228 mService.cancelDiscovery(); 229 } catch (RemoteException e) {Log.e(TAG, "", e);} 230 } 231 232 public boolean isDiscovering() { 233 try { 234 return mService.isDiscovering(); 235 } catch (RemoteException e) {Log.e(TAG, "", e);} 236 return false; 237 } 238 239 public boolean startPeriodicDiscovery() { 240 try { 241 return mService.startPeriodicDiscovery(); 242 } catch (RemoteException e) {Log.e(TAG, "", e);} 243 return false; 244 } 245 public boolean stopPeriodicDiscovery() { 246 try { 247 return mService.stopPeriodicDiscovery(); 248 } catch (RemoteException e) {Log.e(TAG, "", e);} 249 return false; 250 } 251 public boolean isPeriodicDiscovery() { 252 try { 253 return mService.isPeriodicDiscovery(); 254 } catch (RemoteException e) {Log.e(TAG, "", e);} 255 return false; 256 } 257 258 public String[] listRemoteDevices() { 259 try { 260 return mService.listRemoteDevices(); 261 } catch (RemoteException e) {Log.e(TAG, "", e);} 262 return null; 263 } 264 265 /** 266 * List remote devices that have a low level (ACL) connection. 267 * 268 * RFCOMM, SDP and L2CAP are all built on ACL connections. Devices can have 269 * an ACL connection even when not paired - this is common for SDP queries 270 * or for in-progress pairing requests. 271 * 272 * In most cases you probably want to test if a higher level protocol is 273 * connected, rather than testing ACL connections. 274 * 275 * @return bluetooth hardware addresses of remote devices with a current 276 * ACL connection. Array size is 0 if no devices have a 277 * connection. Null on error. 278 */ 279 public String[] listAclConnections() { 280 try { 281 return mService.listAclConnections(); 282 } catch (RemoteException e) {Log.e(TAG, "", e);} 283 return null; 284 } 285 286 /** 287 * Check if a specified remote device has a low level (ACL) connection. 288 * 289 * RFCOMM, SDP and L2CAP are all built on ACL connections. Devices can have 290 * an ACL connection even when not paired - this is common for SDP queries 291 * or for in-progress pairing requests. 292 * 293 * In most cases you probably want to test if a higher level protocol is 294 * connected, rather than testing ACL connections. 295 * 296 * @param address the Bluetooth hardware address you want to check. 297 * @return true if there is an ACL connection, false otherwise and on 298 * error. 299 */ 300 public boolean isAclConnected(String address) { 301 try { 302 return mService.isAclConnected(address); 303 } catch (RemoteException e) {Log.e(TAG, "", e);} 304 return false; 305 } 306 307 /** 308 * Perform a low level (ACL) disconnection of a remote device. 309 * 310 * This forcably disconnects the ACL layer connection to a remote device, 311 * which will cause all RFCOMM, SDP and L2CAP connections to this remote 312 * device to close. 313 * 314 * @param address the Bluetooth hardware address you want to disconnect. 315 * @return true if the device was disconnected, false otherwise and on 316 * error. 317 */ 318 public boolean disconnectRemoteDeviceAcl(String address) { 319 try { 320 return mService.disconnectRemoteDeviceAcl(address); 321 } catch (RemoteException e) {Log.e(TAG, "", e);} 322 return false; 323 } 324 325 /** 326 * Create a bonding with a remote bluetooth device. 327 * 328 * This is an asynchronous call. BluetoothIntent.BONDING_CREATED_ACTION 329 * will be broadcast if and when the remote device is successfully bonded. 330 * 331 * @param address the remote device Bluetooth address. 332 * @return false if we cannot create a bonding to that device, true if 333 * there were no problems beginning the bonding process. 334 */ 335 public boolean createBonding(String address) { 336 return createBonding(address, null); 337 } 338 339 /** 340 * Create a bonding with a remote bluetooth device. 341 * 342 * This is an asynchronous call. onCreateBondingResult() of your callback 343 * will be called when the call is complete, with either RESULT_SUCCESS or 344 * RESULT_FAILURE. 345 * 346 * In addition to the callback, BluetoothIntent.BONDING_CREATED_ACTION will 347 * be broadcast if the remote device is successfully bonded. 348 * 349 * @param address The remote device Bluetooth address. 350 * @param callback Your callback, null is ok. 351 * @return true if your callback was successfully registered, or false if 352 * there was an error, implying your callback will never be called. 353 */ 354 public boolean createBonding(String address, IBluetoothDeviceCallback callback) { 355 try { 356 return mService.createBonding(address, callback); 357 } catch (RemoteException e) {Log.e(TAG, "", e);} 358 return false; 359 } 360 361 public boolean cancelBondingProcess(String address) { 362 try { 363 return mService.cancelBondingProcess(address); 364 } catch (RemoteException e) {Log.e(TAG, "", e);} 365 return false; 366 } 367 368 /** 369 * List remote devices that are bonded (paired) to the local device. 370 * 371 * Bonding (pairing) is the process by which the user enters a pin code for 372 * the device, which generates a shared link key, allowing for 373 * authentication and encryption of future connections. In Android we 374 * require bonding before RFCOMM or SCO connections can be made to a remote 375 * device. 376 * 377 * This function lists which remote devices we have a link key for. It does 378 * not cause any RF transmission, and does not check if the remote device 379 * still has it's link key with us. If the other side no longer has its 380 * link key then the RFCOMM or SCO connection attempt will result in an 381 * error. 382 * 383 * This function does not check if the remote device is in range. 384 * 385 * @return bluetooth hardware addresses of remote devices that are 386 * bonded. Array size is 0 if no devices are bonded. Null on error. 387 */ 388 public String[] listBondings() { 389 try { 390 return mService.listBondings(); 391 } catch (RemoteException e) {Log.e(TAG, "", e);} 392 return null; 393 } 394 395 /** 396 * Check if a remote device is bonded (paired) to the local device. 397 * 398 * Bonding (pairing) is the process by which the user enters a pin code for 399 * the device, which generates a shared link key, allowing for 400 * authentication and encryption of future connections. In Android we 401 * require bonding before RFCOMM or SCO connections can be made to a remote 402 * device. 403 * 404 * This function checks if we have a link key with the remote device. It 405 * does not cause any RF transmission, and does not check if the remote 406 * device still has it's link key with us. If the other side no longer has 407 * a link key then the RFCOMM or SCO connection attempt will result in an 408 * error. 409 * 410 * This function does not check if the remote device is in range. 411 * 412 * @param address Bluetooth hardware address of the remote device to check. 413 * @return true if bonded, false otherwise and on error. 414 */ 415 public boolean hasBonding(String address) { 416 try { 417 return mService.hasBonding(address); 418 } catch (RemoteException e) {Log.e(TAG, "", e);} 419 return false; 420 } 421 422 public boolean removeBonding(String address) { 423 try { 424 return mService.removeBonding(address); 425 } catch (RemoteException e) {Log.e(TAG, "", e);} 426 return false; 427 } 428 429 public String getRemoteName(String address) { 430 try { 431 return mService.getRemoteName(address); 432 } catch (RemoteException e) {Log.e(TAG, "", e);} 433 return null; 434 } 435 436 public String getRemoteAlias(String address) { 437 try { 438 return mService.getRemoteAlias(address); 439 } catch (RemoteException e) {Log.e(TAG, "", e);} 440 return null; 441 } 442 public boolean setRemoteAlias(String address, String alias) { 443 try { 444 return mService.setRemoteAlias(address, alias); 445 } catch (RemoteException e) {Log.e(TAG, "", e);} 446 return false; 447 } 448 public boolean clearRemoteAlias(String address) { 449 try { 450 return mService.clearRemoteAlias(address); 451 } catch (RemoteException e) {Log.e(TAG, "", e);} 452 return false; 453 } 454 public String getRemoteVersion(String address) { 455 try { 456 return mService.getRemoteVersion(address); 457 } catch (RemoteException e) {Log.e(TAG, "", e);} 458 return null; 459 } 460 public String getRemoteRevision(String address) { 461 try { 462 return mService.getRemoteRevision(address); 463 } catch (RemoteException e) {Log.e(TAG, "", e);} 464 return null; 465 } 466 public String getRemoteManufacturer(String address) { 467 try { 468 return mService.getRemoteManufacturer(address); 469 } catch (RemoteException e) {Log.e(TAG, "", e);} 470 return null; 471 } 472 public String getRemoteCompany(String address) { 473 try { 474 return mService.getRemoteCompany(address); 475 } catch (RemoteException e) {Log.e(TAG, "", e);} 476 return null; 477 } 478 public String getRemoteMajorClass(String address) { 479 try { 480 return mService.getRemoteMajorClass(address); 481 } catch (RemoteException e) {Log.e(TAG, "", e);} 482 return null; 483 } 484 public String getRemoteMinorClass(String address) { 485 try { 486 return mService.getRemoteMinorClass(address); 487 } catch (RemoteException e) {Log.e(TAG, "", e);} 488 return null; 489 } 490 public String[] getRemoteServiceClasses(String address) { 491 try { 492 return mService.getRemoteServiceClasses(address); 493 } catch (RemoteException e) {Log.e(TAG, "", e);} 494 return null; 495 } 496 497 /** 498 * Returns the RFCOMM channel associated with the 16-byte UUID on 499 * the remote Bluetooth address. 500 * 501 * Performs a SDP ServiceSearchAttributeRequest transaction. The provided 502 * uuid is verified in the returned record. If there was a problem, or the 503 * specified uuid does not exist, -1 is returned. 504 */ 505 public boolean getRemoteServiceChannel(String address, short uuid16, 506 IBluetoothDeviceCallback callback) { 507 try { 508 return mService.getRemoteServiceChannel(address, uuid16, callback); 509 } catch (RemoteException e) {Log.e(TAG, "", e);} 510 return false; 511 } 512 513 public int getRemoteClass(String address) { 514 try { 515 return mService.getRemoteClass(address); 516 } catch (RemoteException e) {Log.e(TAG, "", e);} 517 return DeviceClass.CLASS_UNKNOWN; 518 } 519 public byte[] getRemoteFeatures(String address) { 520 try { 521 return mService.getRemoteFeatures(address); 522 } catch (RemoteException e) {Log.e(TAG, "", e);} 523 return null; 524 } 525 public String lastSeen(String address) { 526 try { 527 return mService.lastSeen(address); 528 } catch (RemoteException e) {Log.e(TAG, "", e);} 529 return null; 530 } 531 public String lastUsed(String address) { 532 try { 533 return mService.lastUsed(address); 534 } catch (RemoteException e) {Log.e(TAG, "", e);} 535 return null; 536 } 537 538 public boolean setPin(String address, byte[] pin) { 539 try { 540 return mService.setPin(address, pin); 541 } catch (RemoteException e) {Log.e(TAG, "", e);} 542 return false; 543 } 544 public boolean cancelPin(String address) { 545 try { 546 return mService.cancelPin(address); 547 } catch (RemoteException e) {Log.e(TAG, "", e);} 548 return false; 549 } 550 551 /** 552 * Check that a pin is valid and convert to byte array. 553 * 554 * Bluetooth pin's are 1 to 16 bytes of UTF8 characters. 555 * @param pin pin as java String 556 * @return the pin code as a UTF8 byte array, or null if it is an invalid 557 * Bluetooth pin. 558 */ 559 public static byte[] convertPinToBytes(String pin) { 560 if (pin == null) { 561 return null; 562 } 563 byte[] pinBytes; 564 try { 565 pinBytes = pin.getBytes("UTF8"); 566 } catch (UnsupportedEncodingException uee) { 567 Log.e(TAG, "UTF8 not supported?!?"); // this should not happen 568 return null; 569 } 570 if (pinBytes.length <= 0 || pinBytes.length > 16) { 571 return null; 572 } 573 return pinBytes; 574 } 575 576 577 /* Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */ 578 private static final int ADDRESS_LENGTH = 17; 579 public static boolean checkBluetoothAddress(String address) { 580 if (address == null || address.length() != ADDRESS_LENGTH) { 581 return false; 582 } 583 for (int i = 0; i < ADDRESS_LENGTH; i++) { 584 char c = address.charAt(i); 585 switch (i % 3) { 586 case 0: 587 case 1: 588 if (Character.digit(c, 16) != -1) { 589 break; // hex character, OK 590 } 591 return false; 592 case 2: 593 if (c == ':') { 594 break; // OK 595 } 596 return false; 597 } 598 } 599 return true; 600 } 601} 602