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.Manifest;
20 import android.annotation.RequiresPermission;
21 import android.annotation.SdkConstant;
22 import android.annotation.SdkConstant.SdkConstantType;
23 import android.annotation.SystemApi;
24 import android.content.Context;
25 import android.os.Handler;
26 import android.os.Looper;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 import android.os.ParcelUuid;
30 import android.os.Process;
31 import android.os.RemoteException;
32 import android.util.Log;
33 
34 import java.io.IOException;
35 import java.io.UnsupportedEncodingException;
36 import java.util.UUID;
37 
38 /**
39  * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
40  * create a connection with the respective device or query information about
41  * it, such as the name, address, class, and bonding state.
42  *
43  * <p>This class is really just a thin wrapper for a Bluetooth hardware
44  * address. Objects of this class are immutable. Operations on this class
45  * are performed on the remote Bluetooth hardware address, using the
46  * {@link BluetoothAdapter} that was used to create this {@link
47  * BluetoothDevice}.
48  *
49  * <p>To get a {@link BluetoothDevice}, use
50  * {@link BluetoothAdapter#getRemoteDevice(String)
51  * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device
52  * of a known MAC address (which you can get through device discovery with
53  * {@link BluetoothAdapter}) or get one from the set of bonded devices
54  * returned by {@link BluetoothAdapter#getBondedDevices()
55  * BluetoothAdapter.getBondedDevices()}. You can then open a
56  * {@link BluetoothSocket} for communication with the remote device, using
57  * {@link #createRfcommSocketToServiceRecord(UUID)}.
58  *
59  * <p class="note"><strong>Note:</strong>
60  * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
61  *
62  * <div class="special reference">
63  * <h3>Developer Guides</h3>
64  * <p>
65  * For more information about using Bluetooth, read the <a href=
66  * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
67  * guide.
68  * </p>
69  * </div>
70  *
71  * {@see BluetoothAdapter}
72  * {@see BluetoothSocket}
73  */
74 public final class BluetoothDevice implements Parcelable {
75     private static final String TAG = "BluetoothDevice";
76     private static final boolean DBG = false;
77 
78     /**
79      * Connection state bitmask as returned by getConnectionState.
80      */
81     private static final int CONNECTION_STATE_DISCONNECTED = 0;
82     private static final int CONNECTION_STATE_CONNECTED = 1;
83     private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2;
84     private static final int CONNECTION_STATE_ENCRYPTED_LE = 4;
85 
86     /**
87      * Sentinel error value for this class. Guaranteed to not equal any other
88      * integer constant in this class. Provided as a convenience for functions
89      * that require a sentinel error value, for example:
90      * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
91      * BluetoothDevice.ERROR)</code>
92      */
93     public static final int ERROR = Integer.MIN_VALUE;
94 
95     /**
96      * Broadcast Action: Remote device discovered.
97      * <p>Sent when a remote device is found during discovery.
98      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
99      * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
100      * {@link #EXTRA_RSSI} if they are available.
101      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} and
102      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive.
103      */
104      // TODO: Change API to not broadcast RSSI if not available (incoming connection)
105     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
106     public static final String ACTION_FOUND =
107             "android.bluetooth.device.action.FOUND";
108 
109     /**
110      * Broadcast Action: Remote device disappeared.
111      * <p>Sent when a remote device that was found in the last discovery is not
112      * found in the current discovery.
113      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
114      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
115      * @hide
116      */
117     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
118     public static final String ACTION_DISAPPEARED =
119             "android.bluetooth.device.action.DISAPPEARED";
120 
121     /**
122      * Broadcast Action: Bluetooth class of a remote device has changed.
123      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
124      * #EXTRA_CLASS}.
125      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
126      * {@see BluetoothClass}
127      */
128     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
129     public static final String ACTION_CLASS_CHANGED =
130             "android.bluetooth.device.action.CLASS_CHANGED";
131 
132     /**
133      * Broadcast Action: Indicates a low level (ACL) connection has been
134      * established with a remote device.
135      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
136      * <p>ACL connections are managed automatically by the Android Bluetooth
137      * stack.
138      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
139      */
140     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
141     public static final String ACTION_ACL_CONNECTED =
142             "android.bluetooth.device.action.ACL_CONNECTED";
143 
144     /**
145      * Broadcast Action: Indicates that a low level (ACL) disconnection has
146      * been requested for a remote device, and it will soon be disconnected.
147      * <p>This is useful for graceful disconnection. Applications should use
148      * this intent as a hint to immediately terminate higher level connections
149      * (RFCOMM, L2CAP, or profile connections) to the remote device.
150      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
151      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
152      */
153     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
154     public static final String ACTION_ACL_DISCONNECT_REQUESTED =
155             "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
156 
157     /**
158      * Broadcast Action: Indicates a low level (ACL) disconnection from a
159      * remote device.
160      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
161      * <p>ACL connections are managed automatically by the Android Bluetooth
162      * stack.
163      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
164      */
165     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
166     public static final String ACTION_ACL_DISCONNECTED =
167             "android.bluetooth.device.action.ACL_DISCONNECTED";
168 
169     /**
170      * Broadcast Action: Indicates the friendly name of a remote device has
171      * been retrieved for the first time, or changed since the last retrieval.
172      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
173      * #EXTRA_NAME}.
174      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
175      */
176     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
177     public static final String ACTION_NAME_CHANGED =
178             "android.bluetooth.device.action.NAME_CHANGED";
179 
180     /**
181      * Broadcast Action: Indicates the alias of a remote device has been
182      * changed.
183      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
184      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
185      *
186      * @hide
187      */
188     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
189     public static final String ACTION_ALIAS_CHANGED =
190             "android.bluetooth.device.action.ALIAS_CHANGED";
191 
192     /**
193      * Broadcast Action: Indicates a change in the bond state of a remote
194      * device. For example, if a device is bonded (paired).
195      * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
196      * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
197      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
198      */
199     // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
200     // contain a hidden extra field EXTRA_REASON with the result code.
201     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
202     public static final String ACTION_BOND_STATE_CHANGED =
203             "android.bluetooth.device.action.BOND_STATE_CHANGED";
204 
205     /**
206      * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
207      * broadcast by this class. It contains the {@link BluetoothDevice} that
208      * the intent applies to.
209      */
210     public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
211 
212     /**
213      * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
214      * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
215      */
216     public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
217 
218     /**
219      * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
220      * Contains the RSSI value of the remote device as reported by the
221      * Bluetooth hardware.
222      */
223     public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
224 
225     /**
226      * Used as a Parcelable {@link BluetoothClass} extra field in {@link
227      * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
228      */
229     public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
230 
231     /**
232      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
233      * Contains the bond state of the remote device.
234      * <p>Possible values are:
235      * {@link #BOND_NONE},
236      * {@link #BOND_BONDING},
237      * {@link #BOND_BONDED}.
238      */
239     public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
240     /**
241      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
242      * Contains the previous bond state of the remote device.
243      * <p>Possible values are:
244      * {@link #BOND_NONE},
245      * {@link #BOND_BONDING},
246      * {@link #BOND_BONDED}.
247      */
248     public static final String EXTRA_PREVIOUS_BOND_STATE =
249             "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
250     /**
251      * Indicates the remote device is not bonded (paired).
252      * <p>There is no shared link key with the remote device, so communication
253      * (if it is allowed at all) will be unauthenticated and unencrypted.
254      */
255     public static final int BOND_NONE = 10;
256     /**
257      * Indicates bonding (pairing) is in progress with the remote device.
258      */
259     public static final int BOND_BONDING = 11;
260     /**
261      * Indicates the remote device is bonded (paired).
262      * <p>A shared link keys exists locally for the remote device, so
263      * communication can be authenticated and encrypted.
264      * <p><i>Being bonded (paired) with a remote device does not necessarily
265      * mean the device is currently connected. It just means that the pending
266      * procedure was completed at some earlier time, and the link key is still
267      * stored locally, ready to use on the next connection.
268      * </i>
269      */
270     public static final int BOND_BONDED = 12;
271 
272     /**
273      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
274      * intents for unbond reason.
275      * @hide
276      */
277     public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
278 
279     /**
280      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
281      * intents to indicate pairing method used. Possible values are:
282      * {@link #PAIRING_VARIANT_PIN},
283      * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION},
284      */
285     public static final String EXTRA_PAIRING_VARIANT =
286             "android.bluetooth.device.extra.PAIRING_VARIANT";
287 
288     /**
289      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
290      * intents as the value of passkey.
291      */
292     public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
293 
294     /**
295      * Bluetooth device type, Unknown
296      */
297     public static final int DEVICE_TYPE_UNKNOWN = 0;
298 
299     /**
300      * Bluetooth device type, Classic - BR/EDR devices
301      */
302     public static final int DEVICE_TYPE_CLASSIC = 1;
303 
304     /**
305      * Bluetooth device type, Low Energy - LE-only
306      */
307     public static final int DEVICE_TYPE_LE = 2;
308 
309     /**
310      * Bluetooth device type, Dual Mode - BR/EDR/LE
311      */
312     public static final int DEVICE_TYPE_DUAL = 3;
313 
314 
315     /** @hide */
316     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
317     public static final String ACTION_SDP_RECORD =
318             "android.bluetooth.device.action.SDP_RECORD";
319 
320     /**
321      * Broadcast Action: This intent is used to broadcast the {@link UUID}
322      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
323      * has been fetched. This intent is sent only when the UUIDs of the remote
324      * device are requested to be fetched using Service Discovery Protocol
325      * <p> Always contains the extra field {@link #EXTRA_DEVICE}
326      * <p> Always contains the extra field {@link #EXTRA_UUID}
327      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
328      */
329     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
330     public static final String ACTION_UUID =
331             "android.bluetooth.device.action.UUID";
332 
333     /** @hide */
334     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
335     public static final String ACTION_MAS_INSTANCE =
336             "android.bluetooth.device.action.MAS_INSTANCE";
337 
338     /**
339      * Broadcast Action: Indicates a failure to retrieve the name of a remote
340      * device.
341      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
342      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
343      * @hide
344      */
345     //TODO: is this actually useful?
346     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
347     public static final String ACTION_NAME_FAILED =
348             "android.bluetooth.device.action.NAME_FAILED";
349 
350     /**
351      * Broadcast Action: This intent is used to broadcast PAIRING REQUEST
352      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to
353      * receive.
354      */
355     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
356     public static final String ACTION_PAIRING_REQUEST =
357             "android.bluetooth.device.action.PAIRING_REQUEST";
358     /** @hide */
359     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
360     public static final String ACTION_PAIRING_CANCEL =
361             "android.bluetooth.device.action.PAIRING_CANCEL";
362 
363     /** @hide */
364     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
365     public static final String ACTION_CONNECTION_ACCESS_REQUEST =
366             "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
367 
368     /** @hide */
369     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
370     public static final String ACTION_CONNECTION_ACCESS_REPLY =
371             "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
372 
373     /** @hide */
374     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
375     public static final String ACTION_CONNECTION_ACCESS_CANCEL =
376             "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
377 
378     /**
379      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
380      * @hide
381      */
382     public static final String EXTRA_ACCESS_REQUEST_TYPE =
383         "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE";
384 
385     /**@hide*/
386     public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1;
387 
388     /**@hide*/
389     public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
390 
391     /**@hide*/
392     public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3;
393 
394     /**@hide*/
395     public static final int REQUEST_TYPE_SIM_ACCESS = 4;
396 
397     /**
398      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
399      * Contains package name to return reply intent to.
400      * @hide
401      */
402     public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME";
403 
404     /**
405      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
406      * Contains class name to return reply intent to.
407      * @hide
408      */
409     public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME";
410 
411     /**
412      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
413      * @hide
414      */
415     public static final String EXTRA_CONNECTION_ACCESS_RESULT =
416         "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
417 
418     /**@hide*/
419     public static final int CONNECTION_ACCESS_YES = 1;
420 
421     /**@hide*/
422     public static final int CONNECTION_ACCESS_NO = 2;
423 
424     /**
425      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents,
426      * Contains boolean to indicate if the allowed response is once-for-all so that
427      * next request will be granted without asking user again.
428      * @hide
429      */
430     public static final String EXTRA_ALWAYS_ALLOWED =
431         "android.bluetooth.device.extra.ALWAYS_ALLOWED";
432 
433     /**
434      * A bond attempt succeeded
435      * @hide
436      */
437     public static final int BOND_SUCCESS = 0;
438 
439     /**
440      * A bond attempt failed because pins did not match, or remote device did
441      * not respond to pin request in time
442      * @hide
443      */
444     public static final int UNBOND_REASON_AUTH_FAILED = 1;
445 
446     /**
447      * A bond attempt failed because the other side explicitly rejected
448      * bonding
449      * @hide
450      */
451     public static final int UNBOND_REASON_AUTH_REJECTED = 2;
452 
453     /**
454      * A bond attempt failed because we canceled the bonding process
455      * @hide
456      */
457     public static final int UNBOND_REASON_AUTH_CANCELED = 3;
458 
459     /**
460      * A bond attempt failed because we could not contact the remote device
461      * @hide
462      */
463     public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
464 
465     /**
466      * A bond attempt failed because a discovery is in progress
467      * @hide
468      */
469     public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
470 
471     /**
472      * A bond attempt failed because of authentication timeout
473      * @hide
474      */
475     public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
476 
477     /**
478      * A bond attempt failed because of repeated attempts
479      * @hide
480      */
481     public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
482 
483     /**
484      * A bond attempt failed because we received an Authentication Cancel
485      * by remote end
486      * @hide
487      */
488     public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
489 
490     /**
491      * An existing bond was explicitly revoked
492      * @hide
493      */
494     public static final int UNBOND_REASON_REMOVED = 9;
495 
496     /**
497      * The user will be prompted to enter a pin or
498      * an app will enter a pin for user.
499      */
500     public static final int PAIRING_VARIANT_PIN = 0;
501 
502     /**
503      * The user will be prompted to enter a passkey
504      * @hide
505      */
506     public static final int PAIRING_VARIANT_PASSKEY = 1;
507 
508     /**
509      * The user will be prompted to confirm the passkey displayed on the screen or
510      * an app will confirm the passkey for the user.
511      */
512     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
513 
514     /**
515      * The user will be prompted to accept or deny the incoming pairing request
516      * @hide
517      */
518     public static final int PAIRING_VARIANT_CONSENT = 3;
519 
520     /**
521      * The user will be prompted to enter the passkey displayed on remote device
522      * This is used for Bluetooth 2.1 pairing.
523      * @hide
524      */
525     public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
526 
527     /**
528      * The user will be prompted to enter the PIN displayed on remote device.
529      * This is used for Bluetooth 2.0 pairing.
530      * @hide
531      */
532     public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
533 
534     /**
535      * The user will be prompted to accept or deny the OOB pairing request
536      * @hide
537      */
538     public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
539 
540     /**
541      * The user will be prompted to enter a 16 digit pin or
542      * an app will enter a 16 digit pin for user.
543      * @hide
544      */
545     public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7;
546 
547     /**
548      * Used as an extra field in {@link #ACTION_UUID} intents,
549      * Contains the {@link android.os.ParcelUuid}s of the remote device which
550      * is a parcelable version of {@link UUID}.
551      */
552     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
553 
554     /** @hide */
555     public static final String EXTRA_SDP_RECORD =
556         "android.bluetooth.device.extra.SDP_RECORD";
557 
558     /** @hide */
559     public static final String EXTRA_SDP_SEARCH_STATUS =
560             "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
561     /**
562      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
563      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
564      * @hide
565      */
566     public static final int ACCESS_UNKNOWN = 0;
567 
568     /**
569      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
570      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
571      * @hide
572      */
573     public static final int ACCESS_ALLOWED = 1;
574 
575     /**
576      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
577      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
578      * @hide
579      */
580     public static final int ACCESS_REJECTED = 2;
581 
582      /**
583       * No preferrence of physical transport for GATT connections to remote dual-mode devices
584       */
585     public static final int TRANSPORT_AUTO = 0;
586 
587     /**
588      * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
589      */
590     public static final int TRANSPORT_BREDR = 1;
591 
592     /**
593      * Prefer LE transport for GATT connections to remote dual-mode devices
594      */
595     public static final int TRANSPORT_LE = 2;
596 
597     /**
598      * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or
599      * connection.
600      */
601     public static final int PHY_LE_1M = 1;
602 
603     /**
604      * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or
605      * connection.
606      */
607     public static final int PHY_LE_2M = 2;
608 
609     /**
610      * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning
611      * or connection.
612      */
613     public static final int PHY_LE_CODED = 3;
614 
615     /**
616      * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available
617      * options in a bitmask.
618      */
619     public static final int PHY_LE_1M_MASK = 1;
620 
621     /**
622      * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available
623      * options in a bitmask.
624      */
625     public static final int PHY_LE_2M_MASK = 2;
626 
627     /**
628      * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many
629      * available options in a bitmask.
630      */
631     public static final int PHY_LE_CODED_MASK = 4;
632 
633     /**
634      * No preferred coding when transmitting on the LE Coded PHY.
635      */
636     public static final int PHY_OPTION_NO_PREFERRED = 0;
637 
638     /**
639      * Prefer the S=2 coding to be used when transmitting on the LE Coded PHY.
640      */
641     public static final int PHY_OPTION_S2 = 1;
642 
643     /**
644      * Prefer the S=8 coding to be used when transmitting on the LE Coded PHY.
645      */
646     public static final int PHY_OPTION_S8 = 2;
647 
648 
649     /** @hide */
650     public static final String EXTRA_MAS_INSTANCE =
651         "android.bluetooth.device.extra.MAS_INSTANCE";
652 
653     /**
654      * Lazy initialization. Guaranteed final after first object constructed, or
655      * getService() called.
656      * TODO: Unify implementation of sService amongst BluetoothFoo API's
657      */
658     private static IBluetooth sService;
659 
660     private final String mAddress;
661 
getService()662     /*package*/ static IBluetooth getService() {
663         synchronized (BluetoothDevice.class) {
664             if (sService == null) {
665                 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
666                 sService = adapter.getBluetoothService(mStateChangeCallback);
667             }
668         }
669         return sService;
670     }
671 
672     static IBluetoothManagerCallback mStateChangeCallback = new IBluetoothManagerCallback.Stub() {
673 
674         public void onBluetoothServiceUp(IBluetooth bluetoothService)
675                 throws RemoteException {
676             synchronized (BluetoothDevice.class) {
677                 if (sService == null) {
678                     sService = bluetoothService;
679                 }
680             }
681         }
682 
683         public void onBluetoothServiceDown()
684             throws RemoteException {
685             synchronized (BluetoothDevice.class) {
686                 sService = null;
687             }
688         }
689 
690         public void onBrEdrDown()
691         {
692             if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state");
693         }
694     };
695     /**
696      * Create a new BluetoothDevice
697      * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
698      * and is validated in this constructor.
699      * @param address valid Bluetooth MAC address
700      * @throws RuntimeException Bluetooth is not available on this platform
701      * @throws IllegalArgumentException address is invalid
702      * @hide
703      */
BluetoothDevice(String address)704     /*package*/ BluetoothDevice(String address) {
705         getService();  // ensures sService is initialized
706         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
707             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
708         }
709 
710         mAddress = address;
711     }
712 
713     @Override
equals(Object o)714     public boolean equals(Object o) {
715         if (o instanceof BluetoothDevice) {
716             return mAddress.equals(((BluetoothDevice)o).getAddress());
717         }
718         return false;
719     }
720 
721     @Override
hashCode()722     public int hashCode() {
723         return mAddress.hashCode();
724     }
725 
726     /**
727      * Returns a string representation of this BluetoothDevice.
728      * <p>Currently this is the Bluetooth hardware address, for example
729      * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
730      * if you explicitly require the Bluetooth hardware address in case the
731      * {@link #toString} representation changes in the future.
732      * @return string representation of this BluetoothDevice
733      */
734     @Override
toString()735     public String toString() {
736         return mAddress;
737     }
738 
describeContents()739     public int describeContents() {
740         return 0;
741     }
742 
743     public static final Parcelable.Creator<BluetoothDevice> CREATOR =
744             new Parcelable.Creator<BluetoothDevice>() {
745         public BluetoothDevice createFromParcel(Parcel in) {
746             return new BluetoothDevice(in.readString());
747         }
748         public BluetoothDevice[] newArray(int size) {
749             return new BluetoothDevice[size];
750         }
751     };
752 
writeToParcel(Parcel out, int flags)753     public void writeToParcel(Parcel out, int flags) {
754         out.writeString(mAddress);
755     }
756 
757     /**
758      * Returns the hardware address of this BluetoothDevice.
759      * <p> For example, "00:11:22:AA:BB:CC".
760      * @return Bluetooth hardware address as string
761      */
getAddress()762     public String getAddress() {
763         if (DBG) Log.d(TAG, "mAddress: " + mAddress);
764         return mAddress;
765     }
766 
767     /**
768      * Get the friendly Bluetooth name of the remote device.
769      *
770      * <p>The local adapter will automatically retrieve remote names when
771      * performing a device scan, and will cache them. This method just returns
772      * the name for this device from the cache.
773      *
774      * @return the Bluetooth name, or null if there was a problem.
775      */
776     @RequiresPermission(Manifest.permission.BLUETOOTH)
getName()777     public String getName() {
778         if (sService == null) {
779             Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
780             return null;
781         }
782         try {
783             return sService.getRemoteName(this);
784         } catch (RemoteException e) {Log.e(TAG, "", e);}
785         return null;
786     }
787 
788     /**
789      * Get the Bluetooth device type of the remote device.
790      *
791      * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE}
792      *                         {@link #DEVICE_TYPE_DUAL}.
793      *         {@link #DEVICE_TYPE_UNKNOWN} if it's not available
794      */
795     @RequiresPermission(Manifest.permission.BLUETOOTH)
getType()796     public int getType() {
797         if (sService == null) {
798             Log.e(TAG, "BT not enabled. Cannot get Remote Device type");
799             return DEVICE_TYPE_UNKNOWN;
800         }
801         try {
802             return sService.getRemoteType(this);
803         } catch (RemoteException e) {Log.e(TAG, "", e);}
804         return DEVICE_TYPE_UNKNOWN;
805     }
806 
807     /**
808      * Get the Bluetooth alias of the remote device.
809      * <p>Alias is the locally modified name of a remote device.
810      *
811      * @return the Bluetooth alias, or null if no alias or there was a problem
812      * @hide
813      */
getAlias()814     public String getAlias() {
815         if (sService == null) {
816             Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias");
817             return null;
818         }
819         try {
820             return sService.getRemoteAlias(this);
821         } catch (RemoteException e) {Log.e(TAG, "", e);}
822         return null;
823     }
824 
825     /**
826      * Set the Bluetooth alias of the remote device.
827      * <p>Alias is the locally modified name of a remote device.
828      * <p>This methoid overwrites the alias. The changed
829      * alias is saved in the local storage so that the change
830      * is preserved over power cycle.
831      *
832      * @return true on success, false on error
833      * @hide
834      */
setAlias(String alias)835     public boolean setAlias(String alias) {
836         if (sService == null) {
837             Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
838             return false;
839         }
840         try {
841             return sService.setRemoteAlias(this, alias);
842         } catch (RemoteException e) {Log.e(TAG, "", e);}
843         return false;
844     }
845 
846     /**
847      * Get the Bluetooth alias of the remote device.
848      * If Alias is null, get the Bluetooth name instead.
849      * @see #getAlias()
850      * @see #getName()
851      *
852      * @return the Bluetooth alias, or null if no alias or there was a problem
853      * @hide
854      */
getAliasName()855     public String getAliasName() {
856         String name = getAlias();
857         if (name == null) {
858             name = getName();
859         }
860         return name;
861     }
862 
863     /**
864      * Start the bonding (pairing) process with the remote device.
865      * <p>This is an asynchronous call, it will return immediately. Register
866      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
867      * the bonding process completes, and its result.
868      * <p>Android system services will handle the necessary user interactions
869      * to confirm and complete the bonding process.
870      *
871      * @return false on immediate error, true if bonding will begin
872      */
873     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
createBond()874     public boolean createBond() {
875         if (sService == null) {
876             Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
877             return false;
878         }
879         try {
880             Log.i(TAG, "createBond() for device " + getAddress() +
881                     " called by pid: " + Process.myPid() +
882                     " tid: " + Process.myTid());
883             return sService.createBond(this, TRANSPORT_AUTO);
884         } catch (RemoteException e) {Log.e(TAG, "", e);}
885         return false;
886     }
887 
888     /**
889      * Start the bonding (pairing) process with the remote device using the
890      * specified transport.
891      *
892      * <p>This is an asynchronous call, it will return immediately. Register
893      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
894      * the bonding process completes, and its result.
895      * <p>Android system services will handle the necessary user interactions
896      * to confirm and complete the bonding process.
897      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
898      *
899      * @param transport The transport to use for the pairing procedure.
900      * @return false on immediate error, true if bonding will begin
901      * @throws IllegalArgumentException if an invalid transport was specified
902      * @hide
903      */
createBond(int transport)904     public boolean createBond(int transport) {
905         if (sService == null) {
906             Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
907             return false;
908         }
909         if (TRANSPORT_AUTO > transport || transport > TRANSPORT_LE)
910         {
911             throw new IllegalArgumentException(transport + " is not a valid Bluetooth transport");
912         }
913         try {
914             Log.i(TAG, "createBond() for device " + getAddress() +
915                     " called by pid: " + Process.myPid() +
916                     " tid: " + Process.myTid());
917             return sService.createBond(this, transport);
918         } catch (RemoteException e) {Log.e(TAG, "", e);}
919         return false;
920     }
921 
922     /**
923      * Start the bonding (pairing) process with the remote device using the
924      * Out Of Band mechanism.
925      *
926      * <p>This is an asynchronous call, it will return immediately. Register
927      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
928      * the bonding process completes, and its result.
929      *
930      * <p>Android system services will handle the necessary user interactions
931      * to confirm and complete the bonding process.
932      *
933      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
934      *
935      * @param transport - Transport to use
936      * @param oobData - Out Of Band data
937      * @return false on immediate error, true if bonding will begin
938      *
939      * @hide
940      */
createBondOutOfBand(int transport, OobData oobData)941     public boolean createBondOutOfBand(int transport, OobData oobData) {
942         try {
943             return sService.createBondOutOfBand(this, transport, oobData);
944         } catch (RemoteException e) {Log.e(TAG, "", e);}
945         return false;
946     }
947 
948     /** @hide */
isBondingInitiatedLocally()949     public boolean isBondingInitiatedLocally() {
950         try {
951             return sService.isBondingInitiatedLocally(this);
952         } catch (RemoteException e) {Log.e(TAG, "", e);}
953         return false;
954     }
955 
956     /**
957      * Set the Out Of Band data for a remote device to be used later
958      * in the pairing mechanism. Users can obtain this data through other
959      * trusted channels
960      *
961      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
962      *
963      * @param hash Simple Secure pairing hash
964      * @param randomizer The random key obtained using OOB
965      * @return false on error; true otherwise
966      *
967      * @hide
968      */
setDeviceOutOfBandData(byte[] hash, byte[] randomizer)969     public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
970       //TODO(BT)
971       /*
972       try {
973         return sService.setDeviceOutOfBandData(this, hash, randomizer);
974       } catch (RemoteException e) {Log.e(TAG, "", e);} */
975       return false;
976     }
977 
978     /**
979      * Cancel an in-progress bonding request started with {@link #createBond}.
980      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
981      *
982      * @return true on success, false on error
983      * @hide
984      */
cancelBondProcess()985     public boolean cancelBondProcess() {
986         if (sService == null) {
987             Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
988             return false;
989         }
990         try {
991             Log.i(TAG, "cancelBondProcess() for device " + getAddress() +
992                     " called by pid: " + Process.myPid() +
993                     " tid: " + Process.myTid());
994             return sService.cancelBondProcess(this);
995         } catch (RemoteException e) {Log.e(TAG, "", e);}
996         return false;
997     }
998 
999     /**
1000      * Remove bond (pairing) with the remote device.
1001      * <p>Delete the link key associated with the remote device, and
1002      * immediately terminate connections to that device that require
1003      * authentication and encryption.
1004      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1005      *
1006      * @return true on success, false on error
1007      * @hide
1008      */
removeBond()1009     public boolean removeBond() {
1010         if (sService == null) {
1011             Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
1012             return false;
1013         }
1014         try {
1015             Log.i(TAG, "removeBond() for device " + getAddress() +
1016                     " called by pid: " + Process.myPid() +
1017                     " tid: " + Process.myTid());
1018             return sService.removeBond(this);
1019         } catch (RemoteException e) {Log.e(TAG, "", e);}
1020         return false;
1021     }
1022 
1023     /**
1024      * Get the bond state of the remote device.
1025      * <p>Possible values for the bond state are:
1026      * {@link #BOND_NONE},
1027      * {@link #BOND_BONDING},
1028      * {@link #BOND_BONDED}.
1029      *
1030      * @return the bond state
1031      */
1032     @RequiresPermission(Manifest.permission.BLUETOOTH)
getBondState()1033     public int getBondState() {
1034         if (sService == null) {
1035             Log.e(TAG, "BT not enabled. Cannot get bond state");
1036             return BOND_NONE;
1037         }
1038         try {
1039             return sService.getBondState(this);
1040         } catch (RemoteException e) {Log.e(TAG, "", e);}
1041         catch (NullPointerException npe) {
1042             // Handle case where bluetooth service proxy
1043             // is already null.
1044             Log.e(TAG, "NullPointerException for getBondState() of device ("+
1045                 getAddress()+")", npe);
1046         }
1047         return BOND_NONE;
1048     }
1049 
1050     /**
1051      * Returns whether there is an open connection to this device.
1052      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1053      *
1054      * @return True if there is at least one open connection to this device.
1055      * @hide
1056      */
1057     @SystemApi
isConnected()1058     public boolean isConnected() {
1059         if (sService == null) {
1060             // BT is not enabled, we cannot be connected.
1061             return false;
1062         }
1063         try {
1064             return sService.getConnectionState(this) != CONNECTION_STATE_DISCONNECTED;
1065         } catch (RemoteException e) {
1066             Log.e(TAG, "", e);
1067             return false;
1068         }
1069     }
1070 
1071     /**
1072      * Returns whether there is an open connection to this device
1073      * that has been encrypted.
1074      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1075      *
1076      * @return True if there is at least one encrypted connection to this device.
1077      * @hide
1078      */
1079     @SystemApi
isEncrypted()1080     public boolean isEncrypted() {
1081         if (sService == null) {
1082             // BT is not enabled, we cannot be connected.
1083             return false;
1084         }
1085         try {
1086             return sService.getConnectionState(this) > CONNECTION_STATE_CONNECTED;
1087         } catch (RemoteException e) {
1088             Log.e(TAG, "", e);
1089             return false;
1090         }
1091     }
1092 
1093     /**
1094      * Get the Bluetooth class of the remote device.
1095      *
1096      * @return Bluetooth class object, or null on error
1097      */
1098     @RequiresPermission(Manifest.permission.BLUETOOTH)
getBluetoothClass()1099     public BluetoothClass getBluetoothClass() {
1100         if (sService == null) {
1101             Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
1102             return null;
1103         }
1104         try {
1105             int classInt = sService.getRemoteClass(this);
1106             if (classInt == BluetoothClass.ERROR) return null;
1107             return new BluetoothClass(classInt);
1108         } catch (RemoteException e) {Log.e(TAG, "", e);}
1109         return null;
1110     }
1111 
1112     /**
1113      * Returns the supported features (UUIDs) of the remote device.
1114      *
1115      * <p>This method does not start a service discovery procedure to retrieve the UUIDs
1116      * from the remote device. Instead, the local cached copy of the service
1117      * UUIDs are returned.
1118      * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired.
1119      *
1120      * @return the supported features (UUIDs) of the remote device,
1121      *         or null on error
1122      */
1123     @RequiresPermission(Manifest.permission.BLUETOOTH)
getUuids()1124      public ParcelUuid[] getUuids() {
1125          if (sService == null || isBluetoothEnabled() == false) {
1126             Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
1127              return null;
1128          }
1129         try {
1130             return sService.getRemoteUuids(this);
1131         } catch (RemoteException e) {Log.e(TAG, "", e);}
1132         return null;
1133     }
1134 
1135      /**
1136       * Perform a service discovery on the remote device to get the UUIDs supported.
1137       *
1138       * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
1139       * with the UUIDs supported by the remote end. If there is an error
1140       * in getting the SDP records or if the process takes a long time,
1141       * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently
1142       * present in the cache. Clients should use the {@link #getUuids} to get UUIDs
1143       * if service discovery is not to be performed.
1144       *
1145       * @return False if the sanity check fails, True if the process
1146       *               of initiating an ACL connection to the remote device
1147       *               was started.
1148       */
1149      @RequiresPermission(Manifest.permission.BLUETOOTH)
fetchUuidsWithSdp()1150      public boolean fetchUuidsWithSdp() {
1151         IBluetooth service = sService;
1152         if (service == null || isBluetoothEnabled() == false) {
1153             Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
1154             return false;
1155         }
1156         try {
1157             return service.fetchRemoteUuids(this);
1158         } catch (RemoteException e) {Log.e(TAG, "", e);}
1159             return false;
1160     }
1161 
1162      /**
1163       * Perform a service discovery on the remote device to get the SDP records associated
1164       * with the specified UUID.
1165       *
1166       * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent,
1167       * with the SDP records found on the remote end. If there is an error
1168       * in getting the SDP records or if the process takes a long time,
1169       * {@link #ACTION_SDP_RECORD} intent is sent with an status value in
1170       * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
1171       * Detailed status error codes can be found by members of the Bluetooth package in
1172       * the AbstractionLayer class.
1173       * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1174       * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
1175       * The object type will match one of the SdpXxxRecord types, depending on the UUID searched
1176       * for.
1177       *
1178       * @return False if the sanity check fails, True if the process
1179       *               of initiating an ACL connection to the remote device
1180       *               was started.
1181       */
1182      /** @hide */
sdpSearch(ParcelUuid uuid)1183      public boolean sdpSearch(ParcelUuid uuid) {
1184          if (sService == null) {
1185              Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
1186              return false;
1187          }
1188          try {
1189              return sService.sdpSearch(this,uuid);
1190          } catch (RemoteException e) {Log.e(TAG, "", e);}
1191          return false;
1192      }
1193 
1194     /**
1195      * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
1196      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1197      *
1198      * @return true pin has been set
1199      *         false for error
1200      */
setPin(byte[] pin)1201     public boolean setPin(byte[] pin) {
1202         if (sService == null) {
1203             Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
1204             return false;
1205         }
1206         try {
1207             return sService.setPin(this, true, pin.length, pin);
1208         } catch (RemoteException e) {Log.e(TAG, "", e);}
1209         return false;
1210     }
1211 
1212     /** @hide */
setPasskey(int passkey)1213     public boolean setPasskey(int passkey) {
1214         //TODO(BT)
1215         /*
1216         try {
1217             return sService.setPasskey(this, true, 4, passkey);
1218         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1219         return false;
1220     }
1221 
1222     /**
1223      * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
1224      *
1225      * @return true confirmation has been sent out
1226      *         false for error
1227      */
1228     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
setPairingConfirmation(boolean confirm)1229     public boolean setPairingConfirmation(boolean confirm) {
1230         if (sService == null) {
1231             Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
1232             return false;
1233         }
1234         try {
1235             return sService.setPairingConfirmation(this, confirm);
1236         } catch (RemoteException e) {Log.e(TAG, "", e);}
1237         return false;
1238     }
1239 
1240     /** @hide */
setRemoteOutOfBandData()1241     public boolean setRemoteOutOfBandData() {
1242         // TODO(BT)
1243         /*
1244         try {
1245           return sService.setRemoteOutOfBandData(this);
1246       } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1247       return false;
1248     }
1249 
1250     /** @hide */
cancelPairingUserInput()1251     public boolean cancelPairingUserInput() {
1252         if (sService == null) {
1253             Log.e(TAG, "BT not enabled. Cannot create pairing user input");
1254             return false;
1255         }
1256         try {
1257             return sService.cancelBondProcess(this);
1258         } catch (RemoteException e) {Log.e(TAG, "", e);}
1259         return false;
1260     }
1261 
1262     /** @hide */
isBluetoothDock()1263     public boolean isBluetoothDock() {
1264         // TODO(BT)
1265         /*
1266         try {
1267             return sService.isBluetoothDock(this);
1268         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1269         return false;
1270     }
1271 
isBluetoothEnabled()1272      boolean isBluetoothEnabled() {
1273          boolean ret = false;
1274          BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1275          if (adapter != null && adapter.isEnabled() == true) {
1276              ret = true;
1277          }
1278          return ret;
1279      }
1280 
1281     /**
1282      * Requires {@link android.Manifest.permission#BLUETOOTH}.
1283      * @return Whether the phonebook access is allowed to this device. Can be
1284      *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
1285      * @hide
1286      */
getPhonebookAccessPermission()1287     public int getPhonebookAccessPermission() {
1288         if (sService == null) {
1289             return ACCESS_UNKNOWN;
1290         }
1291         try {
1292             return sService.getPhonebookAccessPermission(this);
1293         } catch (RemoteException e) {
1294             Log.e(TAG, "", e);
1295         }
1296         return ACCESS_UNKNOWN;
1297     }
1298 
1299     /**
1300      * Sets whether the phonebook access is allowed to this device.
1301      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1302      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
1303      *              {@link #ACCESS_REJECTED}.
1304      * @return Whether the value has been successfully set.
1305      * @hide
1306      */
setPhonebookAccessPermission(int value)1307     public boolean setPhonebookAccessPermission(int value) {
1308         if (sService == null) {
1309             return false;
1310         }
1311         try {
1312             return sService.setPhonebookAccessPermission(this, value);
1313         } catch (RemoteException e) {
1314             Log.e(TAG, "", e);
1315         }
1316         return false;
1317     }
1318 
1319     /**
1320      * Requires {@link android.Manifest.permission#BLUETOOTH}.
1321      * @return Whether the message access is allowed to this device. Can be
1322      *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
1323      * @hide
1324      */
getMessageAccessPermission()1325     public int getMessageAccessPermission() {
1326         if (sService == null) {
1327             return ACCESS_UNKNOWN;
1328         }
1329         try {
1330             return sService.getMessageAccessPermission(this);
1331         } catch (RemoteException e) {
1332             Log.e(TAG, "", e);
1333         }
1334         return ACCESS_UNKNOWN;
1335     }
1336 
1337     /**
1338      * Sets whether the message access is allowed to this device.
1339      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1340      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
1341      *              {@link #ACCESS_REJECTED}.
1342      * @return Whether the value has been successfully set.
1343      * @hide
1344      */
setMessageAccessPermission(int value)1345     public boolean setMessageAccessPermission(int value) {
1346         if (sService == null) {
1347             return false;
1348         }
1349         try {
1350             return sService.setMessageAccessPermission(this, value);
1351         } catch (RemoteException e) {
1352             Log.e(TAG, "", e);
1353         }
1354         return false;
1355     }
1356 
1357     /**
1358      * Requires {@link android.Manifest.permission#BLUETOOTH}.
1359      * @return Whether the Sim access is allowed to this device. Can be
1360      *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
1361      * @hide
1362      */
getSimAccessPermission()1363     public int getSimAccessPermission() {
1364         if (sService == null) {
1365             return ACCESS_UNKNOWN;
1366         }
1367         try {
1368             return sService.getSimAccessPermission(this);
1369         } catch (RemoteException e) {
1370             Log.e(TAG, "", e);
1371         }
1372         return ACCESS_UNKNOWN;
1373     }
1374 
1375     /**
1376      * Sets whether the Sim access is allowed to this device.
1377      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1378      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
1379      *              {@link #ACCESS_REJECTED}.
1380      * @return Whether the value has been successfully set.
1381      * @hide
1382      */
setSimAccessPermission(int value)1383     public boolean setSimAccessPermission(int value) {
1384         if (sService == null) {
1385             return false;
1386         }
1387         try {
1388             return sService.setSimAccessPermission(this, value);
1389         } catch (RemoteException e) {
1390             Log.e(TAG, "", e);
1391         }
1392         return false;
1393     }
1394 
1395     /**
1396      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
1397      * outgoing connection to this remote device on given channel.
1398      * <p>The remote device will be authenticated and communication on this
1399      * socket will be encrypted.
1400      * <p> Use this socket only if an authenticated socket link is possible.
1401      * Authentication refers to the authentication of the link key to
1402      * prevent man-in-the-middle type of attacks.
1403      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1404      * have an input and output capability or just has the ability to
1405      * display a numeric key, a secure socket connection is not possible.
1406      * In such a case, use {#link createInsecureRfcommSocket}.
1407      * For more details, refer to the Security Model section 5.2 (vol 3) of
1408      * Bluetooth Core Specification version 2.1 + EDR.
1409      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1410      * connection.
1411      * <p>Valid RFCOMM channels are in range 1 to 30.
1412      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1413      *
1414      * @param channel RFCOMM channel to connect to
1415      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1416      * @throws IOException on error, for example Bluetooth not available, or
1417      *                     insufficient permissions
1418      * @hide
1419      */
createRfcommSocket(int channel)1420     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
1421         if (isBluetoothEnabled() == false) {
1422             Log.e(TAG, "Bluetooth is not enabled");
1423             throw new IOException();
1424         }
1425         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
1426                 null);
1427     }
1428 
1429     /**
1430      * Create an L2cap {@link BluetoothSocket} ready to start a secure
1431      * outgoing connection to this remote device on given channel.
1432      * <p>The remote device will be authenticated and communication on this
1433      * socket will be encrypted.
1434      * <p> Use this socket only if an authenticated socket link is possible.
1435      * Authentication refers to the authentication of the link key to
1436      * prevent man-in-the-middle type of attacks.
1437      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1438      * have an input and output capability or just has the ability to
1439      * display a numeric key, a secure socket connection is not possible.
1440      * In such a case, use {#link createInsecureRfcommSocket}.
1441      * For more details, refer to the Security Model section 5.2 (vol 3) of
1442      * Bluetooth Core Specification version 2.1 + EDR.
1443      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1444      * connection.
1445      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
1446      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1447      *
1448      * @param channel L2cap PSM/channel to connect to
1449      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1450      * @throws IOException on error, for example Bluetooth not available, or
1451      *                     insufficient permissions
1452      * @hide
1453      */
createL2capSocket(int channel)1454     public BluetoothSocket createL2capSocket(int channel) throws IOException {
1455         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
1456                 null);
1457     }
1458 
1459     /**
1460      * Create an L2cap {@link BluetoothSocket} ready to start an insecure
1461      * outgoing connection to this remote device on given channel.
1462      * <p>The remote device will be not authenticated and communication on this
1463      * socket will not be encrypted.
1464      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1465      * connection.
1466      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
1467      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1468      *
1469      * @param channel L2cap PSM/channel to connect to
1470      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1471      * @throws IOException on error, for example Bluetooth not available, or
1472      *                     insufficient permissions
1473      * @hide
1474      */
createInsecureL2capSocket(int channel)1475     public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException {
1476         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel,
1477                 null);
1478     }
1479 
1480     /**
1481      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
1482      * outgoing connection to this remote device using SDP lookup of uuid.
1483      * <p>This is designed to be used with {@link
1484      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
1485      * Bluetooth applications.
1486      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1487      * connection. This will also perform an SDP lookup of the given uuid to
1488      * determine which channel to connect to.
1489      * <p>The remote device will be authenticated and communication on this
1490      * socket will be encrypted.
1491      * <p> Use this socket only if an authenticated socket link is possible.
1492      * Authentication refers to the authentication of the link key to
1493      * prevent man-in-the-middle type of attacks.
1494      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1495      * have an input and output capability or just has the ability to
1496      * display a numeric key, a secure socket connection is not possible.
1497      * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}.
1498      * For more details, refer to the Security Model section 5.2 (vol 3) of
1499      * Bluetooth Core Specification version 2.1 + EDR.
1500      * <p>Hint: If you are connecting to a Bluetooth serial board then try
1501      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
1502      * However if you are connecting to an Android peer then please generate
1503      * your own unique UUID.
1504      *
1505      * @param uuid service record uuid to lookup RFCOMM channel
1506      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1507      * @throws IOException on error, for example Bluetooth not available, or
1508      *                     insufficient permissions
1509      */
1510     @RequiresPermission(Manifest.permission.BLUETOOTH)
createRfcommSocketToServiceRecord(UUID uuid)1511     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
1512         if (isBluetoothEnabled() == false) {
1513             Log.e(TAG, "Bluetooth is not enabled");
1514             throw new IOException();
1515         }
1516 
1517         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
1518                 new ParcelUuid(uuid));
1519     }
1520 
1521     /**
1522      * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
1523      * outgoing connection to this remote device using SDP lookup of uuid.
1524      * <p> The communication channel will not have an authenticated link key
1525      * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
1526      * devices, the link key will be encrypted, as encryption is mandatory.
1527      * For legacy devices (pre Bluetooth 2.1 devices) the link key will
1528      * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
1529      * encrypted and authenticated communication channel is desired.
1530      * <p>This is designed to be used with {@link
1531      * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
1532      * Bluetooth applications.
1533      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1534      * connection. This will also perform an SDP lookup of the given uuid to
1535      * determine which channel to connect to.
1536      * <p>The remote device will be authenticated and communication on this
1537      * socket will be encrypted.
1538      * <p>Hint: If you are connecting to a Bluetooth serial board then try
1539      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
1540      * However if you are connecting to an Android peer then please generate
1541      * your own unique UUID.
1542      *
1543      * @param uuid service record uuid to lookup RFCOMM channel
1544      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1545      * @throws IOException on error, for example Bluetooth not available, or
1546      *                     insufficient permissions
1547      */
1548     @RequiresPermission(Manifest.permission.BLUETOOTH)
createInsecureRfcommSocketToServiceRecord(UUID uuid)1549     public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
1550         if (isBluetoothEnabled() == false) {
1551             Log.e(TAG, "Bluetooth is not enabled");
1552             throw new IOException();
1553         }
1554         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
1555                 new ParcelUuid(uuid));
1556     }
1557 
1558     /**
1559      * Construct an insecure RFCOMM socket ready to start an outgoing
1560      * connection.
1561      * Call #connect on the returned #BluetoothSocket to begin the connection.
1562      * The remote device will not be authenticated and communication on this
1563      * socket will not be encrypted.
1564      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1565      *
1566      * @param port    remote port
1567      * @return An RFCOMM BluetoothSocket
1568      * @throws IOException On error, for example Bluetooth not available, or
1569      *                     insufficient permissions.
1570      * @hide
1571      */
createInsecureRfcommSocket(int port)1572     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
1573 
1574         if (isBluetoothEnabled() == false) {
1575             Log.e(TAG, "Bluetooth is not enabled");
1576             throw new IOException();
1577         }
1578         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
1579                 null);
1580     }
1581 
1582     /**
1583      * Construct a SCO socket ready to start an outgoing connection.
1584      * Call #connect on the returned #BluetoothSocket to begin the connection.
1585      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1586      *
1587      * @return a SCO BluetoothSocket
1588      * @throws IOException on error, for example Bluetooth not available, or
1589      *                     insufficient permissions.
1590      * @hide
1591      */
createScoSocket()1592     public BluetoothSocket createScoSocket() throws IOException {
1593 
1594         if (isBluetoothEnabled() == false) {
1595             Log.e(TAG, "Bluetooth is not enabled");
1596             throw new IOException();
1597         }
1598         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
1599     }
1600 
1601     /**
1602      * Check that a pin is valid and convert to byte array.
1603      *
1604      * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
1605      * @param pin pin as java String
1606      * @return the pin code as a UTF-8 byte array, or null if it is an invalid
1607      *         Bluetooth pin.
1608      * @hide
1609      */
convertPinToBytes(String pin)1610     public static byte[] convertPinToBytes(String pin) {
1611         if (pin == null) {
1612             return null;
1613         }
1614         byte[] pinBytes;
1615         try {
1616             pinBytes = pin.getBytes("UTF-8");
1617         } catch (UnsupportedEncodingException uee) {
1618             Log.e(TAG, "UTF-8 not supported?!?");  // this should not happen
1619             return null;
1620         }
1621         if (pinBytes.length <= 0 || pinBytes.length > 16) {
1622             return null;
1623         }
1624         return pinBytes;
1625     }
1626 
1627     /**
1628      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
1629      * The callback is used to deliver results to Caller, such as connection status as well
1630      * as any further GATT client operations.
1631      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
1632      * GATT client operations.
1633      * @param callback GATT callback handler that will receive asynchronous callbacks.
1634      * @param autoConnect Whether to directly connect to the remote device (false)
1635      *                    or to automatically connect as soon as the remote
1636      *                    device becomes available (true).
1637      * @throws IllegalArgumentException if callback is null
1638      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)1639     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
1640                                      BluetoothGattCallback callback) {
1641         return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));
1642     }
1643 
1644     /**
1645      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
1646      * The callback is used to deliver results to Caller, such as connection status as well
1647      * as any further GATT client operations.
1648      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
1649      * GATT client operations.
1650      * @param callback GATT callback handler that will receive asynchronous callbacks.
1651      * @param autoConnect Whether to directly connect to the remote device (false)
1652      *                    or to automatically connect as soon as the remote
1653      *                    device becomes available (true).
1654      * @param transport preferred transport for GATT connections to remote dual-mode devices
1655      *             {@link BluetoothDevice#TRANSPORT_AUTO} or
1656      *             {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
1657      * @throws IllegalArgumentException if callback is null
1658      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)1659     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
1660                                      BluetoothGattCallback callback, int transport) {
1661         return (connectGatt(context, autoConnect,callback, transport, PHY_LE_1M_MASK));
1662     }
1663 
1664     /**
1665      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
1666      * The callback is used to deliver results to Caller, such as connection status as well
1667      * as any further GATT client operations.
1668      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
1669      * GATT client operations.
1670      * @param callback GATT callback handler that will receive asynchronous callbacks.
1671      * @param autoConnect Whether to directly connect to the remote device (false)
1672      *                    or to automatically connect as soon as the remote
1673      *                    device becomes available (true).
1674      * @param transport preferred transport for GATT connections to remote dual-mode devices
1675      *             {@link BluetoothDevice#TRANSPORT_AUTO} or
1676      *             {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
1677      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of
1678      *             {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK},
1679      *             and {@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect
1680      *             if {@code autoConnect} is set to true.
1681      * @throws NullPointerException if callback is null
1682      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy)1683     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
1684                                      BluetoothGattCallback callback, int transport, int phy) {
1685         return connectGatt(context, autoConnect,callback, transport, phy, null);
1686     }
1687 
1688     /**
1689      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
1690      * The callback is used to deliver results to Caller, such as connection status as well
1691      * as any further GATT client operations.
1692      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
1693      * GATT client operations.
1694      * @param callback GATT callback handler that will receive asynchronous callbacks.
1695      * @param autoConnect Whether to directly connect to the remote device (false)
1696      *                    or to automatically connect as soon as the remote
1697      *                    device becomes available (true).
1698      * @param transport preferred transport for GATT connections to remote dual-mode devices
1699      *             {@link BluetoothDevice#TRANSPORT_AUTO} or
1700      *             {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
1701      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of
1702      *             {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK},
1703      *             an d{@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect
1704      *             if {@code autoConnect} is set to true.
1705      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen
1706      *             on an un-specified background thread.
1707      * @throws NullPointerException if callback is null
1708      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler)1709     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
1710                                      BluetoothGattCallback callback, int transport, int phy,
1711                                      Handler handler) {
1712         if (callback == null)
1713             throw new NullPointerException("callback is null");
1714 
1715         // TODO(Bluetooth) check whether platform support BLE
1716         //     Do the check here or in GattServer?
1717         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1718         IBluetoothManager managerService = adapter.getBluetoothManager();
1719         try {
1720             IBluetoothGatt iGatt = managerService.getBluetoothGatt();
1721             if (iGatt == null) {
1722                 // BLE is not supported
1723                 return null;
1724             }
1725             BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport, phy);
1726             gatt.connect(autoConnect, callback, handler);
1727             return gatt;
1728         } catch (RemoteException e) {Log.e(TAG, "", e);}
1729         return null;
1730     }
1731 }
1732