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