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