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