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