• 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.Manifest;
20 import android.annotation.RequiresPermission;
21 import android.annotation.SdkConstant;
22 import android.annotation.SdkConstant.SdkConstantType;
23 import android.annotation.SystemApi;
24 import android.content.Context;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.os.ParcelUuid;
28 import android.os.Process;
29 import android.os.RemoteException;
30 import android.util.Log;
31 
32 import java.io.IOException;
33 import java.io.UnsupportedEncodingException;
34 import java.util.UUID;
35 
36 /**
37  * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
38  * create a connection with the respective device or query information about
39  * it, such as the name, address, class, and bonding state.
40  *
41  * <p>This class is really just a thin wrapper for a Bluetooth hardware
42  * address. Objects of this class are immutable. Operations on this class
43  * are performed on the remote Bluetooth hardware address, using the
44  * {@link BluetoothAdapter} that was used to create this {@link
45  * BluetoothDevice}.
46  *
47  * <p>To get a {@link BluetoothDevice}, use
48  * {@link BluetoothAdapter#getRemoteDevice(String)
49  * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device
50  * of a known MAC address (which you can get through device discovery with
51  * {@link BluetoothAdapter}) or get one from the set of bonded devices
52  * returned by {@link BluetoothAdapter#getBondedDevices()
53  * BluetoothAdapter.getBondedDevices()}. You can then open a
54  * {@link BluetoothSocket} for communication with the remote device, using
55  * {@link #createRfcommSocketToServiceRecord(UUID)}.
56  *
57  * <p class="note"><strong>Note:</strong>
58  * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
59  *
60  * <div class="special reference">
61  * <h3>Developer Guides</h3>
62  * <p>
63  * For more information about using Bluetooth, read the <a href=
64  * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
65  * guide.
66  * </p>
67  * </div>
68  *
69  * {@see BluetoothAdapter}
70  * {@see BluetoothSocket}
71  */
72 public final class BluetoothDevice implements Parcelable {
73     private static final String TAG = "BluetoothDevice";
74     private static final boolean DBG = false;
75 
76     /**
77      * Connection state bitmask as returned by getConnectionState.
78      */
79     private static final int CONNECTION_STATE_DISCONNECTED = 0;
80     private static final int CONNECTION_STATE_CONNECTED = 1;
81     private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2;
82     private static final int CONNECTION_STATE_ENCRYPTED_LE = 4;
83 
84     /**
85      * Sentinel error value for this class. Guaranteed to not equal any other
86      * integer constant in this class. Provided as a convenience for functions
87      * that require a sentinel error value, for example:
88      * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
89      * BluetoothDevice.ERROR)</code>
90      */
91     public static final int ERROR = Integer.MIN_VALUE;
92 
93     /**
94      * Broadcast Action: Remote device discovered.
95      * <p>Sent when a remote device is found during discovery.
96      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
97      * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
98      * {@link #EXTRA_RSSI} if they are available.
99      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} and
100      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive.
101      */
102      // TODO: Change API to not broadcast RSSI if not available (incoming connection)
103     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
104     public static final String ACTION_FOUND =
105             "android.bluetooth.device.action.FOUND";
106 
107     /**
108      * Broadcast Action: Remote device disappeared.
109      * <p>Sent when a remote device that was found in the last discovery is not
110      * found in the current discovery.
111      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
112      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
113      * @hide
114      */
115     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
116     public static final String ACTION_DISAPPEARED =
117             "android.bluetooth.device.action.DISAPPEARED";
118 
119     /**
120      * Broadcast Action: Bluetooth class of a remote device has changed.
121      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
122      * #EXTRA_CLASS}.
123      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
124      * {@see BluetoothClass}
125      */
126     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
127     public static final String ACTION_CLASS_CHANGED =
128             "android.bluetooth.device.action.CLASS_CHANGED";
129 
130     /**
131      * Broadcast Action: Indicates a low level (ACL) connection has been
132      * established with a remote device.
133      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
134      * <p>ACL connections are managed automatically by the Android Bluetooth
135      * stack.
136      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
137      */
138     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
139     public static final String ACTION_ACL_CONNECTED =
140             "android.bluetooth.device.action.ACL_CONNECTED";
141 
142     /**
143      * Broadcast Action: Indicates that a low level (ACL) disconnection has
144      * been requested for a remote device, and it will soon be disconnected.
145      * <p>This is useful for graceful disconnection. Applications should use
146      * this intent as a hint to immediately terminate higher level connections
147      * (RFCOMM, L2CAP, or profile connections) to the remote device.
148      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
149      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
150      */
151     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
152     public static final String ACTION_ACL_DISCONNECT_REQUESTED =
153             "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
154 
155     /**
156      * Broadcast Action: Indicates a low level (ACL) disconnection from a
157      * remote device.
158      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
159      * <p>ACL connections are managed automatically by the Android Bluetooth
160      * stack.
161      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
162      */
163     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
164     public static final String ACTION_ACL_DISCONNECTED =
165             "android.bluetooth.device.action.ACL_DISCONNECTED";
166 
167     /**
168      * Broadcast Action: Indicates the friendly name of a remote device has
169      * been retrieved for the first time, or changed since the last retrieval.
170      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
171      * #EXTRA_NAME}.
172      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
173      */
174     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
175     public static final String ACTION_NAME_CHANGED =
176             "android.bluetooth.device.action.NAME_CHANGED";
177 
178     /**
179      * Broadcast Action: Indicates the alias of a remote device has been
180      * changed.
181      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
182      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
183      *
184      * @hide
185      */
186     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
187     public static final String ACTION_ALIAS_CHANGED =
188             "android.bluetooth.device.action.ALIAS_CHANGED";
189 
190     /**
191      * Broadcast Action: Indicates a change in the bond state of a remote
192      * device. For example, if a device is bonded (paired).
193      * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
194      * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
195      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
196      */
197     // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
198     // contain a hidden extra field EXTRA_REASON with the result code.
199     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
200     public static final String ACTION_BOND_STATE_CHANGED =
201             "android.bluetooth.device.action.BOND_STATE_CHANGED";
202 
203     /**
204      * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
205      * broadcast by this class. It contains the {@link BluetoothDevice} that
206      * the intent applies to.
207      */
208     public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
209 
210     /**
211      * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
212      * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
213      */
214     public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
215 
216     /**
217      * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
218      * Contains the RSSI value of the remote device as reported by the
219      * Bluetooth hardware.
220      */
221     public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
222 
223     /**
224      * Used as a Parcelable {@link BluetoothClass} extra field in {@link
225      * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
226      */
227     public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
228 
229     /**
230      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
231      * Contains the bond state of the remote device.
232      * <p>Possible values are:
233      * {@link #BOND_NONE},
234      * {@link #BOND_BONDING},
235      * {@link #BOND_BONDED}.
236      */
237     public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
238     /**
239      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
240      * Contains the previous bond state of the remote device.
241      * <p>Possible values are:
242      * {@link #BOND_NONE},
243      * {@link #BOND_BONDING},
244      * {@link #BOND_BONDED}.
245      */
246     public static final String EXTRA_PREVIOUS_BOND_STATE =
247             "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
248     /**
249      * Indicates the remote device is not bonded (paired).
250      * <p>There is no shared link key with the remote device, so communication
251      * (if it is allowed at all) will be unauthenticated and unencrypted.
252      */
253     public static final int BOND_NONE = 10;
254     /**
255      * Indicates bonding (pairing) is in progress with the remote device.
256      */
257     public static final int BOND_BONDING = 11;
258     /**
259      * Indicates the remote device is bonded (paired).
260      * <p>A shared link keys exists locally for the remote device, so
261      * communication can be authenticated and encrypted.
262      * <p><i>Being bonded (paired) with a remote device does not necessarily
263      * mean the device is currently connected. It just means that the pending
264      * procedure was completed at some earlier time, and the link key is still
265      * stored locally, ready to use on the next connection.
266      * </i>
267      */
268     public static final int BOND_BONDED = 12;
269 
270     /**
271      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
272      * intents for unbond reason.
273      * @hide
274      */
275     public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
276 
277     /**
278      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
279      * intents to indicate pairing method used. Possible values are:
280      * {@link #PAIRING_VARIANT_PIN},
281      * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION},
282      */
283     public static final String EXTRA_PAIRING_VARIANT =
284             "android.bluetooth.device.extra.PAIRING_VARIANT";
285 
286     /**
287      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
288      * intents as the value of passkey.
289      */
290     public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
291 
292     /**
293      * Bluetooth device type, Unknown
294      */
295     public static final int DEVICE_TYPE_UNKNOWN = 0;
296 
297     /**
298      * Bluetooth device type, Classic - BR/EDR devices
299      */
300     public static final int DEVICE_TYPE_CLASSIC = 1;
301 
302     /**
303      * Bluetooth device type, Low Energy - LE-only
304      */
305     public static final int DEVICE_TYPE_LE = 2;
306 
307     /**
308      * Bluetooth device type, Dual Mode - BR/EDR/LE
309      */
310     public static final int DEVICE_TYPE_DUAL = 3;
311 
312 
313     /** @hide */
314     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
315     public static final String ACTION_SDP_RECORD =
316             "android.bluetooth.device.action.SDP_RECORD";
317 
318     /**
319      * Broadcast Action: This intent is used to broadcast the {@link UUID}
320      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
321      * has been fetched. This intent is sent only when the UUIDs of the remote
322      * device are requested to be fetched using Service Discovery Protocol
323      * <p> Always contains the extra field {@link #EXTRA_DEVICE}
324      * <p> Always contains the extra field {@link #EXTRA_UUID}
325      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
326      */
327     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
328     public static final String ACTION_UUID =
329             "android.bluetooth.device.action.UUID";
330 
331     /** @hide */
332     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
333     public static final String ACTION_MAS_INSTANCE =
334             "android.bluetooth.device.action.MAS_INSTANCE";
335 
336     /**
337      * Broadcast Action: Indicates a failure to retrieve the name of a remote
338      * device.
339      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
340      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
341      * @hide
342      */
343     //TODO: is this actually useful?
344     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
345     public static final String ACTION_NAME_FAILED =
346             "android.bluetooth.device.action.NAME_FAILED";
347 
348     /**
349      * Broadcast Action: This intent is used to broadcast PAIRING REQUEST
350      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to
351      * receive.
352      */
353     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
354     public static final String ACTION_PAIRING_REQUEST =
355             "android.bluetooth.device.action.PAIRING_REQUEST";
356     /** @hide */
357     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
358     public static final String ACTION_PAIRING_CANCEL =
359             "android.bluetooth.device.action.PAIRING_CANCEL";
360 
361     /** @hide */
362     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
363     public static final String ACTION_CONNECTION_ACCESS_REQUEST =
364             "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
365 
366     /** @hide */
367     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
368     public static final String ACTION_CONNECTION_ACCESS_REPLY =
369             "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
370 
371     /** @hide */
372     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
373     public static final String ACTION_CONNECTION_ACCESS_CANCEL =
374             "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
375 
376     /**
377      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
378      * @hide
379      */
380     public static final String EXTRA_ACCESS_REQUEST_TYPE =
381         "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE";
382 
383     /**@hide*/
384     public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1;
385 
386     /**@hide*/
387     public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
388 
389     /**@hide*/
390     public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3;
391 
392     /**@hide*/
393     public static final int REQUEST_TYPE_SIM_ACCESS = 4;
394 
395     /**
396      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
397      * Contains package name to return reply intent to.
398      * @hide
399      */
400     public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME";
401 
402     /**
403      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
404      * Contains class name to return reply intent to.
405      * @hide
406      */
407     public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME";
408 
409     /**
410      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
411      * @hide
412      */
413     public static final String EXTRA_CONNECTION_ACCESS_RESULT =
414         "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
415 
416     /**@hide*/
417     public static final int CONNECTION_ACCESS_YES = 1;
418 
419     /**@hide*/
420     public static final int CONNECTION_ACCESS_NO = 2;
421 
422     /**
423      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents,
424      * Contains boolean to indicate if the allowed response is once-for-all so that
425      * next request will be granted without asking user again.
426      * @hide
427      */
428     public static final String EXTRA_ALWAYS_ALLOWED =
429         "android.bluetooth.device.extra.ALWAYS_ALLOWED";
430 
431     /**
432      * A bond attempt succeeded
433      * @hide
434      */
435     public static final int BOND_SUCCESS = 0;
436 
437     /**
438      * A bond attempt failed because pins did not match, or remote device did
439      * not respond to pin request in time
440      * @hide
441      */
442     public static final int UNBOND_REASON_AUTH_FAILED = 1;
443 
444     /**
445      * A bond attempt failed because the other side explicitly rejected
446      * bonding
447      * @hide
448      */
449     public static final int UNBOND_REASON_AUTH_REJECTED = 2;
450 
451     /**
452      * A bond attempt failed because we canceled the bonding process
453      * @hide
454      */
455     public static final int UNBOND_REASON_AUTH_CANCELED = 3;
456 
457     /**
458      * A bond attempt failed because we could not contact the remote device
459      * @hide
460      */
461     public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
462 
463     /**
464      * A bond attempt failed because a discovery is in progress
465      * @hide
466      */
467     public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
468 
469     /**
470      * A bond attempt failed because of authentication timeout
471      * @hide
472      */
473     public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
474 
475     /**
476      * A bond attempt failed because of repeated attempts
477      * @hide
478      */
479     public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
480 
481     /**
482      * A bond attempt failed because we received an Authentication Cancel
483      * by remote end
484      * @hide
485      */
486     public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
487 
488     /**
489      * An existing bond was explicitly revoked
490      * @hide
491      */
492     public static final int UNBOND_REASON_REMOVED = 9;
493 
494     /**
495      * The user will be prompted to enter a pin or
496      * an app will enter a pin for user.
497      */
498     public static final int PAIRING_VARIANT_PIN = 0;
499 
500     /**
501      * The user will be prompted to enter a passkey
502      * @hide
503      */
504     public static final int PAIRING_VARIANT_PASSKEY = 1;
505 
506     /**
507      * The user will be prompted to confirm the passkey displayed on the screen or
508      * an app will confirm the passkey for the user.
509      */
510     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
511 
512     /**
513      * The user will be prompted to accept or deny the incoming pairing request
514      * @hide
515      */
516     public static final int PAIRING_VARIANT_CONSENT = 3;
517 
518     /**
519      * The user will be prompted to enter the passkey displayed on remote device
520      * This is used for Bluetooth 2.1 pairing.
521      * @hide
522      */
523     public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
524 
525     /**
526      * The user will be prompted to enter the PIN displayed on remote device.
527      * This is used for Bluetooth 2.0 pairing.
528      * @hide
529      */
530     public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
531 
532     /**
533      * The user will be prompted to accept or deny the OOB pairing request
534      * @hide
535      */
536     public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
537 
538     /**
539      * The user will be prompted to enter a 16 digit pin or
540      * an app will enter a 16 digit pin for user.
541      * @hide
542      */
543     public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7;
544 
545     /**
546      * Used as an extra field in {@link #ACTION_UUID} intents,
547      * Contains the {@link android.os.ParcelUuid}s of the remote device which
548      * is a parcelable version of {@link UUID}.
549      */
550     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
551 
552     /** @hide */
553     public static final String EXTRA_SDP_RECORD =
554         "android.bluetooth.device.extra.SDP_RECORD";
555 
556     /** @hide */
557     public static final String EXTRA_SDP_SEARCH_STATUS =
558             "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
559     /**
560      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
561      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
562      * @hide
563      */
564     public static final int ACCESS_UNKNOWN = 0;
565 
566     /**
567      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
568      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
569      * @hide
570      */
571     public static final int ACCESS_ALLOWED = 1;
572 
573     /**
574      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
575      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
576      * @hide
577      */
578     public static final int ACCESS_REJECTED = 2;
579 
580      /**
581       * No preferrence of physical transport for GATT connections to remote dual-mode devices
582       */
583     public static final int TRANSPORT_AUTO = 0;
584 
585     /**
586      * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
587      */
588     public static final int TRANSPORT_BREDR = 1;
589 
590     /**
591      * Prefer LE transport for GATT connections to remote dual-mode devices
592      */
593     public static final int TRANSPORT_LE = 2;
594 
595     /** @hide */
596     public static final String EXTRA_MAS_INSTANCE =
597         "android.bluetooth.device.extra.MAS_INSTANCE";
598 
599     /**
600      * Lazy initialization. Guaranteed final after first object constructed, or
601      * getService() called.
602      * TODO: Unify implementation of sService amongst BluetoothFoo API's
603      */
604     private static IBluetooth sService;
605 
606     private final String mAddress;
607 
getService()608     /*package*/ static IBluetooth getService() {
609         synchronized (BluetoothDevice.class) {
610             if (sService == null) {
611                 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
612                 sService = adapter.getBluetoothService(mStateChangeCallback);
613             }
614         }
615         return sService;
616     }
617 
618     static IBluetoothManagerCallback mStateChangeCallback = new IBluetoothManagerCallback.Stub() {
619 
620         public void onBluetoothServiceUp(IBluetooth bluetoothService)
621                 throws RemoteException {
622             synchronized (BluetoothDevice.class) {
623                 if (sService == null) {
624                     sService = bluetoothService;
625                 }
626             }
627         }
628 
629         public void onBluetoothServiceDown()
630             throws RemoteException {
631             synchronized (BluetoothDevice.class) {
632                 sService = null;
633             }
634         }
635 
636         public void onBrEdrDown()
637         {
638             if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state");
639         }
640     };
641     /**
642      * Create a new BluetoothDevice
643      * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
644      * and is validated in this constructor.
645      * @param address valid Bluetooth MAC address
646      * @throws RuntimeException Bluetooth is not available on this platform
647      * @throws IllegalArgumentException address is invalid
648      * @hide
649      */
BluetoothDevice(String address)650     /*package*/ BluetoothDevice(String address) {
651         getService();  // ensures sService is initialized
652         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
653             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
654         }
655 
656         mAddress = address;
657     }
658 
659     @Override
equals(Object o)660     public boolean equals(Object o) {
661         if (o instanceof BluetoothDevice) {
662             return mAddress.equals(((BluetoothDevice)o).getAddress());
663         }
664         return false;
665     }
666 
667     @Override
hashCode()668     public int hashCode() {
669         return mAddress.hashCode();
670     }
671 
672     /**
673      * Returns a string representation of this BluetoothDevice.
674      * <p>Currently this is the Bluetooth hardware address, for example
675      * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
676      * if you explicitly require the Bluetooth hardware address in case the
677      * {@link #toString} representation changes in the future.
678      * @return string representation of this BluetoothDevice
679      */
680     @Override
toString()681     public String toString() {
682         return mAddress;
683     }
684 
describeContents()685     public int describeContents() {
686         return 0;
687     }
688 
689     public static final Parcelable.Creator<BluetoothDevice> CREATOR =
690             new Parcelable.Creator<BluetoothDevice>() {
691         public BluetoothDevice createFromParcel(Parcel in) {
692             return new BluetoothDevice(in.readString());
693         }
694         public BluetoothDevice[] newArray(int size) {
695             return new BluetoothDevice[size];
696         }
697     };
698 
writeToParcel(Parcel out, int flags)699     public void writeToParcel(Parcel out, int flags) {
700         out.writeString(mAddress);
701     }
702 
703     /**
704      * Returns the hardware address of this BluetoothDevice.
705      * <p> For example, "00:11:22:AA:BB:CC".
706      * @return Bluetooth hardware address as string
707      */
getAddress()708     public String getAddress() {
709         if (DBG) Log.d(TAG, "mAddress: " + mAddress);
710         return mAddress;
711     }
712 
713     /**
714      * Get the friendly Bluetooth name of the remote device.
715      *
716      * <p>The local adapter will automatically retrieve remote names when
717      * performing a device scan, and will cache them. This method just returns
718      * the name for this device from the cache.
719      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
720      *
721      * @return the Bluetooth name, or null if there was a problem.
722      */
723     @RequiresPermission(Manifest.permission.BLUETOOTH)
getName()724     public String getName() {
725         if (sService == null) {
726             Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
727             return null;
728         }
729         try {
730             return sService.getRemoteName(this);
731         } catch (RemoteException e) {Log.e(TAG, "", e);}
732         return null;
733     }
734 
735     /**
736      * Get the Bluetooth device type of the remote device.
737      *
738      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
739      *
740      * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE}
741      *                         {@link #DEVICE_TYPE_DUAL}.
742      *         {@link #DEVICE_TYPE_UNKNOWN} if it's not available
743      */
744     @RequiresPermission(Manifest.permission.BLUETOOTH)
getType()745     public int getType() {
746         if (sService == null) {
747             Log.e(TAG, "BT not enabled. Cannot get Remote Device type");
748             return DEVICE_TYPE_UNKNOWN;
749         }
750         try {
751             return sService.getRemoteType(this);
752         } catch (RemoteException e) {Log.e(TAG, "", e);}
753         return DEVICE_TYPE_UNKNOWN;
754     }
755 
756     /**
757      * Get the Bluetooth alias of the remote device.
758      * <p>Alias is the locally modified name of a remote device.
759      *
760      * @return the Bluetooth alias, or null if no alias or there was a problem
761      * @hide
762      */
getAlias()763     public String getAlias() {
764         if (sService == null) {
765             Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias");
766             return null;
767         }
768         try {
769             return sService.getRemoteAlias(this);
770         } catch (RemoteException e) {Log.e(TAG, "", e);}
771         return null;
772     }
773 
774     /**
775      * Set the Bluetooth alias of the remote device.
776      * <p>Alias is the locally modified name of a remote device.
777      * <p>This methoid overwrites the alias. The changed
778      * alias is saved in the local storage so that the change
779      * is preserved over power cycle.
780      *
781      * @return true on success, false on error
782      * @hide
783      */
setAlias(String alias)784     public boolean setAlias(String alias) {
785         if (sService == null) {
786             Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
787             return false;
788         }
789         try {
790             return sService.setRemoteAlias(this, alias);
791         } catch (RemoteException e) {Log.e(TAG, "", e);}
792         return false;
793     }
794 
795     /**
796      * Get the Bluetooth alias of the remote device.
797      * If Alias is null, get the Bluetooth name instead.
798      * @see #getAlias()
799      * @see #getName()
800      *
801      * @return the Bluetooth alias, or null if no alias or there was a problem
802      * @hide
803      */
getAliasName()804     public String getAliasName() {
805         String name = getAlias();
806         if (name == null) {
807             name = getName();
808         }
809         return name;
810     }
811 
812     /**
813      * Start the bonding (pairing) process with the remote device.
814      * <p>This is an asynchronous call, it will return immediately. Register
815      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
816      * the bonding process completes, and its result.
817      * <p>Android system services will handle the necessary user interactions
818      * to confirm and complete the bonding process.
819      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
820      *
821      * @return false on immediate error, true if bonding will begin
822      */
823     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
createBond()824     public boolean createBond() {
825         if (sService == null) {
826             Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
827             return false;
828         }
829         try {
830             Log.i(TAG, "createBond() for device " + getAddress() +
831                     " called by pid: " + Process.myPid() +
832                     " tid: " + Process.myTid());
833             return sService.createBond(this, TRANSPORT_AUTO);
834         } catch (RemoteException e) {Log.e(TAG, "", e);}
835         return false;
836     }
837 
838     /**
839      * Start the bonding (pairing) process with the remote device using the
840      * specified transport.
841      *
842      * <p>This is an asynchronous call, it will return immediately. Register
843      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
844      * the bonding process completes, and its result.
845      * <p>Android system services will handle the necessary user interactions
846      * to confirm and complete the bonding process.
847      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
848      *
849      * @param transport The transport to use for the pairing procedure.
850      * @return false on immediate error, true if bonding will begin
851      * @throws IllegalArgumentException if an invalid transport was specified
852      * @hide
853      */
createBond(int transport)854     public boolean createBond(int transport) {
855         if (sService == null) {
856             Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
857             return false;
858         }
859         if (TRANSPORT_AUTO > transport || transport > TRANSPORT_LE)
860         {
861             throw new IllegalArgumentException(transport + " is not a valid Bluetooth transport");
862         }
863         try {
864             Log.i(TAG, "createBond() for device " + getAddress() +
865                     " called by pid: " + Process.myPid() +
866                     " tid: " + Process.myTid());
867             return sService.createBond(this, transport);
868         } catch (RemoteException e) {Log.e(TAG, "", e);}
869         return false;
870     }
871 
872     /**
873      * Start the bonding (pairing) process with the remote device using the
874      * Out Of Band mechanism.
875      *
876      * <p>This is an asynchronous call, it will return immediately. Register
877      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
878      * the bonding process completes, and its result.
879      *
880      * <p>Android system services will handle the necessary user interactions
881      * to confirm and complete the bonding process.
882      *
883      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
884      *
885      * @param transport - Transport to use
886      * @param oobData - Out Of Band data
887      * @return false on immediate error, true if bonding will begin
888      *
889      * @hide
890      */
createBondOutOfBand(int transport, OobData oobData)891     public boolean createBondOutOfBand(int transport, OobData oobData) {
892         try {
893             return sService.createBondOutOfBand(this, transport, oobData);
894         } catch (RemoteException e) {Log.e(TAG, "", e);}
895         return false;
896     }
897 
898     /**
899      * Set the Out Of Band data for a remote device to be used later
900      * in the pairing mechanism. Users can obtain this data through other
901      * trusted channels
902      *
903      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
904      *
905      * @param hash Simple Secure pairing hash
906      * @param randomizer The random key obtained using OOB
907      * @return false on error; true otherwise
908      *
909      * @hide
910      */
setDeviceOutOfBandData(byte[] hash, byte[] randomizer)911     public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
912       //TODO(BT)
913       /*
914       try {
915         return sService.setDeviceOutOfBandData(this, hash, randomizer);
916       } catch (RemoteException e) {Log.e(TAG, "", e);} */
917       return false;
918     }
919 
920     /**
921      * Cancel an in-progress bonding request started with {@link #createBond}.
922      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
923      *
924      * @return true on success, false on error
925      * @hide
926      */
cancelBondProcess()927     public boolean cancelBondProcess() {
928         if (sService == null) {
929             Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
930             return false;
931         }
932         try {
933             Log.i(TAG, "cancelBondProcess() for device " + getAddress() +
934                     " called by pid: " + Process.myPid() +
935                     " tid: " + Process.myTid());
936             return sService.cancelBondProcess(this);
937         } catch (RemoteException e) {Log.e(TAG, "", e);}
938         return false;
939     }
940 
941     /**
942      * Remove bond (pairing) with the remote device.
943      * <p>Delete the link key associated with the remote device, and
944      * immediately terminate connections to that device that require
945      * authentication and encryption.
946      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
947      *
948      * @return true on success, false on error
949      * @hide
950      */
removeBond()951     public boolean removeBond() {
952         if (sService == null) {
953             Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
954             return false;
955         }
956         try {
957             Log.i(TAG, "removeBond() for device " + getAddress() +
958                     " called by pid: " + Process.myPid() +
959                     " tid: " + Process.myTid());
960             return sService.removeBond(this);
961         } catch (RemoteException e) {Log.e(TAG, "", e);}
962         return false;
963     }
964 
965     /**
966      * Get the bond state of the remote device.
967      * <p>Possible values for the bond state are:
968      * {@link #BOND_NONE},
969      * {@link #BOND_BONDING},
970      * {@link #BOND_BONDED}.
971      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
972      *
973      * @return the bond state
974      */
975     @RequiresPermission(Manifest.permission.BLUETOOTH)
getBondState()976     public int getBondState() {
977         if (sService == null) {
978             Log.e(TAG, "BT not enabled. Cannot get bond state");
979             return BOND_NONE;
980         }
981         try {
982             return sService.getBondState(this);
983         } catch (RemoteException e) {Log.e(TAG, "", e);}
984         catch (NullPointerException npe) {
985             // Handle case where bluetooth service proxy
986             // is already null.
987             Log.e(TAG, "NullPointerException for getBondState() of device ("+
988                 getAddress()+")", npe);
989         }
990         return BOND_NONE;
991     }
992 
993     /**
994      * Returns whether there is an open connection to this device.
995      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
996      *
997      * @return True if there is at least one open connection to this device.
998      * @hide
999      */
1000     @SystemApi
isConnected()1001     public boolean isConnected() {
1002         if (sService == null) {
1003             // BT is not enabled, we cannot be connected.
1004             return false;
1005         }
1006         try {
1007             return sService.getConnectionState(this) != CONNECTION_STATE_DISCONNECTED;
1008         } catch (RemoteException e) {
1009             Log.e(TAG, "", e);
1010             return false;
1011         }
1012     }
1013 
1014     /**
1015      * Returns whether there is an open connection to this device
1016      * that has been encrypted.
1017      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1018      *
1019      * @return True if there is at least one encrypted connection to this device.
1020      * @hide
1021      */
1022     @SystemApi
isEncrypted()1023     public boolean isEncrypted() {
1024         if (sService == null) {
1025             // BT is not enabled, we cannot be connected.
1026             return false;
1027         }
1028         try {
1029             return sService.getConnectionState(this) > CONNECTION_STATE_CONNECTED;
1030         } catch (RemoteException e) {
1031             Log.e(TAG, "", e);
1032             return false;
1033         }
1034     }
1035 
1036     /**
1037      * Get the Bluetooth class of the remote device.
1038      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1039      *
1040      * @return Bluetooth class object, or null on error
1041      */
1042     @RequiresPermission(Manifest.permission.BLUETOOTH)
getBluetoothClass()1043     public BluetoothClass getBluetoothClass() {
1044         if (sService == null) {
1045             Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
1046             return null;
1047         }
1048         try {
1049             int classInt = sService.getRemoteClass(this);
1050             if (classInt == BluetoothClass.ERROR) return null;
1051             return new BluetoothClass(classInt);
1052         } catch (RemoteException e) {Log.e(TAG, "", e);}
1053         return null;
1054     }
1055 
1056     /**
1057      * Returns the supported features (UUIDs) of the remote device.
1058      *
1059      * <p>This method does not start a service discovery procedure to retrieve the UUIDs
1060      * from the remote device. Instead, the local cached copy of the service
1061      * UUIDs are returned.
1062      * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired.
1063      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1064      *
1065      * @return the supported features (UUIDs) of the remote device,
1066      *         or null on error
1067      */
1068     @RequiresPermission(Manifest.permission.BLUETOOTH)
getUuids()1069      public ParcelUuid[] getUuids() {
1070          if (sService == null || isBluetoothEnabled() == false) {
1071             Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
1072              return null;
1073          }
1074         try {
1075             return sService.getRemoteUuids(this);
1076         } catch (RemoteException e) {Log.e(TAG, "", e);}
1077         return null;
1078     }
1079 
1080      /**
1081       * Perform a service discovery on the remote device to get the UUIDs supported.
1082       *
1083       * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
1084       * with the UUIDs supported by the remote end. If there is an error
1085       * in getting the SDP records or if the process takes a long time,
1086       * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently
1087       * present in the cache. Clients should use the {@link #getUuids} to get UUIDs
1088       * if service discovery is not to be performed.
1089       * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1090       *
1091       * @return False if the sanity check fails, True if the process
1092       *               of initiating an ACL connection to the remote device
1093       *               was started.
1094       */
1095      @RequiresPermission(Manifest.permission.BLUETOOTH)
fetchUuidsWithSdp()1096      public boolean fetchUuidsWithSdp() {
1097         IBluetooth service = sService;
1098         if (service == null || isBluetoothEnabled() == false) {
1099             Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
1100             return false;
1101         }
1102         try {
1103             return service.fetchRemoteUuids(this);
1104         } catch (RemoteException e) {Log.e(TAG, "", e);}
1105             return false;
1106     }
1107 
1108      /**
1109       * Perform a service discovery on the remote device to get the SDP records associated
1110       * with the specified UUID.
1111       *
1112       * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent,
1113       * with the SDP records found on the remote end. If there is an error
1114       * in getting the SDP records or if the process takes a long time,
1115       * {@link #ACTION_SDP_RECORD} intent is sent with an status value in
1116       * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
1117       * Detailed status error codes can be found by members of the Bluetooth package in
1118       * the AbstractionLayer class.
1119       * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1120       * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
1121       * The object type will match one of the SdpXxxRecord types, depending on the UUID searched
1122       * for.
1123       *
1124       * @return False if the sanity check fails, True if the process
1125       *               of initiating an ACL connection to the remote device
1126       *               was started.
1127       */
1128      /** @hide */
sdpSearch(ParcelUuid uuid)1129      public boolean sdpSearch(ParcelUuid uuid) {
1130          if (sService == null) {
1131              Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
1132              return false;
1133          }
1134          try {
1135              return sService.sdpSearch(this,uuid);
1136          } catch (RemoteException e) {Log.e(TAG, "", e);}
1137          return false;
1138      }
1139 
1140     /**
1141      * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
1142      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1143      *
1144      * @return true pin has been set
1145      *         false for error
1146      */
setPin(byte[] pin)1147     public boolean setPin(byte[] pin) {
1148         if (sService == null) {
1149             Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
1150             return false;
1151         }
1152         try {
1153             return sService.setPin(this, true, pin.length, pin);
1154         } catch (RemoteException e) {Log.e(TAG, "", e);}
1155         return false;
1156     }
1157 
1158     /** @hide */
setPasskey(int passkey)1159     public boolean setPasskey(int passkey) {
1160         //TODO(BT)
1161         /*
1162         try {
1163             return sService.setPasskey(this, true, 4, passkey);
1164         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1165         return false;
1166     }
1167 
1168     /**
1169      * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
1170      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1171      *
1172      * @return true confirmation has been sent out
1173      *         false for error
1174      */
1175     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
setPairingConfirmation(boolean confirm)1176     public boolean setPairingConfirmation(boolean confirm) {
1177         if (sService == null) {
1178             Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
1179             return false;
1180         }
1181         try {
1182             return sService.setPairingConfirmation(this, confirm);
1183         } catch (RemoteException e) {Log.e(TAG, "", e);}
1184         return false;
1185     }
1186 
1187     /** @hide */
setRemoteOutOfBandData()1188     public boolean setRemoteOutOfBandData() {
1189         // TODO(BT)
1190         /*
1191         try {
1192           return sService.setRemoteOutOfBandData(this);
1193       } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1194       return false;
1195     }
1196 
1197     /** @hide */
cancelPairingUserInput()1198     public boolean cancelPairingUserInput() {
1199         if (sService == null) {
1200             Log.e(TAG, "BT not enabled. Cannot create pairing user input");
1201             return false;
1202         }
1203         try {
1204             return sService.cancelBondProcess(this);
1205         } catch (RemoteException e) {Log.e(TAG, "", e);}
1206         return false;
1207     }
1208 
1209     /** @hide */
isBluetoothDock()1210     public boolean isBluetoothDock() {
1211         // TODO(BT)
1212         /*
1213         try {
1214             return sService.isBluetoothDock(this);
1215         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1216         return false;
1217     }
1218 
isBluetoothEnabled()1219      boolean isBluetoothEnabled() {
1220          boolean ret = false;
1221          BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1222          if (adapter != null && adapter.isEnabled() == true) {
1223              ret = true;
1224          }
1225          return ret;
1226      }
1227 
1228     /**
1229      * Requires {@link android.Manifest.permission#BLUETOOTH}.
1230      * @return Whether the phonebook access is allowed to this device. Can be
1231      *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
1232      * @hide
1233      */
getPhonebookAccessPermission()1234     public int getPhonebookAccessPermission() {
1235         if (sService == null) {
1236             return ACCESS_UNKNOWN;
1237         }
1238         try {
1239             return sService.getPhonebookAccessPermission(this);
1240         } catch (RemoteException e) {
1241             Log.e(TAG, "", e);
1242         }
1243         return ACCESS_UNKNOWN;
1244     }
1245 
1246     /**
1247      * Sets whether the phonebook access is allowed to this device.
1248      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1249      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
1250      *              {@link #ACCESS_REJECTED}.
1251      * @return Whether the value has been successfully set.
1252      * @hide
1253      */
setPhonebookAccessPermission(int value)1254     public boolean setPhonebookAccessPermission(int value) {
1255         if (sService == null) {
1256             return false;
1257         }
1258         try {
1259             return sService.setPhonebookAccessPermission(this, value);
1260         } catch (RemoteException e) {
1261             Log.e(TAG, "", e);
1262         }
1263         return false;
1264     }
1265 
1266     /**
1267      * Requires {@link android.Manifest.permission#BLUETOOTH}.
1268      * @return Whether the message access is allowed to this device. Can be
1269      *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
1270      * @hide
1271      */
getMessageAccessPermission()1272     public int getMessageAccessPermission() {
1273         if (sService == null) {
1274             return ACCESS_UNKNOWN;
1275         }
1276         try {
1277             return sService.getMessageAccessPermission(this);
1278         } catch (RemoteException e) {
1279             Log.e(TAG, "", e);
1280         }
1281         return ACCESS_UNKNOWN;
1282     }
1283 
1284     /**
1285      * Sets whether the message access is allowed to this device.
1286      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1287      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
1288      *              {@link #ACCESS_REJECTED}.
1289      * @return Whether the value has been successfully set.
1290      * @hide
1291      */
setMessageAccessPermission(int value)1292     public boolean setMessageAccessPermission(int value) {
1293         if (sService == null) {
1294             return false;
1295         }
1296         try {
1297             return sService.setMessageAccessPermission(this, value);
1298         } catch (RemoteException e) {
1299             Log.e(TAG, "", e);
1300         }
1301         return false;
1302     }
1303 
1304     /**
1305      * Requires {@link android.Manifest.permission#BLUETOOTH}.
1306      * @return Whether the Sim access is allowed to this device. Can be
1307      *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
1308      * @hide
1309      */
getSimAccessPermission()1310     public int getSimAccessPermission() {
1311         if (sService == null) {
1312             return ACCESS_UNKNOWN;
1313         }
1314         try {
1315             return sService.getSimAccessPermission(this);
1316         } catch (RemoteException e) {
1317             Log.e(TAG, "", e);
1318         }
1319         return ACCESS_UNKNOWN;
1320     }
1321 
1322     /**
1323      * Sets whether the Sim access is allowed to this device.
1324      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1325      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
1326      *              {@link #ACCESS_REJECTED}.
1327      * @return Whether the value has been successfully set.
1328      * @hide
1329      */
setSimAccessPermission(int value)1330     public boolean setSimAccessPermission(int value) {
1331         if (sService == null) {
1332             return false;
1333         }
1334         try {
1335             return sService.setSimAccessPermission(this, value);
1336         } catch (RemoteException e) {
1337             Log.e(TAG, "", e);
1338         }
1339         return false;
1340     }
1341 
1342     /**
1343      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
1344      * outgoing connection to this remote device on given channel.
1345      * <p>The remote device will be authenticated and communication on this
1346      * socket will be encrypted.
1347      * <p> Use this socket only if an authenticated socket link is possible.
1348      * Authentication refers to the authentication of the link key to
1349      * prevent man-in-the-middle type of attacks.
1350      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1351      * have an input and output capability or just has the ability to
1352      * display a numeric key, a secure socket connection is not possible.
1353      * In such a case, use {#link createInsecureRfcommSocket}.
1354      * For more details, refer to the Security Model section 5.2 (vol 3) of
1355      * Bluetooth Core Specification version 2.1 + EDR.
1356      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1357      * connection.
1358      * <p>Valid RFCOMM channels are in range 1 to 30.
1359      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1360      *
1361      * @param channel RFCOMM channel to connect to
1362      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1363      * @throws IOException on error, for example Bluetooth not available, or
1364      *                     insufficient permissions
1365      * @hide
1366      */
createRfcommSocket(int channel)1367     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
1368         if (isBluetoothEnabled() == false) {
1369             Log.e(TAG, "Bluetooth is not enabled");
1370             throw new IOException();
1371         }
1372         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
1373                 null);
1374     }
1375 
1376     /**
1377      * Create an L2cap {@link BluetoothSocket} ready to start a secure
1378      * outgoing connection to this remote device on given channel.
1379      * <p>The remote device will be authenticated and communication on this
1380      * socket will be encrypted.
1381      * <p> Use this socket only if an authenticated socket link is possible.
1382      * Authentication refers to the authentication of the link key to
1383      * prevent man-in-the-middle type of attacks.
1384      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1385      * have an input and output capability or just has the ability to
1386      * display a numeric key, a secure socket connection is not possible.
1387      * In such a case, use {#link createInsecureRfcommSocket}.
1388      * For more details, refer to the Security Model section 5.2 (vol 3) of
1389      * Bluetooth Core Specification version 2.1 + EDR.
1390      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1391      * connection.
1392      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
1393      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1394      *
1395      * @param channel L2cap PSM/channel to connect to
1396      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1397      * @throws IOException on error, for example Bluetooth not available, or
1398      *                     insufficient permissions
1399      * @hide
1400      */
createL2capSocket(int channel)1401     public BluetoothSocket createL2capSocket(int channel) throws IOException {
1402         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
1403                 null);
1404     }
1405 
1406     /**
1407      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
1408      * outgoing connection to this remote device using SDP lookup of uuid.
1409      * <p>This is designed to be used with {@link
1410      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
1411      * Bluetooth applications.
1412      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1413      * connection. This will also perform an SDP lookup of the given uuid to
1414      * determine which channel to connect to.
1415      * <p>The remote device will be authenticated and communication on this
1416      * socket will be encrypted.
1417      * <p> Use this socket only if an authenticated socket link is possible.
1418      * Authentication refers to the authentication of the link key to
1419      * prevent man-in-the-middle type of attacks.
1420      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1421      * have an input and output capability or just has the ability to
1422      * display a numeric key, a secure socket connection is not possible.
1423      * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}.
1424      * For more details, refer to the Security Model section 5.2 (vol 3) of
1425      * Bluetooth Core Specification version 2.1 + EDR.
1426      * <p>Hint: If you are connecting to a Bluetooth serial board then try
1427      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
1428      * However if you are connecting to an Android peer then please generate
1429      * your own unique UUID.
1430      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1431      *
1432      * @param uuid service record uuid to lookup RFCOMM channel
1433      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1434      * @throws IOException on error, for example Bluetooth not available, or
1435      *                     insufficient permissions
1436      */
1437     @RequiresPermission(Manifest.permission.BLUETOOTH)
createRfcommSocketToServiceRecord(UUID uuid)1438     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
1439         if (isBluetoothEnabled() == false) {
1440             Log.e(TAG, "Bluetooth is not enabled");
1441             throw new IOException();
1442         }
1443 
1444         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
1445                 new ParcelUuid(uuid));
1446     }
1447 
1448     /**
1449      * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
1450      * outgoing connection to this remote device using SDP lookup of uuid.
1451      * <p> The communication channel will not have an authenticated link key
1452      * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
1453      * devices, the link key will be encrypted, as encryption is mandatory.
1454      * For legacy devices (pre Bluetooth 2.1 devices) the link key will
1455      * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
1456      * encrypted and authenticated communication channel is desired.
1457      * <p>This is designed to be used with {@link
1458      * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
1459      * Bluetooth applications.
1460      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1461      * connection. This will also perform an SDP lookup of the given uuid to
1462      * determine which channel to connect to.
1463      * <p>The remote device will be authenticated and communication on this
1464      * socket will be encrypted.
1465      * <p>Hint: If you are connecting to a Bluetooth serial board then try
1466      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
1467      * However if you are connecting to an Android peer then please generate
1468      * your own unique UUID.
1469      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1470      *
1471      * @param uuid service record uuid to lookup RFCOMM channel
1472      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1473      * @throws IOException on error, for example Bluetooth not available, or
1474      *                     insufficient permissions
1475      */
1476     @RequiresPermission(Manifest.permission.BLUETOOTH)
createInsecureRfcommSocketToServiceRecord(UUID uuid)1477     public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
1478         if (isBluetoothEnabled() == false) {
1479             Log.e(TAG, "Bluetooth is not enabled");
1480             throw new IOException();
1481         }
1482         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
1483                 new ParcelUuid(uuid));
1484     }
1485 
1486     /**
1487      * Construct an insecure RFCOMM socket ready to start an outgoing
1488      * connection.
1489      * Call #connect on the returned #BluetoothSocket to begin the connection.
1490      * The remote device will not be authenticated and communication on this
1491      * socket will not be encrypted.
1492      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1493      *
1494      * @param port    remote port
1495      * @return An RFCOMM BluetoothSocket
1496      * @throws IOException On error, for example Bluetooth not available, or
1497      *                     insufficient permissions.
1498      * @hide
1499      */
createInsecureRfcommSocket(int port)1500     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
1501 
1502         if (isBluetoothEnabled() == false) {
1503             Log.e(TAG, "Bluetooth is not enabled");
1504             throw new IOException();
1505         }
1506         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
1507                 null);
1508     }
1509 
1510     /**
1511      * Construct a SCO socket ready to start an outgoing connection.
1512      * Call #connect on the returned #BluetoothSocket to begin the connection.
1513      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1514      *
1515      * @return a SCO BluetoothSocket
1516      * @throws IOException on error, for example Bluetooth not available, or
1517      *                     insufficient permissions.
1518      * @hide
1519      */
createScoSocket()1520     public BluetoothSocket createScoSocket() throws IOException {
1521 
1522         if (isBluetoothEnabled() == false) {
1523             Log.e(TAG, "Bluetooth is not enabled");
1524             throw new IOException();
1525         }
1526         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
1527     }
1528 
1529     /**
1530      * Check that a pin is valid and convert to byte array.
1531      *
1532      * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
1533      * @param pin pin as java String
1534      * @return the pin code as a UTF-8 byte array, or null if it is an invalid
1535      *         Bluetooth pin.
1536      * @hide
1537      */
convertPinToBytes(String pin)1538     public static byte[] convertPinToBytes(String pin) {
1539         if (pin == null) {
1540             return null;
1541         }
1542         byte[] pinBytes;
1543         try {
1544             pinBytes = pin.getBytes("UTF-8");
1545         } catch (UnsupportedEncodingException uee) {
1546             Log.e(TAG, "UTF-8 not supported?!?");  // this should not happen
1547             return null;
1548         }
1549         if (pinBytes.length <= 0 || pinBytes.length > 16) {
1550             return null;
1551         }
1552         return pinBytes;
1553     }
1554 
1555     /**
1556      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
1557      * The callback is used to deliver results to Caller, such as connection status as well
1558      * as any further GATT client operations.
1559      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
1560      * GATT client operations.
1561      * @param callback GATT callback handler that will receive asynchronous callbacks.
1562      * @param autoConnect Whether to directly connect to the remote device (false)
1563      *                    or to automatically connect as soon as the remote
1564      *                    device becomes available (true).
1565      * @throws IllegalArgumentException if callback is null
1566      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)1567     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
1568                                      BluetoothGattCallback callback) {
1569         return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));
1570     }
1571 
1572     /**
1573      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
1574      * The callback is used to deliver results to Caller, such as connection status as well
1575      * as any further GATT client operations.
1576      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
1577      * GATT client operations.
1578      * @param callback GATT callback handler that will receive asynchronous callbacks.
1579      * @param autoConnect Whether to directly connect to the remote device (false)
1580      *                    or to automatically connect as soon as the remote
1581      *                    device becomes available (true).
1582      * @param transport preferred transport for GATT connections to remote dual-mode devices
1583      *             {@link BluetoothDevice#TRANSPORT_AUTO} or
1584      *             {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
1585      * @throws IllegalArgumentException if callback is null
1586      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)1587     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
1588                                      BluetoothGattCallback callback, int transport) {
1589         // TODO(Bluetooth) check whether platform support BLE
1590         //     Do the check here or in GattServer?
1591         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1592         IBluetoothManager managerService = adapter.getBluetoothManager();
1593         try {
1594             IBluetoothGatt iGatt = managerService.getBluetoothGatt();
1595             if (iGatt == null) {
1596                 // BLE is not supported
1597                 return null;
1598             }
1599             BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this, transport);
1600             gatt.connect(autoConnect, callback);
1601             return gatt;
1602         } catch (RemoteException e) {Log.e(TAG, "", e);}
1603         return null;
1604     }
1605 }
1606