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