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