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