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