• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.bluetooth;
18 
19 import android.annotation.SdkConstant;
20 import android.annotation.SdkConstant.SdkConstantType;
21 import android.os.IBinder;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.os.ParcelUuid;
25 import android.os.RemoteException;
26 import android.os.ServiceManager;
27 import android.util.Log;
28 
29 import java.io.IOException;
30 import java.io.UnsupportedEncodingException;
31 import java.util.UUID;
32 
33 /**
34  * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
35  * create a connection with the repective 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 communciation 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  */
60 public 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 ponding
230      * procedure was compeleted 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 explicilty 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 
329     /**
330      * Used as an extra field in {@link #ACTION_UUID} intents,
331      * Contains the {@link android.os.ParcelUuid}s of the remote device which
332      * is a parcelable version of {@link UUID}.
333      * @hide
334      */
335     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
336 
337     /**
338      * Lazy initialization. Guaranteed final after first object constructed, or
339      * getService() called.
340      * TODO: Unify implementation of sService amongst BluetoothFoo API's
341      */
342     private static IBluetooth sService;
343 
344     private final String mAddress;
345 
getService()346     /*package*/ static IBluetooth getService() {
347         synchronized (BluetoothDevice.class) {
348             if (sService == null) {
349                 IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
350                 if (b == null) {
351                     throw new RuntimeException("Bluetooth service not available");
352                 }
353                 sService = IBluetooth.Stub.asInterface(b);
354             }
355         }
356         return sService;
357     }
358 
359     /**
360      * Create a new BluetoothDevice
361      * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
362      * and is validated in this constructor.
363      * @param address valid Bluetooth MAC address
364      * @throws RuntimeException Bluetooth is not available on this platform
365      * @throws IllegalArgumentException address is invalid
366      * @hide
367      */
BluetoothDevice(String address)368     /*package*/ BluetoothDevice(String address) {
369         getService();  // ensures sService is initialized
370         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
371             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
372         }
373 
374         mAddress = address;
375     }
376 
377     @Override
equals(Object o)378     public boolean equals(Object o) {
379         if (o instanceof BluetoothDevice) {
380             return mAddress.equals(((BluetoothDevice)o).getAddress());
381         }
382         return false;
383     }
384 
385     @Override
hashCode()386     public int hashCode() {
387         return mAddress.hashCode();
388     }
389 
390     /**
391      * Returns a string representation of this BluetoothDevice.
392      * <p>Currently this is the Bluetooth hardware address, for example
393      * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
394      * if you explicitly require the Bluetooth hardware address in case the
395      * {@link #toString} representation changes in the future.
396      * @return string representation of this BluetoothDevice
397      */
398     @Override
toString()399     public String toString() {
400         return mAddress;
401     }
402 
describeContents()403     public int describeContents() {
404         return 0;
405     }
406 
407     public static final Parcelable.Creator<BluetoothDevice> CREATOR =
408             new Parcelable.Creator<BluetoothDevice>() {
409         public BluetoothDevice createFromParcel(Parcel in) {
410             return new BluetoothDevice(in.readString());
411         }
412         public BluetoothDevice[] newArray(int size) {
413             return new BluetoothDevice[size];
414         }
415     };
416 
writeToParcel(Parcel out, int flags)417     public void writeToParcel(Parcel out, int flags) {
418         out.writeString(mAddress);
419     }
420 
421     /**
422      * Returns the hardware address of this BluetoothDevice.
423      * <p> For example, "00:11:22:AA:BB:CC".
424      * @return Bluetooth hardware address as string
425      */
getAddress()426     public String getAddress() {
427         return mAddress;
428     }
429 
430     /**
431      * Get the friendly Bluetooth name of the remote device.
432      *
433      * <p>The local adapter will automatically retrieve remote names when
434      * performing a device scan, and will cache them. This method just returns
435      * the name for this device from the cache.
436      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
437      *
438      * @return the Bluetooth name, or null if there was a problem.
439      */
getName()440     public String getName() {
441         try {
442             return sService.getRemoteName(mAddress);
443         } catch (RemoteException e) {Log.e(TAG, "", e);}
444         return null;
445     }
446 
447     /**
448      * Start the bonding (pairing) process with the remote device.
449      * <p>This is an asynchronous call, it will return immediately. Register
450      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
451      * the bonding process completes, and its result.
452      * <p>Android system services will handle the necessary user interactions
453      * to confirm and complete the bonding process.
454      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
455      *
456      * @return false on immediate error, true if bonding will begin
457      * @hide
458      */
createBond()459     public boolean createBond() {
460         try {
461             return sService.createBond(mAddress);
462         } catch (RemoteException e) {Log.e(TAG, "", e);}
463         return false;
464     }
465 
466     /**
467      * Cancel an in-progress bonding request started with {@link #createBond}.
468      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
469      *
470      * @return true on sucess, false on error
471      * @hide
472      */
cancelBondProcess()473     public boolean cancelBondProcess() {
474         try {
475             return sService.cancelBondProcess(mAddress);
476         } catch (RemoteException e) {Log.e(TAG, "", e);}
477         return false;
478     }
479 
480     /**
481      * Remove bond (pairing) with the remote device.
482      * <p>Delete the link key associated with the remote device, and
483      * immediately terminate connections to that device that require
484      * authentication and encryption.
485      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
486      *
487      * @return true on sucess, false on error
488      * @hide
489      */
removeBond()490     public boolean removeBond() {
491         try {
492             return sService.removeBond(mAddress);
493         } catch (RemoteException e) {Log.e(TAG, "", e);}
494         return false;
495     }
496 
497     /**
498      * Get the bond state of the remote device.
499      * <p>Possible values for the bond state are:
500      * {@link #BOND_NONE},
501      * {@link #BOND_BONDING},
502      * {@link #BOND_BONDED}.
503      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
504      *
505      * @return the bond state
506      */
getBondState()507     public int getBondState() {
508         try {
509             return sService.getBondState(mAddress);
510         } catch (RemoteException e) {Log.e(TAG, "", e);}
511         return BOND_NONE;
512     }
513 
514     /**
515      * Get the Bluetooth class of the remote device.
516      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
517      *
518      * @return Bluetooth class object, or null on error
519      */
getBluetoothClass()520     public BluetoothClass getBluetoothClass() {
521         try {
522             int classInt = sService.getRemoteClass(mAddress);
523             if (classInt == BluetoothClass.ERROR) return null;
524             return new BluetoothClass(classInt);
525         } catch (RemoteException e) {Log.e(TAG, "", e);}
526         return null;
527     }
528 
529     /**
530      * Get trust state of a remote device.
531      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
532      * @hide
533      */
getTrustState()534     public boolean getTrustState() {
535         try {
536             return sService.getTrustState(mAddress);
537         } catch (RemoteException e) {
538             Log.e(TAG, "", e);
539         }
540         return false;
541     }
542 
543     /**
544      * Set trust state for a remote device.
545      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
546      * @param value the trust state value (true or false)
547      * @hide
548      */
setTrust(boolean value)549     public boolean setTrust(boolean value) {
550         try {
551             return sService.setTrust(mAddress, value);
552         } catch (RemoteException e) {
553             Log.e(TAG, "", e);
554         }
555         return false;
556     }
557 
558     /** @hide */
getUuids()559      public ParcelUuid[] getUuids() {
560         try {
561             return sService.getRemoteUuids(mAddress);
562         } catch (RemoteException e) {Log.e(TAG, "", e);}
563         return null;
564     }
565 
566      /**
567       *  Perform a SDP query on the remote device to get the UUIDs
568       *  supported. This API is asynchronous and an Intent is sent,
569       *  with the UUIDs supported by the remote end. If there is an error
570       *  in getting the SDP records or if the process takes a long time,
571       *  an Intent is sent with the UUIDs that is currently present in the
572       *  cache. Clients should use the {@link getUuids} to get UUIDs
573       *  is SDP is not to be performed.
574       *
575       *  @return False if the sanity check fails, True if the process
576       *               of initiating an ACL connection to the remote device
577       *               was started.
578       *  @hide
579       */
fetchUuidsWithSdp()580      public boolean fetchUuidsWithSdp() {
581         try {
582             return sService.fetchRemoteUuids(mAddress, null, null);
583         } catch (RemoteException e) {Log.e(TAG, "", e);}
584         return false;
585     }
586 
587     /** @hide */
getServiceChannel(ParcelUuid uuid)588     public int getServiceChannel(ParcelUuid uuid) {
589          try {
590              return sService.getRemoteServiceChannel(mAddress, uuid);
591          } catch (RemoteException e) {Log.e(TAG, "", e);}
592          return BluetoothDevice.ERROR;
593     }
594 
595     /** @hide */
setPin(byte[] pin)596     public boolean setPin(byte[] pin) {
597         try {
598             return sService.setPin(mAddress, pin);
599         } catch (RemoteException e) {Log.e(TAG, "", e);}
600         return false;
601     }
602 
603     /** @hide */
setPasskey(int passkey)604     public boolean setPasskey(int passkey) {
605         try {
606             return sService.setPasskey(mAddress, passkey);
607         } catch (RemoteException e) {Log.e(TAG, "", e);}
608         return false;
609     }
610 
611     /** @hide */
setPairingConfirmation(boolean confirm)612     public boolean setPairingConfirmation(boolean confirm) {
613         try {
614             return sService.setPairingConfirmation(mAddress, confirm);
615         } catch (RemoteException e) {Log.e(TAG, "", e);}
616         return false;
617     }
618 
619     /** @hide */
cancelPairingUserInput()620     public boolean cancelPairingUserInput() {
621         try {
622             return sService.cancelPairingUserInput(mAddress);
623         } catch (RemoteException e) {Log.e(TAG, "", e);}
624         return false;
625     }
626 
627     /**
628      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
629      * outgoing connection to this remote device on given channel.
630      * <p>The remote device will be authenticated and communication on this
631      * socket will be encrypted.
632      * <p>Use {@link BluetoothSocket#connect} to intiate the outgoing
633      * connection.
634      * <p>Valid RFCOMM channels are in range 1 to 30.
635      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
636      *
637      * @param channel RFCOMM channel to connect to
638      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
639      * @throws IOException on error, for example Bluetooth not available, or
640      *                     insufficient permissions
641      * @hide
642      */
createRfcommSocket(int channel)643     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
644         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
645                 null);
646     }
647 
648     /**
649      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
650      * outgoing connection to this remote device using SDP lookup of uuid.
651      * <p>This is designed to be used with {@link
652      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
653      * Bluetooth applications.
654      * <p>Use {@link BluetoothSocket#connect} to intiate the outgoing
655      * connection. This will also perform an SDP lookup of the given uuid to
656      * determine which channel to connect to.
657      * <p>The remote device will be authenticated and communication on this
658      * socket will be encrypted.
659      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
660      *
661      * @param uuid service record uuid to lookup RFCOMM channel
662      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
663      * @throws IOException on error, for example Bluetooth not available, or
664      *                     insufficient permissions
665      */
createRfcommSocketToServiceRecord(UUID uuid)666     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
667         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
668                 new ParcelUuid(uuid));
669     }
670 
671     /**
672      * Construct an insecure RFCOMM socket ready to start an outgoing
673      * connection.
674      * Call #connect on the returned #BluetoothSocket to begin the connection.
675      * The remote device will not be authenticated and communication on this
676      * socket will not be encrypted.
677      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
678      *
679      * @param port    remote port
680      * @return An RFCOMM BluetoothSocket
681      * @throws IOException On error, for example Bluetooth not available, or
682      *                     insufficient permissions.
683      * @hide
684      */
createInsecureRfcommSocket(int port)685     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
686         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
687                 null);
688     }
689 
690     /**
691      * Construct a SCO socket ready to start an outgoing connection.
692      * Call #connect on the returned #BluetoothSocket to begin the connection.
693      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
694      *
695      * @return a SCO BluetoothSocket
696      * @throws IOException on error, for example Bluetooth not available, or
697      *                     insufficient permissions.
698      * @hide
699      */
createScoSocket()700     public BluetoothSocket createScoSocket() throws IOException {
701         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
702     }
703 
704     /**
705      * Check that a pin is valid and convert to byte array.
706      *
707      * Bluetooth pin's are 1 to 16 bytes of UTF8 characters.
708      * @param pin pin as java String
709      * @return the pin code as a UTF8 byte array, or null if it is an invalid
710      *         Bluetooth pin.
711      * @hide
712      */
convertPinToBytes(String pin)713     public static byte[] convertPinToBytes(String pin) {
714         if (pin == null) {
715             return null;
716         }
717         byte[] pinBytes;
718         try {
719             pinBytes = pin.getBytes("UTF8");
720         } catch (UnsupportedEncodingException uee) {
721             Log.e(TAG, "UTF8 not supported?!?");  // this should not happen
722             return null;
723         }
724         if (pinBytes.length <= 0 || pinBytes.length > 16) {
725             return null;
726         }
727         return pinBytes;
728     }
729 
730 }
731