blob: abf08cbfc7658e7f7ee0a56303af19bdb0010fc7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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 {
The Android Open Source Project10592532009-03-18 17:39:46 -070034
35 public static final int BLUETOOTH_STATE_OFF = 0;
36 public static final int BLUETOOTH_STATE_TURNING_ON = 1;
37 public static final int BLUETOOTH_STATE_ON = 2;
38 public static final int BLUETOOTH_STATE_TURNING_OFF = 3;
39
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 /** Inquiry scan and page scan are both off.
41 * Device is neither discoverable nor connectable */
42 public static final int SCAN_MODE_NONE = 0;
43 /** Page scan is on, inquiry scan is off.
44 * Device is connectable, but not discoverable */
45 public static final int SCAN_MODE_CONNECTABLE = 1;
46 /** Page scan and inquiry scan are on.
47 * Device is connectable and discoverable */
48 public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3;
49
50 public static final int RESULT_FAILURE = -1;
51 public static final int RESULT_SUCCESS = 0;
52
53 /** We do not have a link key for the remote device, and are therefore not
54 * bonded */
55 public static final int BOND_NOT_BONDED = 0;
56 /** We have a link key for the remote device, and are probably bonded. */
57 public static final int BOND_BONDED = 1;
58 /** We are currently attempting bonding */
59 public static final int BOND_BONDING = 2;
60
61 //TODO: Unify these result codes in BluetoothResult or BluetoothError
62 /** A bond attempt failed because pins did not match, or remote device did
63 * not respond to pin request in time */
64 public static final int UNBOND_REASON_AUTH_FAILED = 1;
65 /** A bond attempt failed because the other side explicilty rejected
66 * bonding */
67 public static final int UNBOND_REASON_AUTH_REJECTED = 2;
68 /** A bond attempt failed because we canceled the bonding process */
69 public static final int UNBOND_REASON_AUTH_CANCELED = 3;
70 /** A bond attempt failed because we could not contact the remote device */
71 public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
72 /** A bond attempt failed because a discovery is in progress */
73 public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
74 /** An existing bond was explicitly revoked */
75 public static final int UNBOND_REASON_REMOVED = 6;
76
77 private static final String TAG = "BluetoothDevice";
78
79 private final IBluetoothDevice mService;
80 /**
81 * @hide - hide this because it takes a parameter of type
82 * IBluetoothDevice, which is a System private class.
83 * Also note that Context.getSystemService is a factory that
84 * returns a BlueToothDevice. That is the right way to get
85 * a BluetoothDevice.
86 */
87 public BluetoothDevice(IBluetoothDevice service) {
88 mService = service;
89 }
90
91 /**
The Android Open Source Project10592532009-03-18 17:39:46 -070092 * Is Bluetooth currently turned on.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 *
94 * @return true if Bluetooth enabled, false otherwise.
95 */
96 public boolean isEnabled() {
97 try {
98 return mService.isEnabled();
99 } catch (RemoteException e) {Log.e(TAG, "", e);}
100 return false;
101 }
102
103 /**
The Android Open Source Project10592532009-03-18 17:39:46 -0700104 * Get the current state of Bluetooth.
105 *
106 * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR.
107 */
108 public int getBluetoothState() {
109 try {
110 return mService.getBluetoothState();
111 } catch (RemoteException e) {Log.e(TAG, "", e);}
112 return BluetoothError.ERROR;
113 }
114
115 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 * Enable the Bluetooth device.
117 * Turn on the underlying hardware.
The Android Open Source Project10592532009-03-18 17:39:46 -0700118 * This is an asynchronous call,
119 * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if
120 * and when the device is sucessfully enabled.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 * @return false if we cannot enable the Bluetooth device. True does not
122 * imply the device was enabled, it only implies that so far there were no
123 * problems.
124 */
125 public boolean enable() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 try {
The Android Open Source Project10592532009-03-18 17:39:46 -0700127 return mService.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 } catch (RemoteException e) {Log.e(TAG, "", e);}
129 return false;
130 }
131
132 /**
133 * Disable the Bluetooth device.
134 * This turns off the underlying hardware.
135 *
136 * @return true if successful, false otherwise.
137 */
138 public boolean disable() {
139 try {
The Android Open Source Project10592532009-03-18 17:39:46 -0700140 return mService.disable(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 } catch (RemoteException e) {Log.e(TAG, "", e);}
142 return false;
143 }
144
145 public String getAddress() {
146 try {
147 return mService.getAddress();
148 } catch (RemoteException e) {Log.e(TAG, "", e);}
149 return null;
150 }
151
152 /**
153 * Get the friendly Bluetooth name of this device.
154 *
155 * This name is visible to remote Bluetooth devices. Currently it is only
156 * possible to retrieve the Bluetooth name when Bluetooth is enabled.
157 *
158 * @return the Bluetooth name, or null if there was a problem.
159 */
160 public String getName() {
161 try {
162 return mService.getName();
163 } catch (RemoteException e) {Log.e(TAG, "", e);}
164 return null;
165 }
166
167 /**
168 * Set the friendly Bluetooth name of this device.
169 *
170 * This name is visible to remote Bluetooth devices. The Bluetooth Service
171 * is responsible for persisting this name.
172 *
173 * @param name the name to set
174 * @return true, if the name was successfully set. False otherwise.
175 */
176 public boolean setName(String name) {
177 try {
178 return mService.setName(name);
179 } catch (RemoteException e) {Log.e(TAG, "", e);}
180 return false;
181 }
182
183 public String getVersion() {
184 try {
185 return mService.getVersion();
186 } catch (RemoteException e) {Log.e(TAG, "", e);}
187 return null;
188 }
189 public String getRevision() {
190 try {
191 return mService.getRevision();
192 } catch (RemoteException e) {Log.e(TAG, "", e);}
193 return null;
194 }
195 public String getManufacturer() {
196 try {
197 return mService.getManufacturer();
198 } catch (RemoteException e) {Log.e(TAG, "", e);}
199 return null;
200 }
201 public String getCompany() {
202 try {
203 return mService.getCompany();
204 } catch (RemoteException e) {Log.e(TAG, "", e);}
205 return null;
206 }
207
208 /**
209 * Get the current scan mode.
210 * Used to determine if the local device is connectable and/or discoverable
211 * @return Scan mode, one of SCAN_MODE_* or an error code
212 */
213 public int getScanMode() {
214 try {
215 return mService.getScanMode();
216 } catch (RemoteException e) {Log.e(TAG, "", e);}
217 return BluetoothError.ERROR_IPC;
218 }
219
220 /**
221 * Set the current scan mode.
222 * Used to make the local device connectable and/or discoverable
223 * @param scanMode One of SCAN_MODE_*
224 */
225 public void setScanMode(int scanMode) {
226 try {
227 mService.setScanMode(scanMode);
228 } catch (RemoteException e) {Log.e(TAG, "", e);}
229 }
230
231 public int getDiscoverableTimeout() {
232 try {
233 return mService.getDiscoverableTimeout();
234 } catch (RemoteException e) {Log.e(TAG, "", e);}
235 return -1;
236 }
237 public void setDiscoverableTimeout(int timeout) {
238 try {
239 mService.setDiscoverableTimeout(timeout);
240 } catch (RemoteException e) {Log.e(TAG, "", e);}
241 }
242
243 public boolean startDiscovery() {
244 return startDiscovery(true);
245 }
246 public boolean startDiscovery(boolean resolveNames) {
247 try {
248 return mService.startDiscovery(resolveNames);
249 } catch (RemoteException e) {Log.e(TAG, "", e);}
250 return false;
251 }
252
253 public void cancelDiscovery() {
254 try {
255 mService.cancelDiscovery();
256 } catch (RemoteException e) {Log.e(TAG, "", e);}
257 }
258
259 public boolean isDiscovering() {
260 try {
261 return mService.isDiscovering();
262 } catch (RemoteException e) {Log.e(TAG, "", e);}
263 return false;
264 }
265
266 public boolean startPeriodicDiscovery() {
267 try {
268 return mService.startPeriodicDiscovery();
269 } catch (RemoteException e) {Log.e(TAG, "", e);}
270 return false;
271 }
272 public boolean stopPeriodicDiscovery() {
273 try {
274 return mService.stopPeriodicDiscovery();
275 } catch (RemoteException e) {Log.e(TAG, "", e);}
276 return false;
277 }
278 public boolean isPeriodicDiscovery() {
279 try {
280 return mService.isPeriodicDiscovery();
281 } catch (RemoteException e) {Log.e(TAG, "", e);}
282 return false;
283 }
284
285 public String[] listRemoteDevices() {
286 try {
287 return mService.listRemoteDevices();
288 } catch (RemoteException e) {Log.e(TAG, "", e);}
289 return null;
290 }
291
292 /**
293 * List remote devices that have a low level (ACL) connection.
294 *
295 * RFCOMM, SDP and L2CAP are all built on ACL connections. Devices can have
296 * an ACL connection even when not paired - this is common for SDP queries
297 * or for in-progress pairing requests.
298 *
299 * In most cases you probably want to test if a higher level protocol is
300 * connected, rather than testing ACL connections.
301 *
302 * @return bluetooth hardware addresses of remote devices with a current
303 * ACL connection. Array size is 0 if no devices have a
304 * connection. Null on error.
305 */
306 public String[] listAclConnections() {
307 try {
308 return mService.listAclConnections();
309 } catch (RemoteException e) {Log.e(TAG, "", e);}
310 return null;
311 }
312
313 /**
314 * Check if a specified remote device has a low level (ACL) connection.
315 *
316 * RFCOMM, SDP and L2CAP are all built on ACL connections. Devices can have
317 * an ACL connection even when not paired - this is common for SDP queries
318 * or for in-progress pairing requests.
319 *
320 * In most cases you probably want to test if a higher level protocol is
321 * connected, rather than testing ACL connections.
322 *
323 * @param address the Bluetooth hardware address you want to check.
324 * @return true if there is an ACL connection, false otherwise and on
325 * error.
326 */
327 public boolean isAclConnected(String address) {
328 try {
329 return mService.isAclConnected(address);
330 } catch (RemoteException e) {Log.e(TAG, "", e);}
331 return false;
332 }
333
334 /**
335 * Perform a low level (ACL) disconnection of a remote device.
336 *
337 * This forcably disconnects the ACL layer connection to a remote device,
338 * which will cause all RFCOMM, SDP and L2CAP connections to this remote
339 * device to close.
340 *
341 * @param address the Bluetooth hardware address you want to disconnect.
342 * @return true if the device was disconnected, false otherwise and on
343 * error.
344 */
345 public boolean disconnectRemoteDeviceAcl(String address) {
346 try {
347 return mService.disconnectRemoteDeviceAcl(address);
348 } catch (RemoteException e) {Log.e(TAG, "", e);}
349 return false;
350 }
351
352 /**
353 * Create a bonding with a remote bluetooth device.
354 *
355 * This is an asynchronous call. The result of this bonding attempt can be
356 * observed through BluetoothIntent.BOND_STATE_CHANGED_ACTION intents.
357 *
358 * @param address the remote device Bluetooth address.
359 * @return false If there was an immediate problem creating the bonding,
360 * true otherwise.
361 */
362 public boolean createBond(String address) {
363 try {
364 return mService.createBond(address);
365 } catch (RemoteException e) {Log.e(TAG, "", e);}
366 return false;
367 }
368
369 /**
370 * Cancel an in-progress bonding request started with createBond.
371 */
372 public boolean cancelBondProcess(String address) {
373 try {
374 return mService.cancelBondProcess(address);
375 } catch (RemoteException e) {Log.e(TAG, "", e);}
376 return false;
377 }
378
379 /**
380 * Remove an already exisiting bonding (delete the link key).
381 */
382 public boolean removeBond(String address) {
383 try {
384 return mService.removeBond(address);
385 } catch (RemoteException e) {Log.e(TAG, "", e);}
386 return false;
387 }
388
389 /**
390 * List remote devices that are bonded (paired) to the local device.
391 *
392 * Bonding (pairing) is the process by which the user enters a pin code for
393 * the device, which generates a shared link key, allowing for
394 * authentication and encryption of future connections. In Android we
395 * require bonding before RFCOMM or SCO connections can be made to a remote
396 * device.
397 *
398 * This function lists which remote devices we have a link key for. It does
399 * not cause any RF transmission, and does not check if the remote device
400 * still has it's link key with us. If the other side no longer has its
401 * link key then the RFCOMM or SCO connection attempt will result in an
402 * error.
403 *
404 * This function does not check if the remote device is in range.
405 *
406 * Remote devices that have an in-progress bonding attempt are not
407 * returned.
408 *
409 * @return bluetooth hardware addresses of remote devices that are
410 * bonded. Array size is 0 if no devices are bonded. Null on error.
411 */
412 public String[] listBonds() {
413 try {
414 return mService.listBonds();
415 } catch (RemoteException e) {Log.e(TAG, "", e);}
416 return null;
417 }
418
419 /**
420 * Get the bonding state of a remote device.
421 *
422 * Result is one of:
423 * BluetoothError.*
424 * BOND_*
425 *
426 * @param address Bluetooth hardware address of the remote device to check.
427 * @return Result code
428 */
429 public int getBondState(String address) {
430 try {
431 return mService.getBondState(address);
432 } catch (RemoteException e) {Log.e(TAG, "", e);}
433 return BluetoothError.ERROR_IPC;
434 }
435
436 public String getRemoteName(String address) {
437 try {
438 return mService.getRemoteName(address);
439 } catch (RemoteException e) {Log.e(TAG, "", e);}
440 return null;
441 }
442
443 public String getRemoteVersion(String address) {
444 try {
445 return mService.getRemoteVersion(address);
446 } catch (RemoteException e) {Log.e(TAG, "", e);}
447 return null;
448 }
449 public String getRemoteRevision(String address) {
450 try {
451 return mService.getRemoteRevision(address);
452 } catch (RemoteException e) {Log.e(TAG, "", e);}
453 return null;
454 }
455 public String getRemoteManufacturer(String address) {
456 try {
457 return mService.getRemoteManufacturer(address);
458 } catch (RemoteException e) {Log.e(TAG, "", e);}
459 return null;
460 }
461 public String getRemoteCompany(String address) {
462 try {
463 return mService.getRemoteCompany(address);
464 } catch (RemoteException e) {Log.e(TAG, "", e);}
465 return null;
466 }
467
468 /**
469 * Returns the RFCOMM channel associated with the 16-byte UUID on
470 * the remote Bluetooth address.
471 *
472 * Performs a SDP ServiceSearchAttributeRequest transaction. The provided
473 * uuid is verified in the returned record. If there was a problem, or the
474 * specified uuid does not exist, -1 is returned.
475 */
476 public boolean getRemoteServiceChannel(String address, short uuid16,
477 IBluetoothDeviceCallback callback) {
478 try {
479 return mService.getRemoteServiceChannel(address, uuid16, callback);
480 } catch (RemoteException e) {Log.e(TAG, "", e);}
481 return false;
482 }
483
484 /**
485 * Get the major, minor and servics classes of a remote device.
486 * These classes are encoded as a 32-bit integer. See BluetoothClass.
487 * @param address remote device
488 * @return 32-bit class suitable for use with BluetoothClass.
489 */
490 public int getRemoteClass(String address) {
491 try {
492 return mService.getRemoteClass(address);
493 } catch (RemoteException e) {Log.e(TAG, "", e);}
494 return BluetoothClass.ERROR;
495 }
496
497 public byte[] getRemoteFeatures(String address) {
498 try {
499 return mService.getRemoteFeatures(address);
500 } catch (RemoteException e) {Log.e(TAG, "", e);}
501 return null;
502 }
503 public String lastSeen(String address) {
504 try {
505 return mService.lastSeen(address);
506 } catch (RemoteException e) {Log.e(TAG, "", e);}
507 return null;
508 }
509 public String lastUsed(String address) {
510 try {
511 return mService.lastUsed(address);
512 } catch (RemoteException e) {Log.e(TAG, "", e);}
513 return null;
514 }
515
516 public boolean setPin(String address, byte[] pin) {
517 try {
518 return mService.setPin(address, pin);
519 } catch (RemoteException e) {Log.e(TAG, "", e);}
520 return false;
521 }
522 public boolean cancelPin(String address) {
523 try {
524 return mService.cancelPin(address);
525 } catch (RemoteException e) {Log.e(TAG, "", e);}
526 return false;
527 }
528
529 /**
530 * Check that a pin is valid and convert to byte array.
531 *
532 * Bluetooth pin's are 1 to 16 bytes of UTF8 characters.
533 * @param pin pin as java String
534 * @return the pin code as a UTF8 byte array, or null if it is an invalid
535 * Bluetooth pin.
536 */
537 public static byte[] convertPinToBytes(String pin) {
538 if (pin == null) {
539 return null;
540 }
541 byte[] pinBytes;
542 try {
543 pinBytes = pin.getBytes("UTF8");
544 } catch (UnsupportedEncodingException uee) {
545 Log.e(TAG, "UTF8 not supported?!?"); // this should not happen
546 return null;
547 }
548 if (pinBytes.length <= 0 || pinBytes.length > 16) {
549 return null;
550 }
551 return pinBytes;
552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553
554 private static final int ADDRESS_LENGTH = 17;
555 /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */
556 public static boolean checkBluetoothAddress(String address) {
557 if (address == null || address.length() != ADDRESS_LENGTH) {
558 return false;
559 }
560 for (int i = 0; i < ADDRESS_LENGTH; i++) {
561 char c = address.charAt(i);
562 switch (i % 3) {
563 case 0:
564 case 1:
565 if (Character.digit(c, 16) != -1) {
566 break; // hex character, OK
567 }
568 return false;
569 case 2:
570 if (c == ':') {
571 break; // OK
572 }
573 return false;
574 }
575 }
576 return true;
577 }
578}