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