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