BluetoothDevice.java revision 6eef14a7fcf6b6338f21f760830abf369ca0137d
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_PASSKEY = "android.bluetooth.device.extra.PASSKEY";
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    /** A bond attempt succeeded
280     * @hide */
281    public static final int BOND_SUCCESS = 0;
282    /** A bond attempt failed because pins did not match, or remote device did
283     * not respond to pin request in time
284     * @hide */
285    public static final int UNBOND_REASON_AUTH_FAILED = 1;
286    /** A bond attempt failed because the other side explicitly rejected
287     * bonding
288     * @hide */
289    public static final int UNBOND_REASON_AUTH_REJECTED = 2;
290    /** A bond attempt failed because we canceled the bonding process
291     * @hide */
292    public static final int UNBOND_REASON_AUTH_CANCELED = 3;
293    /** A bond attempt failed because we could not contact the remote device
294     * @hide */
295    public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
296    /** A bond attempt failed because a discovery is in progress
297     * @hide */
298    public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
299    /** A bond attempt failed because of authentication timeout
300     * @hide */
301    public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
302    /** A bond attempt failed because of repeated attempts
303     * @hide */
304    public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
305    /** A bond attempt failed because we received an Authentication Cancel
306     *  by remote end
307     * @hide */
308    public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
309    /** An existing bond was explicitly revoked
310     * @hide */
311    public static final int UNBOND_REASON_REMOVED = 9;
312
313    /** The user will be prompted to enter a pin
314     * @hide */
315    public static final int PAIRING_VARIANT_PIN = 0;
316    /** The user will be prompted to enter a passkey
317     * @hide */
318    public static final int PAIRING_VARIANT_PASSKEY = 1;
319    /** The user will be prompted to confirm the passkey displayed on the screen
320     * @hide */
321    public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
322    /** The user will be prompted to accept or deny the incoming pairing request
323     * @hide */
324    public static final int PAIRING_VARIANT_CONSENT = 3;
325    /** The user will be prompted to enter the passkey displayed on remote device
326     * @hide */
327    public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
328    /** The user will be prompted to accept or deny the OOB pairing request
329     * @hide */
330    public static final int PAIRING_VARIANT_OOB_CONSENT = 5;
331    /**
332     * Used as an extra field in {@link #ACTION_UUID} intents,
333     * Contains the {@link android.os.ParcelUuid}s of the remote device which
334     * is a parcelable version of {@link UUID}.
335     * @hide
336     */
337    public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
338
339    /**
340     * Lazy initialization. Guaranteed final after first object constructed, or
341     * getService() called.
342     * TODO: Unify implementation of sService amongst BluetoothFoo API's
343     */
344    private static IBluetooth sService;
345
346    private final String mAddress;
347
348    /*package*/ static IBluetooth getService() {
349        synchronized (BluetoothDevice.class) {
350            if (sService == null) {
351                IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
352                if (b == null) {
353                    throw new RuntimeException("Bluetooth service not available");
354                }
355                sService = IBluetooth.Stub.asInterface(b);
356            }
357        }
358        return sService;
359    }
360
361    /**
362     * Create a new BluetoothDevice
363     * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
364     * and is validated in this constructor.
365     * @param address valid Bluetooth MAC address
366     * @throws RuntimeException Bluetooth is not available on this platform
367     * @throws IllegalArgumentException address is invalid
368     * @hide
369     */
370    /*package*/ BluetoothDevice(String address) {
371        getService();  // ensures sService is initialized
372        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
373            throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
374        }
375
376        mAddress = address;
377    }
378
379    @Override
380    public boolean equals(Object o) {
381        if (o instanceof BluetoothDevice) {
382            return mAddress.equals(((BluetoothDevice)o).getAddress());
383        }
384        return false;
385    }
386
387    @Override
388    public int hashCode() {
389        return mAddress.hashCode();
390    }
391
392    /**
393     * Returns a string representation of this BluetoothDevice.
394     * <p>Currently this is the Bluetooth hardware address, for example
395     * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
396     * if you explicitly require the Bluetooth hardware address in case the
397     * {@link #toString} representation changes in the future.
398     * @return string representation of this BluetoothDevice
399     */
400    @Override
401    public String toString() {
402        return mAddress;
403    }
404
405    public int describeContents() {
406        return 0;
407    }
408
409    public static final Parcelable.Creator<BluetoothDevice> CREATOR =
410            new Parcelable.Creator<BluetoothDevice>() {
411        public BluetoothDevice createFromParcel(Parcel in) {
412            return new BluetoothDevice(in.readString());
413        }
414        public BluetoothDevice[] newArray(int size) {
415            return new BluetoothDevice[size];
416        }
417    };
418
419    public void writeToParcel(Parcel out, int flags) {
420        out.writeString(mAddress);
421    }
422
423    /**
424     * Returns the hardware address of this BluetoothDevice.
425     * <p> For example, "00:11:22:AA:BB:CC".
426     * @return Bluetooth hardware address as string
427     */
428    public String getAddress() {
429        return mAddress;
430    }
431
432    /**
433     * Get the friendly Bluetooth name of the remote device.
434     *
435     * <p>The local adapter will automatically retrieve remote names when
436     * performing a device scan, and will cache them. This method just returns
437     * the name for this device from the cache.
438     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
439     *
440     * @return the Bluetooth name, or null if there was a problem.
441     */
442    public String getName() {
443        try {
444            return sService.getRemoteName(mAddress);
445        } catch (RemoteException e) {Log.e(TAG, "", e);}
446        return null;
447    }
448
449    /**
450     * Start the bonding (pairing) process with the remote device.
451     * <p>This is an asynchronous call, it will return immediately. Register
452     * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
453     * the bonding process completes, and its result.
454     * <p>Android system services will handle the necessary user interactions
455     * to confirm and complete the bonding process.
456     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
457     *
458     * @return false on immediate error, true if bonding will begin
459     * @hide
460     */
461    public boolean createBond() {
462        try {
463            return sService.createBond(mAddress);
464        } catch (RemoteException e) {Log.e(TAG, "", e);}
465        return false;
466    }
467
468    /**
469     * Start the bonding (pairing) process with the remote device using the
470     * Out Of Band mechanism.
471     *
472     * <p>This is an asynchronous call, it will return immediately. Register
473     * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
474     * the bonding process completes, and its result.
475     *
476     * <p>Android system services will handle the necessary user interactions
477     * to confirm and complete the bonding process.
478     *
479     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
480     *
481     * @param hash - Simple Secure pairing hash
482     * @param randomizer - The random key obtained using OOB
483     * @return false on immediate error, true if bonding will begin
484     *
485     * @hide
486     */
487    public boolean createBondOutOfBand(byte[] hash, byte[] randomizer) {
488        try {
489            return sService.createBondOutOfBand(mAddress, hash, randomizer);
490        } catch (RemoteException e) {Log.e(TAG, "", e);}
491        return false;
492    }
493
494    /**
495     * Set the Out Of Band data for a remote device to be used later
496     * in the pairing mechanism. Users can obtain this data through other
497     * trusted channels
498     *
499     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
500     *
501     * @param hash Simple Secure pairing hash
502     * @param randomizer The random key obtained using OOB
503     * @return false on error; true otherwise
504     *
505     * @hide
506     */
507    public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
508      try {
509        return sService.setDeviceOutOfBandData(mAddress, hash, randomizer);
510      } catch (RemoteException e) {Log.e(TAG, "", e);}
511      return false;
512    }
513
514    /**
515     * Cancel an in-progress bonding request started with {@link #createBond}.
516     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
517     *
518     * @return true on success, false on error
519     * @hide
520     */
521    public boolean cancelBondProcess() {
522        try {
523            return sService.cancelBondProcess(mAddress);
524        } catch (RemoteException e) {Log.e(TAG, "", e);}
525        return false;
526    }
527
528    /**
529     * Remove bond (pairing) with the remote device.
530     * <p>Delete the link key associated with the remote device, and
531     * immediately terminate connections to that device that require
532     * authentication and encryption.
533     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
534     *
535     * @return true on success, false on error
536     * @hide
537     */
538    public boolean removeBond() {
539        try {
540            return sService.removeBond(mAddress);
541        } catch (RemoteException e) {Log.e(TAG, "", e);}
542        return false;
543    }
544
545    /**
546     * Get the bond state of the remote device.
547     * <p>Possible values for the bond state are:
548     * {@link #BOND_NONE},
549     * {@link #BOND_BONDING},
550     * {@link #BOND_BONDED}.
551     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
552     *
553     * @return the bond state
554     */
555    public int getBondState() {
556        try {
557            return sService.getBondState(mAddress);
558        } catch (RemoteException e) {Log.e(TAG, "", e);}
559        return BOND_NONE;
560    }
561
562    /**
563     * Get the Bluetooth class of the remote device.
564     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
565     *
566     * @return Bluetooth class object, or null on error
567     */
568    public BluetoothClass getBluetoothClass() {
569        try {
570            int classInt = sService.getRemoteClass(mAddress);
571            if (classInt == BluetoothClass.ERROR) return null;
572            return new BluetoothClass(classInt);
573        } catch (RemoteException e) {Log.e(TAG, "", e);}
574        return null;
575    }
576
577    /**
578     * Get trust state of a remote device.
579     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
580     * @hide
581     */
582    public boolean getTrustState() {
583        try {
584            return sService.getTrustState(mAddress);
585        } catch (RemoteException e) {
586            Log.e(TAG, "", e);
587        }
588        return false;
589    }
590
591    /**
592     * Set trust state for a remote device.
593     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
594     * @param value the trust state value (true or false)
595     * @hide
596     */
597    public boolean setTrust(boolean value) {
598        try {
599            return sService.setTrust(mAddress, value);
600        } catch (RemoteException e) {
601            Log.e(TAG, "", e);
602        }
603        return false;
604    }
605
606    /** @hide */
607     public ParcelUuid[] getUuids() {
608        try {
609            return sService.getRemoteUuids(mAddress);
610        } catch (RemoteException e) {Log.e(TAG, "", e);}
611        return null;
612    }
613
614     /**
615      *  Perform a SDP query on the remote device to get the UUIDs
616      *  supported. This API is asynchronous and an Intent is sent,
617      *  with the UUIDs supported by the remote end. If there is an error
618      *  in getting the SDP records or if the process takes a long time,
619      *  an Intent is sent with the UUIDs that is currently present in the
620      *  cache. Clients should use the {@link #getUuids} to get UUIDs
621      *  is SDP is not to be performed.
622      *
623      *  @return False if the sanity check fails, True if the process
624      *               of initiating an ACL connection to the remote device
625      *               was started.
626      *  @hide
627      */
628     public boolean fetchUuidsWithSdp() {
629        try {
630            return sService.fetchRemoteUuids(mAddress, null, null);
631        } catch (RemoteException e) {Log.e(TAG, "", e);}
632        return false;
633    }
634
635    /** @hide */
636    public int getServiceChannel(ParcelUuid uuid) {
637         try {
638             return sService.getRemoteServiceChannel(mAddress, uuid);
639         } catch (RemoteException e) {Log.e(TAG, "", e);}
640         return BluetoothDevice.ERROR;
641    }
642
643    /** @hide */
644    public boolean setPin(byte[] pin) {
645        try {
646            return sService.setPin(mAddress, pin);
647        } catch (RemoteException e) {Log.e(TAG, "", e);}
648        return false;
649    }
650
651    /** @hide */
652    public boolean setPasskey(int passkey) {
653        try {
654            return sService.setPasskey(mAddress, passkey);
655        } catch (RemoteException e) {Log.e(TAG, "", e);}
656        return false;
657    }
658
659    /** @hide */
660    public boolean setPairingConfirmation(boolean confirm) {
661        try {
662            return sService.setPairingConfirmation(mAddress, confirm);
663        } catch (RemoteException e) {Log.e(TAG, "", e);}
664        return false;
665    }
666
667    /** @hide */
668    public boolean setRemoteOutOfBandData() {
669        try {
670          return sService.setRemoteOutOfBandData(mAddress);
671      } catch (RemoteException e) {Log.e(TAG, "", e);}
672      return false;
673    }
674
675    /** @hide */
676    public boolean cancelPairingUserInput() {
677        try {
678            return sService.cancelPairingUserInput(mAddress);
679        } catch (RemoteException e) {Log.e(TAG, "", e);}
680        return false;
681    }
682
683    /** @hide */
684    public boolean isBluetoothDock() {
685        try {
686            return sService.isBluetoothDock(mAddress);
687        } catch (RemoteException e) {Log.e(TAG, "", e);}
688        return false;
689    }
690
691    /**
692     * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
693     * outgoing connection to this remote device on given channel.
694     * <p>The remote device will be authenticated and communication on this
695     * socket will be encrypted.
696     * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
697     * connection.
698     * <p>Valid RFCOMM channels are in range 1 to 30.
699     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
700     *
701     * @param channel RFCOMM channel to connect to
702     * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
703     * @throws IOException on error, for example Bluetooth not available, or
704     *                     insufficient permissions
705     * @hide
706     */
707    public BluetoothSocket createRfcommSocket(int channel) throws IOException {
708        return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
709                null);
710    }
711
712    /**
713     * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
714     * outgoing connection to this remote device using SDP lookup of uuid.
715     * <p>This is designed to be used with {@link
716     * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
717     * Bluetooth applications.
718     * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
719     * connection. This will also perform an SDP lookup of the given uuid to
720     * determine which channel to connect to.
721     * <p>The remote device will be authenticated and communication on this
722     * socket will be encrypted.
723     * <p>Hint: If you are connecting to a Bluetooth serial board then try
724     * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
725     * However if you are connecting to an Android peer then please generate
726     * your own unique UUID.
727     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
728     *
729     * @param uuid service record uuid to lookup RFCOMM channel
730     * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
731     * @throws IOException on error, for example Bluetooth not available, or
732     *                     insufficient permissions
733     */
734    public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
735        return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
736                new ParcelUuid(uuid));
737    }
738
739    /**
740     * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
741     * outgoing connection to this remote device using SDP lookup of uuid.
742     * <p> The communication channel will not have an authenticated link key
743     * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
744     * devices, the link key will be encrypted, as encryption is mandatory.
745     * For legacy devices (pre Bluetooth 2.1 devices) the link key will
746     * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
747     * encrypted and authenticated communication channel is desired.
748     * <p>This is designed to be used with {@link
749     * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
750     * Bluetooth applications.
751     * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
752     * connection. This will also perform an SDP lookup of the given uuid to
753     * determine which channel to connect to.
754     * <p>The remote device will be authenticated and communication on this
755     * socket will be encrypted.
756     * <p>Hint: If you are connecting to a Bluetooth serial board then try
757     * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
758     * However if you are connecting to an Android peer then please generate
759     * your own unique UUID.
760     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
761     *
762     * @param uuid service record uuid to lookup RFCOMM channel
763     * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
764     * @throws IOException on error, for example Bluetooth not available, or
765     *                     insufficient permissions
766     */
767    public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
768        return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
769                new ParcelUuid(uuid));
770    }
771
772    /**
773     * Construct an insecure RFCOMM socket ready to start an outgoing
774     * connection.
775     * Call #connect on the returned #BluetoothSocket to begin the connection.
776     * The remote device will not be authenticated and communication on this
777     * socket will not be encrypted.
778     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
779     *
780     * @param port    remote port
781     * @return An RFCOMM BluetoothSocket
782     * @throws IOException On error, for example Bluetooth not available, or
783     *                     insufficient permissions.
784     * @hide
785     */
786    public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
787        return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
788                null);
789    }
790
791    /**
792     * Construct a SCO socket ready to start an outgoing connection.
793     * Call #connect on the returned #BluetoothSocket to begin the connection.
794     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
795     *
796     * @return a SCO BluetoothSocket
797     * @throws IOException on error, for example Bluetooth not available, or
798     *                     insufficient permissions.
799     * @hide
800     */
801    public BluetoothSocket createScoSocket() throws IOException {
802        return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
803    }
804
805    /**
806     * Check that a pin is valid and convert to byte array.
807     *
808     * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
809     * @param pin pin as java String
810     * @return the pin code as a UTF-8 byte array, or null if it is an invalid
811     *         Bluetooth pin.
812     * @hide
813     */
814    public static byte[] convertPinToBytes(String pin) {
815        if (pin == null) {
816            return null;
817        }
818        byte[] pinBytes;
819        try {
820            pinBytes = pin.getBytes("UTF-8");
821        } catch (UnsupportedEncodingException uee) {
822            Log.e(TAG, "UTF-8 not supported?!?");  // this should not happen
823            return null;
824        }
825        if (pinBytes.length <= 0 || pinBytes.length > 16) {
826            return null;
827        }
828        return pinBytes;
829    }
830
831}
832