• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.os.IBinder;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.os.ParcelUuid;
25 import android.os.RemoteException;
26 import android.os.ServiceManager;
27 import android.util.Log;
28 
29 import java.io.IOException;
30 import java.io.UnsupportedEncodingException;
31 import java.util.UUID;
32 
33 /**
34  * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
35  * create a connection with the respective device or query information about
36  * it, such as the name, address, class, and bonding state.
37  *
38  * <p>This class is really just a thin wrapper for a Bluetooth hardware
39  * address. Objects of this class are immutable. Operations on this class
40  * are performed on the remote Bluetooth hardware address, using the
41  * {@link BluetoothAdapter} that was used to create this {@link
42  * BluetoothDevice}.
43  *
44  * <p>To get a {@link BluetoothDevice}, use
45  * {@link BluetoothAdapter#getRemoteDevice(String)
46  * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device
47  * of a known MAC address (which you can get through device discovery with
48  * {@link BluetoothAdapter}) or get one from the set of bonded devices
49  * returned by {@link BluetoothAdapter#getBondedDevices()
50  * BluetoothAdapter.getBondedDevices()}. You can then open a
51  * {@link BluetoothSocket} for communication with the remote device, using
52  * {@link #createRfcommSocketToServiceRecord(UUID)}.
53  *
54  * <p class="note"><strong>Note:</strong>
55  * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
56  *
57  * {@see BluetoothAdapter}
58  * {@see BluetoothSocket}
59  */
60 public final class BluetoothDevice implements Parcelable {
61     private static final String TAG = "BluetoothDevice";
62 
63     /**
64      * Sentinel error value for this class. Guaranteed to not equal any other
65      * integer constant in this class. Provided as a convenience for functions
66      * that require a sentinel error value, for example:
67      * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
68      * BluetoothDevice.ERROR)</code>
69      */
70     public static final int ERROR = Integer.MIN_VALUE;
71 
72     /**
73      * Broadcast Action: Remote device discovered.
74      * <p>Sent when a remote device is found during discovery.
75      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
76      * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
77      * {@link #EXTRA_RSSI} if they are available.
78      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
79      */
80      // TODO: Change API to not broadcast RSSI if not available (incoming connection)
81     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
82     public static final String ACTION_FOUND =
83             "android.bluetooth.device.action.FOUND";
84 
85     /**
86      * Broadcast Action: Remote device disappeared.
87      * <p>Sent when a remote device that was found in the last discovery is not
88      * found in the current discovery.
89      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
90      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
91      * @hide
92      */
93     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
94     public static final String ACTION_DISAPPEARED =
95             "android.bluetooth.device.action.DISAPPEARED";
96 
97     /**
98      * Broadcast Action: Bluetooth class of a remote device has changed.
99      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
100      * #EXTRA_CLASS}.
101      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
102      * @see {@link BluetoothClass}
103      */
104     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
105     public static final String ACTION_CLASS_CHANGED =
106             "android.bluetooth.device.action.CLASS_CHANGED";
107 
108     /**
109      * Broadcast Action: Indicates a low level (ACL) connection has been
110      * established with a remote device.
111      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
112      * <p>ACL connections are managed automatically by the Android Bluetooth
113      * stack.
114      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
115      */
116     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
117     public static final String ACTION_ACL_CONNECTED =
118             "android.bluetooth.device.action.ACL_CONNECTED";
119 
120     /**
121      * Broadcast Action: Indicates that a low level (ACL) disconnection has
122      * been requested for a remote device, and it will soon be disconnected.
123      * <p>This is useful for graceful disconnection. Applications should use
124      * this intent as a hint to immediately terminate higher level connections
125      * (RFCOMM, L2CAP, or profile connections) to the remote device.
126      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
127      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
128      */
129     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
130     public static final String ACTION_ACL_DISCONNECT_REQUESTED =
131             "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
132 
133     /**
134      * Broadcast Action: Indicates a low level (ACL) disconnection from a
135      * remote device.
136      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
137      * <p>ACL connections are managed automatically by the Android Bluetooth
138      * stack.
139      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
140      */
141     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
142     public static final String ACTION_ACL_DISCONNECTED =
143             "android.bluetooth.device.action.ACL_DISCONNECTED";
144 
145     /**
146      * Broadcast Action: Indicates the friendly name of a remote device has
147      * been retrieved for the first time, or changed since the last retrieval.
148      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
149      * #EXTRA_NAME}.
150      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
151      */
152     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
153     public static final String ACTION_NAME_CHANGED =
154             "android.bluetooth.device.action.NAME_CHANGED";
155 
156     /**
157      * Broadcast Action: Indicates a change in the bond state of a remote
158      * device. For example, if a device is bonded (paired).
159      * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
160      * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
161      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
162      */
163     // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
164     // contain a hidden extra field EXTRA_REASON with the result code.
165     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
166     public static final String ACTION_BOND_STATE_CHANGED =
167             "android.bluetooth.device.action.BOND_STATE_CHANGED";
168 
169     /**
170      * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
171      * broadcast by this class. It contains the {@link BluetoothDevice} that
172      * the intent applies to.
173      */
174     public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
175 
176     /**
177      * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
178      * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
179      */
180     public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
181 
182     /**
183      * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
184      * Contains the RSSI value of the remote device as reported by the
185      * Bluetooth hardware.
186      */
187     public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
188 
189     /**
190      * Used as an Parcelable {@link BluetoothClass} extra field in {@link
191      * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
192      */
193     public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
194 
195     /**
196      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
197      * Contains the bond state of the remote device.
198      * <p>Possible values are:
199      * {@link #BOND_NONE},
200      * {@link #BOND_BONDING},
201      * {@link #BOND_BONDED}.
202       */
203     public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
204     /**
205      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
206      * Contains the previous bond state of the remote device.
207      * <p>Possible values are:
208      * {@link #BOND_NONE},
209      * {@link #BOND_BONDING},
210      * {@link #BOND_BONDED}.
211       */
212     public static final String EXTRA_PREVIOUS_BOND_STATE =
213             "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
214     /**
215      * Indicates the remote device is not bonded (paired).
216      * <p>There is no shared link key with the remote device, so communication
217      * (if it is allowed at all) will be unauthenticated and unencrypted.
218      */
219     public static final int BOND_NONE = 10;
220     /**
221      * Indicates bonding (pairing) is in progress with the remote device.
222      */
223     public static final int BOND_BONDING = 11;
224     /**
225      * Indicates the remote device is bonded (paired).
226      * <p>A shared link keys exists locally for the remote device, so
227      * communication can be authenticated and encrypted.
228      * <p><i>Being bonded (paired) with a remote device does not necessarily
229      * mean the device is currently connected. It just means that the pending
230      * procedure was completed at some earlier time, and the link key is still
231      * stored locally, ready to use on the next connection.
232      * </i>
233      */
234     public static final int BOND_BONDED = 12;
235 
236     /** @hide */
237     public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
238     /** @hide */
239     public static final String EXTRA_PAIRING_VARIANT =
240             "android.bluetooth.device.extra.PAIRING_VARIANT";
241     /** @hide */
242     public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
243 
244     /**
245      * Broadcast Action: This intent is used to broadcast the {@link UUID}
246      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
247      * has been fetched. This intent is sent only when the UUIDs of the remote
248      * device are requested to be fetched using Service Discovery Protocol
249      * <p> Always contains the extra field {@link #EXTRA_DEVICE}
250      * <p> Always contains the extra filed {@link #EXTRA_UUID}
251      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
252      * @hide
253      */
254     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
255     public static final String ACTION_UUID =
256             "android.bleutooth.device.action.UUID";
257 
258     /**
259      * Broadcast Action: Indicates a failure to retrieve the name of a remote
260      * device.
261      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
262      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
263      * @hide
264      */
265     //TODO: is this actually useful?
266     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
267     public static final String ACTION_NAME_FAILED =
268             "android.bluetooth.device.action.NAME_FAILED";
269 
270     /** @hide */
271     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
272     public static final String ACTION_PAIRING_REQUEST =
273             "android.bluetooth.device.action.PAIRING_REQUEST";
274     /** @hide */
275     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
276     public static final String ACTION_PAIRING_CANCEL =
277             "android.bluetooth.device.action.PAIRING_CANCEL";
278 
279     /** @hide */
280     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
281     public static final String ACTION_CONNECTION_ACCESS_REQUEST =
282             "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
283 
284     /** @hide */
285     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
286     public static final String ACTION_CONNECTION_ACCESS_REPLY =
287             "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
288 
289     /** @hide */
290     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
291     public static final String ACTION_CONNECTION_ACCESS_CANCEL =
292             "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
293 
294     /**
295      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
296      * @hide
297      */
298     public static final String EXTRA_ACCESS_REQUEST_TYPE =
299         "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE";
300 
301     /**@hide*/
302     public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1;
303 
304     /**@hide*/
305     public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
306 
307     /**
308      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
309      * Contains package name to return reply intent to.
310      * @hide
311      */
312     public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME";
313 
314     /**
315      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
316      * Contains class name to return reply intent to.
317      * @hide
318      */
319     public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME";
320 
321     /**
322      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
323      * @hide
324      */
325     public static final String EXTRA_CONNECTION_ACCESS_RESULT =
326         "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
327 
328     /**@hide*/
329     public static final int CONNECTION_ACCESS_YES = 1;
330 
331     /**@hide*/
332     public static final int CONNECTION_ACCESS_NO = 2;
333 
334     /**
335      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents,
336      * Contains boolean to indicate if the allowed response is once-for-all so that
337      * next request will be granted without asking user again.
338      * @hide
339      */
340     public static final String EXTRA_ALWAYS_ALLOWED =
341         "android.bluetooth.device.extra.ALWAYS_ALLOWED";
342 
343     /**
344      * A bond attempt succeeded
345      * @hide
346      */
347     public static final int BOND_SUCCESS = 0;
348 
349     /**
350      * A bond attempt failed because pins did not match, or remote device did
351      * not respond to pin request in time
352      * @hide
353      */
354     public static final int UNBOND_REASON_AUTH_FAILED = 1;
355 
356     /**
357      * A bond attempt failed because the other side explicitly rejected
358      * bonding
359      * @hide
360      */
361     public static final int UNBOND_REASON_AUTH_REJECTED = 2;
362 
363     /**
364      * A bond attempt failed because we canceled the bonding process
365      * @hide
366      */
367     public static final int UNBOND_REASON_AUTH_CANCELED = 3;
368 
369     /**
370      * A bond attempt failed because we could not contact the remote device
371      * @hide
372      */
373     public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
374 
375     /**
376      * A bond attempt failed because a discovery is in progress
377      * @hide
378      */
379     public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
380 
381     /**
382      * A bond attempt failed because of authentication timeout
383      * @hide
384      */
385     public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
386 
387     /**
388      * A bond attempt failed because of repeated attempts
389      * @hide
390      */
391     public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
392 
393     /**
394      * A bond attempt failed because we received an Authentication Cancel
395      * by remote end
396      * @hide
397      */
398     public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
399 
400     /**
401      * An existing bond was explicitly revoked
402      * @hide
403      */
404     public static final int UNBOND_REASON_REMOVED = 9;
405 
406     /**
407      * The user will be prompted to enter a pin
408      * @hide
409      */
410     public static final int PAIRING_VARIANT_PIN = 0;
411 
412     /**
413      * The user will be prompted to enter a passkey
414      * @hide
415      */
416     public static final int PAIRING_VARIANT_PASSKEY = 1;
417 
418     /**
419      * The user will be prompted to confirm the passkey displayed on the screen
420      * @hide
421      */
422     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
423 
424     /**
425      * The user will be prompted to accept or deny the incoming pairing request
426      * @hide
427      */
428     public static final int PAIRING_VARIANT_CONSENT = 3;
429 
430     /**
431      * The user will be prompted to enter the passkey displayed on remote device
432      * This is used for Bluetooth 2.1 pairing.
433      * @hide
434      */
435     public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
436 
437     /**
438      * The user will be prompted to enter the PIN displayed on remote device.
439      * This is used for Bluetooth 2.0 pairing.
440      * @hide
441      */
442     public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
443 
444     /**
445      * The user will be prompted to accept or deny the OOB pairing request
446      * @hide
447      */
448     public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
449 
450     /**
451      * Used as an extra field in {@link #ACTION_UUID} intents,
452      * Contains the {@link android.os.ParcelUuid}s of the remote device which
453      * is a parcelable version of {@link UUID}.
454      * @hide
455      */
456     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
457 
458     /**
459      * Lazy initialization. Guaranteed final after first object constructed, or
460      * getService() called.
461      * TODO: Unify implementation of sService amongst BluetoothFoo API's
462      */
463     private static IBluetooth sService;
464 
465     private final String mAddress;
466 
getService()467     /*package*/ static IBluetooth getService() {
468         synchronized (BluetoothDevice.class) {
469             if (sService == null) {
470                 IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
471                 if (b == null) {
472                     throw new RuntimeException("Bluetooth service not available");
473                 }
474                 sService = IBluetooth.Stub.asInterface(b);
475             }
476         }
477         return sService;
478     }
479 
480     /**
481      * Create a new BluetoothDevice
482      * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
483      * and is validated in this constructor.
484      * @param address valid Bluetooth MAC address
485      * @throws RuntimeException Bluetooth is not available on this platform
486      * @throws IllegalArgumentException address is invalid
487      * @hide
488      */
BluetoothDevice(String address)489     /*package*/ BluetoothDevice(String address) {
490         getService();  // ensures sService is initialized
491         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
492             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
493         }
494 
495         mAddress = address;
496     }
497 
498     @Override
equals(Object o)499     public boolean equals(Object o) {
500         if (o instanceof BluetoothDevice) {
501             return mAddress.equals(((BluetoothDevice)o).getAddress());
502         }
503         return false;
504     }
505 
506     @Override
hashCode()507     public int hashCode() {
508         return mAddress.hashCode();
509     }
510 
511     /**
512      * Returns a string representation of this BluetoothDevice.
513      * <p>Currently this is the Bluetooth hardware address, for example
514      * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
515      * if you explicitly require the Bluetooth hardware address in case the
516      * {@link #toString} representation changes in the future.
517      * @return string representation of this BluetoothDevice
518      */
519     @Override
toString()520     public String toString() {
521         return mAddress;
522     }
523 
describeContents()524     public int describeContents() {
525         return 0;
526     }
527 
528     public static final Parcelable.Creator<BluetoothDevice> CREATOR =
529             new Parcelable.Creator<BluetoothDevice>() {
530         public BluetoothDevice createFromParcel(Parcel in) {
531             return new BluetoothDevice(in.readString());
532         }
533         public BluetoothDevice[] newArray(int size) {
534             return new BluetoothDevice[size];
535         }
536     };
537 
writeToParcel(Parcel out, int flags)538     public void writeToParcel(Parcel out, int flags) {
539         out.writeString(mAddress);
540     }
541 
542     /**
543      * Returns the hardware address of this BluetoothDevice.
544      * <p> For example, "00:11:22:AA:BB:CC".
545      * @return Bluetooth hardware address as string
546      */
getAddress()547     public String getAddress() {
548         return mAddress;
549     }
550 
551     /**
552      * Get the friendly Bluetooth name of the remote device.
553      *
554      * <p>The local adapter will automatically retrieve remote names when
555      * performing a device scan, and will cache them. This method just returns
556      * the name for this device from the cache.
557      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
558      *
559      * @return the Bluetooth name, or null if there was a problem.
560      */
getName()561     public String getName() {
562         try {
563             return sService.getRemoteName(mAddress);
564         } catch (RemoteException e) {Log.e(TAG, "", e);}
565         return null;
566     }
567 
568     /**
569      * Get the Bluetooth alias of the remote device.
570      * <p>Alias is the locally modified name of a remote device.
571      *
572      * @return the Bluetooth alias, or null if no alias or there was a problem
573      * @hide
574      */
getAlias()575     public String getAlias() {
576         try {
577             return sService.getRemoteAlias(mAddress);
578         } catch (RemoteException e) {Log.e(TAG, "", e);}
579         return null;
580     }
581 
582     /**
583      * Set the Bluetooth alias of the remote device.
584      * <p>Alias is the locally modified name of a remote device.
585      * <p>This methoid overwrites the alias. The changed
586      * alias is saved in the local storage so that the change
587      * is preserved over power cycle.
588      *
589      * @return true on success, false on error
590      * @hide
591      */
setAlias(String alias)592     public boolean setAlias(String alias) {
593         try {
594             return sService.setRemoteAlias(mAddress, alias);
595         } catch (RemoteException e) {Log.e(TAG, "", e);}
596         return false;
597     }
598 
599     /**
600      * Get the Bluetooth alias of the remote device.
601      * If Alias is null, get the Bluetooth name instead.
602      * @see #getAlias()
603      * @see #getName()
604      *
605      * @return the Bluetooth alias, or null if no alias or there was a problem
606      * @hide
607      */
getAliasName()608     public String getAliasName() {
609         String name = getAlias();
610         if (name == null) {
611             name = getName();
612         }
613         return name;
614     }
615 
616     /**
617      * Start the bonding (pairing) process with the remote device.
618      * <p>This is an asynchronous call, it will return immediately. Register
619      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
620      * the bonding process completes, and its result.
621      * <p>Android system services will handle the necessary user interactions
622      * to confirm and complete the bonding process.
623      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
624      *
625      * @return false on immediate error, true if bonding will begin
626      * @hide
627      */
createBond()628     public boolean createBond() {
629         try {
630             return sService.createBond(mAddress);
631         } catch (RemoteException e) {Log.e(TAG, "", e);}
632         return false;
633     }
634 
635     /**
636      * Start the bonding (pairing) process with the remote device using the
637      * Out Of Band mechanism.
638      *
639      * <p>This is an asynchronous call, it will return immediately. Register
640      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
641      * the bonding process completes, and its result.
642      *
643      * <p>Android system services will handle the necessary user interactions
644      * to confirm and complete the bonding process.
645      *
646      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
647      *
648      * @param hash - Simple Secure pairing hash
649      * @param randomizer - The random key obtained using OOB
650      * @return false on immediate error, true if bonding will begin
651      *
652      * @hide
653      */
createBondOutOfBand(byte[] hash, byte[] randomizer)654     public boolean createBondOutOfBand(byte[] hash, byte[] randomizer) {
655         try {
656             return sService.createBondOutOfBand(mAddress, hash, randomizer);
657         } catch (RemoteException e) {Log.e(TAG, "", e);}
658         return false;
659     }
660 
661     /**
662      * Set the Out Of Band data for a remote device to be used later
663      * in the pairing mechanism. Users can obtain this data through other
664      * trusted channels
665      *
666      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
667      *
668      * @param hash Simple Secure pairing hash
669      * @param randomizer The random key obtained using OOB
670      * @return false on error; true otherwise
671      *
672      * @hide
673      */
setDeviceOutOfBandData(byte[] hash, byte[] randomizer)674     public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
675       try {
676         return sService.setDeviceOutOfBandData(mAddress, hash, randomizer);
677       } catch (RemoteException e) {Log.e(TAG, "", e);}
678       return false;
679     }
680 
681     /**
682      * Cancel an in-progress bonding request started with {@link #createBond}.
683      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
684      *
685      * @return true on success, false on error
686      * @hide
687      */
cancelBondProcess()688     public boolean cancelBondProcess() {
689         try {
690             return sService.cancelBondProcess(mAddress);
691         } catch (RemoteException e) {Log.e(TAG, "", e);}
692         return false;
693     }
694 
695     /**
696      * Remove bond (pairing) with the remote device.
697      * <p>Delete the link key associated with the remote device, and
698      * immediately terminate connections to that device that require
699      * authentication and encryption.
700      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
701      *
702      * @return true on success, false on error
703      * @hide
704      */
removeBond()705     public boolean removeBond() {
706         try {
707             return sService.removeBond(mAddress);
708         } catch (RemoteException e) {Log.e(TAG, "", e);}
709         return false;
710     }
711 
712     /**
713      * Get the bond state of the remote device.
714      * <p>Possible values for the bond state are:
715      * {@link #BOND_NONE},
716      * {@link #BOND_BONDING},
717      * {@link #BOND_BONDED}.
718      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
719      *
720      * @return the bond state
721      */
getBondState()722     public int getBondState() {
723         try {
724             return sService.getBondState(mAddress);
725         } catch (RemoteException e) {Log.e(TAG, "", e);}
726         return BOND_NONE;
727     }
728 
729     /**
730      * Get the Bluetooth class of the remote device.
731      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
732      *
733      * @return Bluetooth class object, or null on error
734      */
getBluetoothClass()735     public BluetoothClass getBluetoothClass() {
736         try {
737             int classInt = sService.getRemoteClass(mAddress);
738             if (classInt == BluetoothClass.ERROR) return null;
739             return new BluetoothClass(classInt);
740         } catch (RemoteException e) {Log.e(TAG, "", e);}
741         return null;
742     }
743 
744     /**
745      * Get trust state of a remote device.
746      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
747      * @hide
748      */
getTrustState()749     public boolean getTrustState() {
750         try {
751             return sService.getTrustState(mAddress);
752         } catch (RemoteException e) {
753             Log.e(TAG, "", e);
754         }
755         return false;
756     }
757 
758     /**
759      * Set trust state for a remote device.
760      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
761      * @param value the trust state value (true or false)
762      * @hide
763      */
setTrust(boolean value)764     public boolean setTrust(boolean value) {
765         try {
766             return sService.setTrust(mAddress, value);
767         } catch (RemoteException e) {
768             Log.e(TAG, "", e);
769         }
770         return false;
771     }
772 
773     /** @hide */
getUuids()774      public ParcelUuid[] getUuids() {
775         try {
776             return sService.getRemoteUuids(mAddress);
777         } catch (RemoteException e) {Log.e(TAG, "", e);}
778         return null;
779     }
780 
781      /**
782       *  Perform a SDP query on the remote device to get the UUIDs
783       *  supported. This API is asynchronous and an Intent is sent,
784       *  with the UUIDs supported by the remote end. If there is an error
785       *  in getting the SDP records or if the process takes a long time,
786       *  an Intent is sent with the UUIDs that is currently present in the
787       *  cache. Clients should use the {@link #getUuids} to get UUIDs
788       *  is SDP is not to be performed.
789       *
790       *  @return False if the sanity check fails, True if the process
791       *               of initiating an ACL connection to the remote device
792       *               was started.
793       *  @hide
794       */
fetchUuidsWithSdp()795      public boolean fetchUuidsWithSdp() {
796         try {
797             return sService.fetchRemoteUuids(mAddress, null, null);
798         } catch (RemoteException e) {Log.e(TAG, "", e);}
799         return false;
800     }
801 
802     /** @hide */
getServiceChannel(ParcelUuid uuid)803     public int getServiceChannel(ParcelUuid uuid) {
804          try {
805              return sService.getRemoteServiceChannel(mAddress, uuid);
806          } catch (RemoteException e) {Log.e(TAG, "", e);}
807          return BluetoothDevice.ERROR;
808     }
809 
810     /** @hide */
setPin(byte[] pin)811     public boolean setPin(byte[] pin) {
812         try {
813             return sService.setPin(mAddress, pin);
814         } catch (RemoteException e) {Log.e(TAG, "", e);}
815         return false;
816     }
817 
818     /** @hide */
setPasskey(int passkey)819     public boolean setPasskey(int passkey) {
820         try {
821             return sService.setPasskey(mAddress, passkey);
822         } catch (RemoteException e) {Log.e(TAG, "", e);}
823         return false;
824     }
825 
826     /** @hide */
setPairingConfirmation(boolean confirm)827     public boolean setPairingConfirmation(boolean confirm) {
828         try {
829             return sService.setPairingConfirmation(mAddress, confirm);
830         } catch (RemoteException e) {Log.e(TAG, "", e);}
831         return false;
832     }
833 
834     /** @hide */
setRemoteOutOfBandData()835     public boolean setRemoteOutOfBandData() {
836         try {
837           return sService.setRemoteOutOfBandData(mAddress);
838       } catch (RemoteException e) {Log.e(TAG, "", e);}
839       return false;
840     }
841 
842     /** @hide */
cancelPairingUserInput()843     public boolean cancelPairingUserInput() {
844         try {
845             return sService.cancelPairingUserInput(mAddress);
846         } catch (RemoteException e) {Log.e(TAG, "", e);}
847         return false;
848     }
849 
850     /** @hide */
isBluetoothDock()851     public boolean isBluetoothDock() {
852         try {
853             return sService.isBluetoothDock(mAddress);
854         } catch (RemoteException e) {Log.e(TAG, "", e);}
855         return false;
856     }
857 
858     /**
859      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
860      * outgoing connection to this remote device on given channel.
861      * <p>The remote device will be authenticated and communication on this
862      * socket will be encrypted.
863      * <p> Use this socket only if an authenticated socket link is possible.
864      * Authentication refers to the authentication of the link key to
865      * prevent man-in-the-middle type of attacks.
866      * For example, for Bluetooth 2.1 devices, if any of the devices does not
867      * have an input and output capability or just has the ability to
868      * display a numeric key, a secure socket connection is not possible.
869      * In such a case, use {#link createInsecureRfcommSocket}.
870      * For more details, refer to the Security Model section 5.2 (vol 3) of
871      * Bluetooth Core Specification version 2.1 + EDR.
872      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
873      * connection.
874      * <p>Valid RFCOMM channels are in range 1 to 30.
875      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
876      *
877      * @param channel RFCOMM channel to connect to
878      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
879      * @throws IOException on error, for example Bluetooth not available, or
880      *                     insufficient permissions
881      * @hide
882      */
createRfcommSocket(int channel)883     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
884         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
885                 null);
886     }
887 
888     /**
889      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
890      * outgoing connection to this remote device using SDP lookup of uuid.
891      * <p>This is designed to be used with {@link
892      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
893      * Bluetooth applications.
894      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
895      * connection. This will also perform an SDP lookup of the given uuid to
896      * determine which channel to connect to.
897      * <p>The remote device will be authenticated and communication on this
898      * socket will be encrypted.
899      * <p> Use this socket only if an authenticated socket link is possible.
900      * Authentication refers to the authentication of the link key to
901      * prevent man-in-the-middle type of attacks.
902      * For example, for Bluetooth 2.1 devices, if any of the devices does not
903      * have an input and output capability or just has the ability to
904      * display a numeric key, a secure socket connection is not possible.
905      * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}.
906      * For more details, refer to the Security Model section 5.2 (vol 3) of
907      * Bluetooth Core Specification version 2.1 + EDR.
908      * <p>Hint: If you are connecting to a Bluetooth serial board then try
909      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
910      * However if you are connecting to an Android peer then please generate
911      * your own unique UUID.
912      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
913      *
914      * @param uuid service record uuid to lookup RFCOMM channel
915      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
916      * @throws IOException on error, for example Bluetooth not available, or
917      *                     insufficient permissions
918      */
createRfcommSocketToServiceRecord(UUID uuid)919     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
920         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
921                 new ParcelUuid(uuid));
922     }
923 
924     /**
925      * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
926      * outgoing connection to this remote device using SDP lookup of uuid.
927      * <p> The communication channel will not have an authenticated link key
928      * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
929      * devices, the link key will be encrypted, as encryption is mandatory.
930      * For legacy devices (pre Bluetooth 2.1 devices) the link key will
931      * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
932      * encrypted and authenticated communication channel is desired.
933      * <p>This is designed to be used with {@link
934      * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
935      * Bluetooth applications.
936      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
937      * connection. This will also perform an SDP lookup of the given uuid to
938      * determine which channel to connect to.
939      * <p>The remote device will be authenticated and communication on this
940      * socket will be encrypted.
941      * <p>Hint: If you are connecting to a Bluetooth serial board then try
942      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
943      * However if you are connecting to an Android peer then please generate
944      * your own unique UUID.
945      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
946      *
947      * @param uuid service record uuid to lookup RFCOMM channel
948      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
949      * @throws IOException on error, for example Bluetooth not available, or
950      *                     insufficient permissions
951      */
createInsecureRfcommSocketToServiceRecord(UUID uuid)952     public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
953         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
954                 new ParcelUuid(uuid));
955     }
956 
957     /**
958      * Construct an insecure RFCOMM socket ready to start an outgoing
959      * connection.
960      * Call #connect on the returned #BluetoothSocket to begin the connection.
961      * The remote device will not be authenticated and communication on this
962      * socket will not be encrypted.
963      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
964      *
965      * @param port    remote port
966      * @return An RFCOMM BluetoothSocket
967      * @throws IOException On error, for example Bluetooth not available, or
968      *                     insufficient permissions.
969      * @hide
970      */
createInsecureRfcommSocket(int port)971     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
972         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
973                 null);
974     }
975 
976     /**
977      * Construct a SCO socket ready to start an outgoing connection.
978      * Call #connect on the returned #BluetoothSocket to begin the connection.
979      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
980      *
981      * @return a SCO BluetoothSocket
982      * @throws IOException on error, for example Bluetooth not available, or
983      *                     insufficient permissions.
984      * @hide
985      */
createScoSocket()986     public BluetoothSocket createScoSocket() throws IOException {
987         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
988     }
989 
990     /**
991      * Check that a pin is valid and convert to byte array.
992      *
993      * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
994      * @param pin pin as java String
995      * @return the pin code as a UTF-8 byte array, or null if it is an invalid
996      *         Bluetooth pin.
997      * @hide
998      */
convertPinToBytes(String pin)999     public static byte[] convertPinToBytes(String pin) {
1000         if (pin == null) {
1001             return null;
1002         }
1003         byte[] pinBytes;
1004         try {
1005             pinBytes = pin.getBytes("UTF-8");
1006         } catch (UnsupportedEncodingException uee) {
1007             Log.e(TAG, "UTF-8 not supported?!?");  // this should not happen
1008             return null;
1009         }
1010         if (pinBytes.length <= 0 || pinBytes.length > 16) {
1011             return null;
1012         }
1013         return pinBytes;
1014     }
1015 
1016 }
1017