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