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