• 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.Manifest;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.annotation.SdkConstant;
24 import android.annotation.SdkConstant.SdkConstantType;
25 import android.annotation.SystemApi;
26 import android.annotation.UnsupportedAppUsage;
27 import android.content.Context;
28 import android.os.Handler;
29 import android.os.Parcel;
30 import android.os.ParcelUuid;
31 import android.os.Parcelable;
32 import android.os.Process;
33 import android.os.RemoteException;
34 import android.util.Log;
35 
36 import java.io.IOException;
37 import java.io.UnsupportedEncodingException;
38 import java.util.UUID;
39 
40 /**
41  * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
42  * create a connection with the respective device or query information about
43  * it, such as the name, address, class, and bonding state.
44  *
45  * <p>This class is really just a thin wrapper for a Bluetooth hardware
46  * address. Objects of this class are immutable. Operations on this class
47  * are performed on the remote Bluetooth hardware address, using the
48  * {@link BluetoothAdapter} that was used to create this {@link
49  * BluetoothDevice}.
50  *
51  * <p>To get a {@link BluetoothDevice}, use
52  * {@link BluetoothAdapter#getRemoteDevice(String)
53  * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device
54  * of a known MAC address (which you can get through device discovery with
55  * {@link BluetoothAdapter}) or get one from the set of bonded devices
56  * returned by {@link BluetoothAdapter#getBondedDevices()
57  * BluetoothAdapter.getBondedDevices()}. You can then open a
58  * {@link BluetoothSocket} for communication with the remote device, using
59  * {@link #createRfcommSocketToServiceRecord(UUID)} over Bluetooth BR/EDR or using
60  * {@link #createL2capChannel(int)} over Bluetooth LE.
61  *
62  * <p class="note"><strong>Note:</strong>
63  * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
64  *
65  * <div class="special reference">
66  * <h3>Developer Guides</h3>
67  * <p>
68  * For more information about using Bluetooth, read the <a href=
69  * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
70  * guide.
71  * </p>
72  * </div>
73  *
74  * {@see BluetoothAdapter}
75  * {@see BluetoothSocket}
76  */
77 public final class BluetoothDevice implements Parcelable {
78     private static final String TAG = "BluetoothDevice";
79     private static final boolean DBG = false;
80 
81     /**
82      * Connection state bitmask as returned by getConnectionState.
83      */
84     private static final int CONNECTION_STATE_DISCONNECTED = 0;
85     private static final int CONNECTION_STATE_CONNECTED = 1;
86     private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2;
87     private static final int CONNECTION_STATE_ENCRYPTED_LE = 4;
88 
89     /**
90      * Sentinel error value for this class. Guaranteed to not equal any other
91      * integer constant in this class. Provided as a convenience for functions
92      * that require a sentinel error value, for example:
93      * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
94      * BluetoothDevice.ERROR)</code>
95      */
96     public static final int ERROR = Integer.MIN_VALUE;
97 
98     /**
99      * Broadcast Action: Remote device discovered.
100      * <p>Sent when a remote device is found during discovery.
101      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
102      * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
103      * {@link #EXTRA_RSSI} if they are available.
104      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} and
105      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive.
106      */
107     // TODO: Change API to not broadcast RSSI if not available (incoming connection)
108     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
109     public static final String ACTION_FOUND =
110             "android.bluetooth.device.action.FOUND";
111 
112     /**
113      * Broadcast Action: Bluetooth class of a remote device has changed.
114      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
115      * #EXTRA_CLASS}.
116      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
117      * {@see BluetoothClass}
118      */
119     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
120     public static final String ACTION_CLASS_CHANGED =
121             "android.bluetooth.device.action.CLASS_CHANGED";
122 
123     /**
124      * Broadcast Action: Indicates a low level (ACL) connection has been
125      * established with a remote device.
126      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
127      * <p>ACL connections are managed automatically by the Android Bluetooth
128      * stack.
129      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
130      */
131     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
132     public static final String ACTION_ACL_CONNECTED =
133             "android.bluetooth.device.action.ACL_CONNECTED";
134 
135     /**
136      * Broadcast Action: Indicates that a low level (ACL) disconnection has
137      * been requested for a remote device, and it will soon be disconnected.
138      * <p>This is useful for graceful disconnection. Applications should use
139      * this intent as a hint to immediately terminate higher level connections
140      * (RFCOMM, L2CAP, or profile connections) to the remote device.
141      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
142      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
143      */
144     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
145     public static final String ACTION_ACL_DISCONNECT_REQUESTED =
146             "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
147 
148     /**
149      * Broadcast Action: Indicates a low level (ACL) disconnection from a
150      * remote device.
151      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
152      * <p>ACL connections are managed automatically by the Android Bluetooth
153      * stack.
154      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
155      */
156     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
157     public static final String ACTION_ACL_DISCONNECTED =
158             "android.bluetooth.device.action.ACL_DISCONNECTED";
159 
160     /**
161      * Broadcast Action: Indicates the friendly name of a remote device has
162      * been retrieved for the first time, or changed since the last retrieval.
163      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
164      * #EXTRA_NAME}.
165      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
166      */
167     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
168     public static final String ACTION_NAME_CHANGED =
169             "android.bluetooth.device.action.NAME_CHANGED";
170 
171     /**
172      * Broadcast Action: Indicates the alias of a remote device has been
173      * changed.
174      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
175      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
176      *
177      * @hide
178      */
179     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
180     @UnsupportedAppUsage
181     public static final String ACTION_ALIAS_CHANGED =
182             "android.bluetooth.device.action.ALIAS_CHANGED";
183 
184     /**
185      * Broadcast Action: Indicates a change in the bond state of a remote
186      * device. For example, if a device is bonded (paired).
187      * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
188      * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
189      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
190      */
191     // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
192     // contain a hidden extra field EXTRA_REASON with the result code.
193     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
194     public static final String ACTION_BOND_STATE_CHANGED =
195             "android.bluetooth.device.action.BOND_STATE_CHANGED";
196 
197     /**
198      * Broadcast Action: Indicates the battery level of a remote device has
199      * been retrieved for the first time, or changed since the last retrieval
200      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
201      * #EXTRA_BATTERY_LEVEL}.
202      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
203      *
204      * @hide
205      */
206     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
207     public static final String ACTION_BATTERY_LEVEL_CHANGED =
208             "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED";
209 
210     /**
211      * Used as an Integer extra field in {@link #ACTION_BATTERY_LEVEL_CHANGED}
212      * intent. It contains the most recently retrieved battery level information
213      * ranging from 0% to 100% for a remote device, {@link #BATTERY_LEVEL_UNKNOWN}
214      * when the valid is unknown or there is an error
215      *
216      * @hide
217      */
218     public static final String EXTRA_BATTERY_LEVEL =
219             "android.bluetooth.device.extra.BATTERY_LEVEL";
220 
221     /**
222      * Used as the unknown value for {@link #EXTRA_BATTERY_LEVEL} and {@link #getBatteryLevel()}
223      *
224      * @hide
225      */
226     public static final int BATTERY_LEVEL_UNKNOWN = -1;
227 
228     /**
229      * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
230      * broadcast by this class. It contains the {@link BluetoothDevice} that
231      * the intent applies to.
232      */
233     public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
234 
235     /**
236      * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
237      * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
238      */
239     public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
240 
241     /**
242      * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
243      * Contains the RSSI value of the remote device as reported by the
244      * Bluetooth hardware.
245      */
246     public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
247 
248     /**
249      * Used as a Parcelable {@link BluetoothClass} extra field in {@link
250      * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
251      */
252     public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
253 
254     /**
255      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
256      * Contains the bond state of the remote device.
257      * <p>Possible values are:
258      * {@link #BOND_NONE},
259      * {@link #BOND_BONDING},
260      * {@link #BOND_BONDED}.
261      */
262     public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
263     /**
264      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
265      * Contains the previous bond state of the remote device.
266      * <p>Possible values are:
267      * {@link #BOND_NONE},
268      * {@link #BOND_BONDING},
269      * {@link #BOND_BONDED}.
270      */
271     public static final String EXTRA_PREVIOUS_BOND_STATE =
272             "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
273     /**
274      * Indicates the remote device is not bonded (paired).
275      * <p>There is no shared link key with the remote device, so communication
276      * (if it is allowed at all) will be unauthenticated and unencrypted.
277      */
278     public static final int BOND_NONE = 10;
279     /**
280      * Indicates bonding (pairing) is in progress with the remote device.
281      */
282     public static final int BOND_BONDING = 11;
283     /**
284      * Indicates the remote device is bonded (paired).
285      * <p>A shared link keys exists locally for the remote device, so
286      * communication can be authenticated and encrypted.
287      * <p><i>Being bonded (paired) with a remote device does not necessarily
288      * mean the device is currently connected. It just means that the pending
289      * procedure was completed at some earlier time, and the link key is still
290      * stored locally, ready to use on the next connection.
291      * </i>
292      */
293     public static final int BOND_BONDED = 12;
294 
295     /**
296      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
297      * intents for unbond reason.
298      *
299      * @hide
300      */
301     @UnsupportedAppUsage
302     public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
303 
304     /**
305      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
306      * intents to indicate pairing method used. Possible values are:
307      * {@link #PAIRING_VARIANT_PIN},
308      * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION},
309      */
310     public static final String EXTRA_PAIRING_VARIANT =
311             "android.bluetooth.device.extra.PAIRING_VARIANT";
312 
313     /**
314      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
315      * intents as the value of passkey.
316      */
317     public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
318 
319     /**
320      * Bluetooth device type, Unknown
321      */
322     public static final int DEVICE_TYPE_UNKNOWN = 0;
323 
324     /**
325      * Bluetooth device type, Classic - BR/EDR devices
326      */
327     public static final int DEVICE_TYPE_CLASSIC = 1;
328 
329     /**
330      * Bluetooth device type, Low Energy - LE-only
331      */
332     public static final int DEVICE_TYPE_LE = 2;
333 
334     /**
335      * Bluetooth device type, Dual Mode - BR/EDR/LE
336      */
337     public static final int DEVICE_TYPE_DUAL = 3;
338 
339 
340     /** @hide */
341     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
342     @UnsupportedAppUsage
343     public static final String ACTION_SDP_RECORD =
344             "android.bluetooth.device.action.SDP_RECORD";
345 
346     /**
347      * Maximum length of a metadata entry, this is to avoid exploding Bluetooth
348      * disk usage
349      * @hide
350      */
351     @SystemApi
352     public static final int METADATA_MAX_LENGTH = 2048;
353 
354     /**
355      * Manufacturer name of this Bluetooth device
356      * Data type should be {@String} as {@link Byte} array.
357      * @hide
358      */
359     @SystemApi
360     public static final int METADATA_MANUFACTURER_NAME = 0;
361 
362     /**
363      * Model name of this Bluetooth device
364      * Data type should be {@String} as {@link Byte} array.
365      * @hide
366      */
367     @SystemApi
368     public static final int METADATA_MODEL_NAME = 1;
369 
370     /**
371      * Software version of this Bluetooth device
372      * Data type should be {@String} as {@link Byte} array.
373      * @hide
374      */
375     @SystemApi
376     public static final int METADATA_SOFTWARE_VERSION = 2;
377 
378     /**
379      * Hardware version of this Bluetooth device
380      * Data type should be {@String} as {@link Byte} array.
381      * @hide
382      */
383     @SystemApi
384     public static final int METADATA_HARDWARE_VERSION = 3;
385 
386     /**
387      * Package name of the companion app, if any
388      * Data type should be {@String} as {@link Byte} array.
389      * @hide
390      */
391     @SystemApi
392     public static final int METADATA_COMPANION_APP = 4;
393 
394     /**
395      * URI to the main icon shown on the settings UI
396      * Data type should be {@link Byte} array.
397      * @hide
398      */
399     @SystemApi
400     public static final int METADATA_MAIN_ICON = 5;
401 
402     /**
403      * Whether this device is an untethered headset with left, right and case
404      * Data type should be {@String} as {@link Byte} array.
405      * @hide
406      */
407     @SystemApi
408     public static final int METADATA_IS_UNTETHERED_HEADSET = 6;
409 
410     /**
411      * URI to icon of the left headset
412      * Data type should be {@link Byte} array.
413      * @hide
414      */
415     @SystemApi
416     public static final int METADATA_UNTETHERED_LEFT_ICON = 7;
417 
418     /**
419      * URI to icon of the right headset
420      * Data type should be {@link Byte} array.
421      * @hide
422      */
423     @SystemApi
424     public static final int METADATA_UNTETHERED_RIGHT_ICON = 8;
425 
426     /**
427      * URI to icon of the headset charging case
428      * Data type should be {@link Byte} array.
429      * @hide
430      */
431     @SystemApi
432     public static final int METADATA_UNTETHERED_CASE_ICON = 9;
433 
434     /**
435      * Battery level of left headset
436      * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
437      * as invalid.
438      * @hide
439      */
440     @SystemApi
441     public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10;
442 
443     /**
444      * Battery level of rigth headset
445      * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
446      * as invalid.
447      * @hide
448      */
449     @SystemApi
450     public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11;
451 
452     /**
453      * Battery level of the headset charging case
454      * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
455      * as invalid.
456      * @hide
457      */
458     @SystemApi
459     public static final int METADATA_UNTETHERED_CASE_BATTERY = 12;
460 
461     /**
462      * Whether the left headset is charging
463      * Data type should be {@String} as {@link Byte} array.
464      * @hide
465      */
466     @SystemApi
467     public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13;
468 
469     /**
470      * Whether the right headset is charging
471      * Data type should be {@String} as {@link Byte} array.
472      * @hide
473      */
474     @SystemApi
475     public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14;
476 
477     /**
478      * Whether the headset charging case is charging
479      * Data type should be {@String} as {@link Byte} array.
480      * @hide
481      */
482     @SystemApi
483     public static final int METADATA_UNTETHERED_CASE_CHARGING = 15;
484 
485     /**
486      * URI to the enhanced settings UI slice
487      * Data type should be {@String} as {@link Byte} array, null means
488      * the UI does not exist.
489      * @hide
490      */
491     @SystemApi
492     public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16;
493 
494     /**
495      * Broadcast Action: This intent is used to broadcast the {@link UUID}
496      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
497      * has been fetched. This intent is sent only when the UUIDs of the remote
498      * device are requested to be fetched using Service Discovery Protocol
499      * <p> Always contains the extra field {@link #EXTRA_DEVICE}
500      * <p> Always contains the extra field {@link #EXTRA_UUID}
501      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to receive.
502      */
503     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
504     public static final String ACTION_UUID =
505             "android.bluetooth.device.action.UUID";
506 
507     /** @hide */
508     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
509     public static final String ACTION_MAS_INSTANCE =
510             "android.bluetooth.device.action.MAS_INSTANCE";
511 
512     /**
513      * Broadcast Action: Indicates a failure to retrieve the name of a remote
514      * device.
515      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
516      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
517      *
518      * @hide
519      */
520     //TODO: is this actually useful?
521     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
522     public static final String ACTION_NAME_FAILED =
523             "android.bluetooth.device.action.NAME_FAILED";
524 
525     /**
526      * Broadcast Action: This intent is used to broadcast PAIRING REQUEST
527      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to
528      * receive.
529      */
530     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
531     public static final String ACTION_PAIRING_REQUEST =
532             "android.bluetooth.device.action.PAIRING_REQUEST";
533     /** @hide */
534     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
535     @UnsupportedAppUsage
536     public static final String ACTION_PAIRING_CANCEL =
537             "android.bluetooth.device.action.PAIRING_CANCEL";
538 
539     /** @hide */
540     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
541     public static final String ACTION_CONNECTION_ACCESS_REQUEST =
542             "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
543 
544     /** @hide */
545     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
546     public static final String ACTION_CONNECTION_ACCESS_REPLY =
547             "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
548 
549     /** @hide */
550     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
551     public static final String ACTION_CONNECTION_ACCESS_CANCEL =
552             "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
553 
554     /**
555      * Intent to broadcast silence mode changed.
556      * Alway contains the extra field {@link #EXTRA_DEVICE}
557      *
558      * @hide
559      */
560     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
561     @SystemApi
562     public static final String ACTION_SILENCE_MODE_CHANGED =
563             "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
564 
565     /**
566      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
567      *
568      * @hide
569      */
570     public static final String EXTRA_ACCESS_REQUEST_TYPE =
571             "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE";
572 
573     /** @hide */
574     public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1;
575 
576     /** @hide */
577     public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
578 
579     /** @hide */
580     public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3;
581 
582     /** @hide */
583     public static final int REQUEST_TYPE_SIM_ACCESS = 4;
584 
585     /**
586      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
587      * Contains package name to return reply intent to.
588      *
589      * @hide
590      */
591     public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME";
592 
593     /**
594      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
595      * Contains class name to return reply intent to.
596      *
597      * @hide
598      */
599     public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME";
600 
601     /**
602      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
603      *
604      * @hide
605      */
606     public static final String EXTRA_CONNECTION_ACCESS_RESULT =
607             "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
608 
609     /** @hide */
610     public static final int CONNECTION_ACCESS_YES = 1;
611 
612     /** @hide */
613     public static final int CONNECTION_ACCESS_NO = 2;
614 
615     /**
616      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents,
617      * Contains boolean to indicate if the allowed response is once-for-all so that
618      * next request will be granted without asking user again.
619      *
620      * @hide
621      */
622     public static final String EXTRA_ALWAYS_ALLOWED =
623             "android.bluetooth.device.extra.ALWAYS_ALLOWED";
624 
625     /**
626      * A bond attempt succeeded
627      *
628      * @hide
629      */
630     public static final int BOND_SUCCESS = 0;
631 
632     /**
633      * A bond attempt failed because pins did not match, or remote device did
634      * not respond to pin request in time
635      *
636      * @hide
637      */
638     @UnsupportedAppUsage
639     public static final int UNBOND_REASON_AUTH_FAILED = 1;
640 
641     /**
642      * A bond attempt failed because the other side explicitly rejected
643      * bonding
644      *
645      * @hide
646      */
647     @UnsupportedAppUsage
648     public static final int UNBOND_REASON_AUTH_REJECTED = 2;
649 
650     /**
651      * A bond attempt failed because we canceled the bonding process
652      *
653      * @hide
654      */
655     public static final int UNBOND_REASON_AUTH_CANCELED = 3;
656 
657     /**
658      * A bond attempt failed because we could not contact the remote device
659      *
660      * @hide
661      */
662     @UnsupportedAppUsage
663     public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
664 
665     /**
666      * A bond attempt failed because a discovery is in progress
667      *
668      * @hide
669      */
670     @UnsupportedAppUsage
671     public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
672 
673     /**
674      * A bond attempt failed because of authentication timeout
675      *
676      * @hide
677      */
678     @UnsupportedAppUsage
679     public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
680 
681     /**
682      * A bond attempt failed because of repeated attempts
683      *
684      * @hide
685      */
686     @UnsupportedAppUsage
687     public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
688 
689     /**
690      * A bond attempt failed because we received an Authentication Cancel
691      * by remote end
692      *
693      * @hide
694      */
695     @UnsupportedAppUsage
696     public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
697 
698     /**
699      * An existing bond was explicitly revoked
700      *
701      * @hide
702      */
703     public static final int UNBOND_REASON_REMOVED = 9;
704 
705     /**
706      * The user will be prompted to enter a pin or
707      * an app will enter a pin for user.
708      */
709     public static final int PAIRING_VARIANT_PIN = 0;
710 
711     /**
712      * The user will be prompted to enter a passkey
713      *
714      * @hide
715      */
716     public static final int PAIRING_VARIANT_PASSKEY = 1;
717 
718     /**
719      * The user will be prompted to confirm the passkey displayed on the screen or
720      * an app will confirm the passkey for the user.
721      */
722     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
723 
724     /**
725      * The user will be prompted to accept or deny the incoming pairing request
726      *
727      * @hide
728      */
729     public static final int PAIRING_VARIANT_CONSENT = 3;
730 
731     /**
732      * The user will be prompted to enter the passkey displayed on remote device
733      * This is used for Bluetooth 2.1 pairing.
734      *
735      * @hide
736      */
737     public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
738 
739     /**
740      * The user will be prompted to enter the PIN displayed on remote device.
741      * This is used for Bluetooth 2.0 pairing.
742      *
743      * @hide
744      */
745     public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
746 
747     /**
748      * The user will be prompted to accept or deny the OOB pairing request
749      *
750      * @hide
751      */
752     public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
753 
754     /**
755      * The user will be prompted to enter a 16 digit pin or
756      * an app will enter a 16 digit pin for user.
757      *
758      * @hide
759      */
760     public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7;
761 
762     /**
763      * Used as an extra field in {@link #ACTION_UUID} intents,
764      * Contains the {@link android.os.ParcelUuid}s of the remote device which
765      * is a parcelable version of {@link UUID}.
766      */
767     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
768 
769     /** @hide */
770     public static final String EXTRA_SDP_RECORD =
771             "android.bluetooth.device.extra.SDP_RECORD";
772 
773     /** @hide */
774     @UnsupportedAppUsage
775     public static final String EXTRA_SDP_SEARCH_STATUS =
776             "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
777     /**
778      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
779      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
780      *
781      * @hide
782      */
783     @SystemApi
784     public static final int ACCESS_UNKNOWN = 0;
785 
786     /**
787      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
788      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
789      *
790      * @hide
791      */
792     @SystemApi
793     public static final int ACCESS_ALLOWED = 1;
794 
795     /**
796      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
797      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
798      *
799      * @hide
800      */
801     @SystemApi
802     public static final int ACCESS_REJECTED = 2;
803 
804     /**
805      * No preference of physical transport for GATT connections to remote dual-mode devices
806      */
807     public static final int TRANSPORT_AUTO = 0;
808 
809     /**
810      * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
811      */
812     public static final int TRANSPORT_BREDR = 1;
813 
814     /**
815      * Prefer LE transport for GATT connections to remote dual-mode devices
816      */
817     public static final int TRANSPORT_LE = 2;
818 
819     /**
820      * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or
821      * connection.
822      */
823     public static final int PHY_LE_1M = 1;
824 
825     /**
826      * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or
827      * connection.
828      */
829     public static final int PHY_LE_2M = 2;
830 
831     /**
832      * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning
833      * or connection.
834      */
835     public static final int PHY_LE_CODED = 3;
836 
837     /**
838      * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available
839      * options in a bitmask.
840      */
841     public static final int PHY_LE_1M_MASK = 1;
842 
843     /**
844      * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available
845      * options in a bitmask.
846      */
847     public static final int PHY_LE_2M_MASK = 2;
848 
849     /**
850      * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many
851      * available options in a bitmask.
852      */
853     public static final int PHY_LE_CODED_MASK = 4;
854 
855     /**
856      * No preferred coding when transmitting on the LE Coded PHY.
857      */
858     public static final int PHY_OPTION_NO_PREFERRED = 0;
859 
860     /**
861      * Prefer the S=2 coding to be used when transmitting on the LE Coded PHY.
862      */
863     public static final int PHY_OPTION_S2 = 1;
864 
865     /**
866      * Prefer the S=8 coding to be used when transmitting on the LE Coded PHY.
867      */
868     public static final int PHY_OPTION_S8 = 2;
869 
870 
871     /** @hide */
872     public static final String EXTRA_MAS_INSTANCE =
873             "android.bluetooth.device.extra.MAS_INSTANCE";
874 
875     /**
876      * Lazy initialization. Guaranteed final after first object constructed, or
877      * getService() called.
878      * TODO: Unify implementation of sService amongst BluetoothFoo API's
879      */
880     private static volatile IBluetooth sService;
881 
882     private final String mAddress;
883 
884     /*package*/
885     @UnsupportedAppUsage
getService()886     static IBluetooth getService() {
887         synchronized (BluetoothDevice.class) {
888             if (sService == null) {
889                 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
890                 sService = adapter.getBluetoothService(sStateChangeCallback);
891             }
892         }
893         return sService;
894     }
895 
896     static IBluetoothManagerCallback sStateChangeCallback = new IBluetoothManagerCallback.Stub() {
897 
898         public void onBluetoothServiceUp(IBluetooth bluetoothService)
899                 throws RemoteException {
900             synchronized (BluetoothDevice.class) {
901                 if (sService == null) {
902                     sService = bluetoothService;
903                 }
904             }
905         }
906 
907         public void onBluetoothServiceDown()
908                 throws RemoteException {
909             synchronized (BluetoothDevice.class) {
910                 sService = null;
911             }
912         }
913 
914         public void onBrEdrDown() {
915             if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state");
916         }
917     };
918 
919     /**
920      * Create a new BluetoothDevice
921      * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
922      * and is validated in this constructor.
923      *
924      * @param address valid Bluetooth MAC address
925      * @throws RuntimeException Bluetooth is not available on this platform
926      * @throws IllegalArgumentException address is invalid
927      * @hide
928      */
929     @UnsupportedAppUsage
BluetoothDevice(String address)930     /*package*/ BluetoothDevice(String address) {
931         getService();  // ensures sService is initialized
932         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
933             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
934         }
935 
936         mAddress = address;
937     }
938 
939     @Override
equals(Object o)940     public boolean equals(Object o) {
941         if (o instanceof BluetoothDevice) {
942             return mAddress.equals(((BluetoothDevice) o).getAddress());
943         }
944         return false;
945     }
946 
947     @Override
hashCode()948     public int hashCode() {
949         return mAddress.hashCode();
950     }
951 
952     /**
953      * Returns a string representation of this BluetoothDevice.
954      * <p>Currently this is the Bluetooth hardware address, for example
955      * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
956      * if you explicitly require the Bluetooth hardware address in case the
957      * {@link #toString} representation changes in the future.
958      *
959      * @return string representation of this BluetoothDevice
960      */
961     @Override
toString()962     public String toString() {
963         return mAddress;
964     }
965 
966     @Override
describeContents()967     public int describeContents() {
968         return 0;
969     }
970 
971     public static final @android.annotation.NonNull Parcelable.Creator<BluetoothDevice> CREATOR =
972             new Parcelable.Creator<BluetoothDevice>() {
973                 public BluetoothDevice createFromParcel(Parcel in) {
974                     return new BluetoothDevice(in.readString());
975                 }
976 
977                 public BluetoothDevice[] newArray(int size) {
978                     return new BluetoothDevice[size];
979                 }
980             };
981 
982     @Override
writeToParcel(Parcel out, int flags)983     public void writeToParcel(Parcel out, int flags) {
984         out.writeString(mAddress);
985     }
986 
987     /**
988      * Returns the hardware address of this BluetoothDevice.
989      * <p> For example, "00:11:22:AA:BB:CC".
990      *
991      * @return Bluetooth hardware address as string
992      */
getAddress()993     public String getAddress() {
994         if (DBG) Log.d(TAG, "mAddress: " + mAddress);
995         return mAddress;
996     }
997 
998     /**
999      * Get the friendly Bluetooth name of the remote device.
1000      *
1001      * <p>The local adapter will automatically retrieve remote names when
1002      * performing a device scan, and will cache them. This method just returns
1003      * the name for this device from the cache.
1004      *
1005      * @return the Bluetooth name, or null if there was a problem.
1006      */
1007     @RequiresPermission(Manifest.permission.BLUETOOTH)
getName()1008     public String getName() {
1009         final IBluetooth service = sService;
1010         if (service == null) {
1011             Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
1012             return null;
1013         }
1014         try {
1015             String name = service.getRemoteName(this);
1016             if (name != null) {
1017                 return name.replaceAll("[\\t\\n\\r]+", " ");
1018             }
1019             return null;
1020         } catch (RemoteException e) {
1021             Log.e(TAG, "", e);
1022         }
1023         return null;
1024     }
1025 
1026     /**
1027      * Get the Bluetooth device type of the remote device.
1028      *
1029      * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} {@link
1030      * #DEVICE_TYPE_DUAL}. {@link #DEVICE_TYPE_UNKNOWN} if it's not available
1031      */
1032     @RequiresPermission(Manifest.permission.BLUETOOTH)
getType()1033     public int getType() {
1034         final IBluetooth service = sService;
1035         if (service == null) {
1036             Log.e(TAG, "BT not enabled. Cannot get Remote Device type");
1037             return DEVICE_TYPE_UNKNOWN;
1038         }
1039         try {
1040             return service.getRemoteType(this);
1041         } catch (RemoteException e) {
1042             Log.e(TAG, "", e);
1043         }
1044         return DEVICE_TYPE_UNKNOWN;
1045     }
1046 
1047     /**
1048      * Get the Bluetooth alias of the remote device.
1049      * <p>Alias is the locally modified name of a remote device.
1050      *
1051      * @return the Bluetooth alias, or null if no alias or there was a problem
1052      * @hide
1053      */
1054     @UnsupportedAppUsage
getAlias()1055     public String getAlias() {
1056         final IBluetooth service = sService;
1057         if (service == null) {
1058             Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias");
1059             return null;
1060         }
1061         try {
1062             return service.getRemoteAlias(this);
1063         } catch (RemoteException e) {
1064             Log.e(TAG, "", e);
1065         }
1066         return null;
1067     }
1068 
1069     /**
1070      * Set the Bluetooth alias of the remote device.
1071      * <p>Alias is the locally modified name of a remote device.
1072      * <p>This methoid overwrites the alias. The changed
1073      * alias is saved in the local storage so that the change
1074      * is preserved over power cycle.
1075      *
1076      * @return true on success, false on error
1077      * @hide
1078      */
1079     @UnsupportedAppUsage
setAlias(String alias)1080     public boolean setAlias(String alias) {
1081         final IBluetooth service = sService;
1082         if (service == null) {
1083             Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
1084             return false;
1085         }
1086         try {
1087             return service.setRemoteAlias(this, alias);
1088         } catch (RemoteException e) {
1089             Log.e(TAG, "", e);
1090         }
1091         return false;
1092     }
1093 
1094     /**
1095      * Get the Bluetooth alias of the remote device.
1096      * If Alias is null, get the Bluetooth name instead.
1097      *
1098      * @return the Bluetooth alias, or null if no alias or there was a problem
1099      * @hide
1100      * @see #getAlias()
1101      * @see #getName()
1102      */
1103     @UnsupportedAppUsage
getAliasName()1104     public String getAliasName() {
1105         String name = getAlias();
1106         if (name == null) {
1107             name = getName();
1108         }
1109         return name;
1110     }
1111 
1112     /**
1113      * Get the most recent identified battery level of this Bluetooth device
1114      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1115      *
1116      * @return Battery level in percents from 0 to 100, or {@link #BATTERY_LEVEL_UNKNOWN} if
1117      * Bluetooth is disabled, or device is disconnected, or does not have any battery reporting
1118      * service, or return value is invalid
1119      * @hide
1120      */
1121     @RequiresPermission(Manifest.permission.BLUETOOTH)
1122     @UnsupportedAppUsage
getBatteryLevel()1123     public int getBatteryLevel() {
1124         final IBluetooth service = sService;
1125         if (service == null) {
1126             Log.e(TAG, "Bluetooth disabled. Cannot get remote device battery level");
1127             return BATTERY_LEVEL_UNKNOWN;
1128         }
1129         try {
1130             return service.getBatteryLevel(this);
1131         } catch (RemoteException e) {
1132             Log.e(TAG, "", e);
1133         }
1134         return BATTERY_LEVEL_UNKNOWN;
1135     }
1136 
1137     /**
1138      * Start the bonding (pairing) process with the remote device.
1139      * <p>This is an asynchronous call, it will return immediately. Register
1140      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
1141      * the bonding process completes, and its result.
1142      * <p>Android system services will handle the necessary user interactions
1143      * to confirm and complete the bonding process.
1144      *
1145      * @return false on immediate error, true if bonding will begin
1146      */
1147     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
createBond()1148     public boolean createBond() {
1149         final IBluetooth service = sService;
1150         if (service == null) {
1151             Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
1152             return false;
1153         }
1154         try {
1155             Log.i(TAG, "createBond() for device " + getAddress()
1156                     + " called by pid: " + Process.myPid()
1157                     + " tid: " + Process.myTid());
1158             return service.createBond(this, TRANSPORT_AUTO);
1159         } catch (RemoteException e) {
1160             Log.e(TAG, "", e);
1161         }
1162         return false;
1163     }
1164 
1165     /**
1166      * Start the bonding (pairing) process with the remote device using the
1167      * specified transport.
1168      *
1169      * <p>This is an asynchronous call, it will return immediately. Register
1170      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
1171      * the bonding process completes, and its result.
1172      * <p>Android system services will handle the necessary user interactions
1173      * to confirm and complete the bonding process.
1174      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1175      *
1176      * @param transport The transport to use for the pairing procedure.
1177      * @return false on immediate error, true if bonding will begin
1178      * @throws IllegalArgumentException if an invalid transport was specified
1179      * @hide
1180      */
1181     @UnsupportedAppUsage
createBond(int transport)1182     public boolean createBond(int transport) {
1183         final IBluetooth service = sService;
1184         if (service == null) {
1185             Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
1186             return false;
1187         }
1188         if (TRANSPORT_AUTO > transport || transport > TRANSPORT_LE) {
1189             throw new IllegalArgumentException(transport + " is not a valid Bluetooth transport");
1190         }
1191         try {
1192             Log.i(TAG, "createBond() for device " + getAddress()
1193                     + " called by pid: " + Process.myPid()
1194                     + " tid: " + Process.myTid());
1195             return service.createBond(this, transport);
1196         } catch (RemoteException e) {
1197             Log.e(TAG, "", e);
1198         }
1199         return false;
1200     }
1201 
1202     /**
1203      * Start the bonding (pairing) process with the remote device using the
1204      * Out Of Band mechanism.
1205      *
1206      * <p>This is an asynchronous call, it will return immediately. Register
1207      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
1208      * the bonding process completes, and its result.
1209      *
1210      * <p>Android system services will handle the necessary user interactions
1211      * to confirm and complete the bonding process.
1212      *
1213      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1214      *
1215      * @param transport - Transport to use
1216      * @param oobData - Out Of Band data
1217      * @return false on immediate error, true if bonding will begin
1218      * @hide
1219      */
createBondOutOfBand(int transport, OobData oobData)1220     public boolean createBondOutOfBand(int transport, OobData oobData) {
1221         final IBluetooth service = sService;
1222         if (service == null) {
1223             Log.w(TAG, "BT not enabled, createBondOutOfBand failed");
1224             return false;
1225         }
1226         try {
1227             return service.createBondOutOfBand(this, transport, oobData);
1228         } catch (RemoteException e) {
1229             Log.e(TAG, "", e);
1230         }
1231         return false;
1232     }
1233 
1234     /** @hide */
1235     @UnsupportedAppUsage
isBondingInitiatedLocally()1236     public boolean isBondingInitiatedLocally() {
1237         final IBluetooth service = sService;
1238         if (service == null) {
1239             Log.w(TAG, "BT not enabled, isBondingInitiatedLocally failed");
1240             return false;
1241         }
1242         try {
1243             return service.isBondingInitiatedLocally(this);
1244         } catch (RemoteException e) {
1245             Log.e(TAG, "", e);
1246         }
1247         return false;
1248     }
1249 
1250     /**
1251      * Set the Out Of Band data for a remote device to be used later
1252      * in the pairing mechanism. Users can obtain this data through other
1253      * trusted channels
1254      *
1255      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1256      *
1257      * @param hash Simple Secure pairing hash
1258      * @param randomizer The random key obtained using OOB
1259      * @return false on error; true otherwise
1260      * @hide
1261      */
setDeviceOutOfBandData(byte[] hash, byte[] randomizer)1262     public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
1263         //TODO(BT)
1264       /*
1265       try {
1266         return sService.setDeviceOutOfBandData(this, hash, randomizer);
1267       } catch (RemoteException e) {Log.e(TAG, "", e);} */
1268         return false;
1269     }
1270 
1271     /**
1272      * Cancel an in-progress bonding request started with {@link #createBond}.
1273      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1274      *
1275      * @return true on success, false on error
1276      * @hide
1277      */
1278     @SystemApi
1279     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
cancelBondProcess()1280     public boolean cancelBondProcess() {
1281         final IBluetooth service = sService;
1282         if (service == null) {
1283             Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
1284             return false;
1285         }
1286         try {
1287             Log.i(TAG, "cancelBondProcess() for device " + getAddress()
1288                     + " called by pid: " + Process.myPid()
1289                     + " tid: " + Process.myTid());
1290             return service.cancelBondProcess(this);
1291         } catch (RemoteException e) {
1292             Log.e(TAG, "", e);
1293         }
1294         return false;
1295     }
1296 
1297     /**
1298      * Remove bond (pairing) with the remote device.
1299      * <p>Delete the link key associated with the remote device, and
1300      * immediately terminate connections to that device that require
1301      * authentication and encryption.
1302      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1303      *
1304      * @return true on success, false on error
1305      * @hide
1306      */
1307     @SystemApi
1308     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN)
removeBond()1309     public boolean removeBond() {
1310         final IBluetooth service = sService;
1311         if (service == null) {
1312             Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
1313             return false;
1314         }
1315         try {
1316             Log.i(TAG, "removeBond() for device " + getAddress()
1317                     + " called by pid: " + Process.myPid()
1318                     + " tid: " + Process.myTid());
1319             return service.removeBond(this);
1320         } catch (RemoteException e) {
1321             Log.e(TAG, "", e);
1322         }
1323         return false;
1324     }
1325 
1326     /**
1327      * Get the bond state of the remote device.
1328      * <p>Possible values for the bond state are:
1329      * {@link #BOND_NONE},
1330      * {@link #BOND_BONDING},
1331      * {@link #BOND_BONDED}.
1332      *
1333      * @return the bond state
1334      */
1335     @RequiresPermission(Manifest.permission.BLUETOOTH)
getBondState()1336     public int getBondState() {
1337         final IBluetooth service = sService;
1338         if (service == null) {
1339             Log.e(TAG, "BT not enabled. Cannot get bond state");
1340             return BOND_NONE;
1341         }
1342         try {
1343             return service.getBondState(this);
1344         } catch (RemoteException e) {
1345             Log.e(TAG, "", e);
1346         }
1347         return BOND_NONE;
1348     }
1349 
1350     /**
1351      * Returns whether there is an open connection to this device.
1352      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1353      *
1354      * @return True if there is at least one open connection to this device.
1355      * @hide
1356      */
1357     @SystemApi
1358     @RequiresPermission(android.Manifest.permission.BLUETOOTH)
isConnected()1359     public boolean isConnected() {
1360         final IBluetooth service = sService;
1361         if (service == null) {
1362             // BT is not enabled, we cannot be connected.
1363             return false;
1364         }
1365         try {
1366             return service.getConnectionState(this) != CONNECTION_STATE_DISCONNECTED;
1367         } catch (RemoteException e) {
1368             Log.e(TAG, "", e);
1369             return false;
1370         }
1371     }
1372 
1373     /**
1374      * Returns whether there is an open connection to this device
1375      * that has been encrypted.
1376      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1377      *
1378      * @return True if there is at least one encrypted connection to this device.
1379      * @hide
1380      */
1381     @SystemApi
1382     @RequiresPermission(android.Manifest.permission.BLUETOOTH)
isEncrypted()1383     public boolean isEncrypted() {
1384         final IBluetooth service = sService;
1385         if (service == null) {
1386             // BT is not enabled, we cannot be connected.
1387             return false;
1388         }
1389         try {
1390             return service.getConnectionState(this) > CONNECTION_STATE_CONNECTED;
1391         } catch (RemoteException e) {
1392             Log.e(TAG, "", e);
1393             return false;
1394         }
1395     }
1396 
1397     /**
1398      * Get the Bluetooth class of the remote device.
1399      *
1400      * @return Bluetooth class object, or null on error
1401      */
1402     @RequiresPermission(Manifest.permission.BLUETOOTH)
getBluetoothClass()1403     public BluetoothClass getBluetoothClass() {
1404         final IBluetooth service = sService;
1405         if (service == null) {
1406             Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
1407             return null;
1408         }
1409         try {
1410             int classInt = service.getRemoteClass(this);
1411             if (classInt == BluetoothClass.ERROR) return null;
1412             return new BluetoothClass(classInt);
1413         } catch (RemoteException e) {
1414             Log.e(TAG, "", e);
1415         }
1416         return null;
1417     }
1418 
1419     /**
1420      * Returns the supported features (UUIDs) of the remote device.
1421      *
1422      * <p>This method does not start a service discovery procedure to retrieve the UUIDs
1423      * from the remote device. Instead, the local cached copy of the service
1424      * UUIDs are returned.
1425      * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired.
1426      *
1427      * @return the supported features (UUIDs) of the remote device, or null on error
1428      */
1429     @RequiresPermission(Manifest.permission.BLUETOOTH)
getUuids()1430     public ParcelUuid[] getUuids() {
1431         final IBluetooth service = sService;
1432         if (service == null || !isBluetoothEnabled()) {
1433             Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
1434             return null;
1435         }
1436         try {
1437             return service.getRemoteUuids(this);
1438         } catch (RemoteException e) {
1439             Log.e(TAG, "", e);
1440         }
1441         return null;
1442     }
1443 
1444     /**
1445      * Perform a service discovery on the remote device to get the UUIDs supported.
1446      *
1447      * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
1448      * with the UUIDs supported by the remote end. If there is an error
1449      * in getting the SDP records or if the process takes a long time,
1450      * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently
1451      * present in the cache. Clients should use the {@link #getUuids} to get UUIDs
1452      * if service discovery is not to be performed.
1453      *
1454      * @return False if the sanity check fails, True if the process of initiating an ACL connection
1455      * to the remote device was started.
1456      */
1457     @RequiresPermission(Manifest.permission.BLUETOOTH)
fetchUuidsWithSdp()1458     public boolean fetchUuidsWithSdp() {
1459         final IBluetooth service = sService;
1460         if (service == null || !isBluetoothEnabled()) {
1461             Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
1462             return false;
1463         }
1464         try {
1465             return service.fetchRemoteUuids(this);
1466         } catch (RemoteException e) {
1467             Log.e(TAG, "", e);
1468         }
1469         return false;
1470     }
1471 
1472     /**
1473      * Perform a service discovery on the remote device to get the SDP records associated
1474      * with the specified UUID.
1475      *
1476      * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent,
1477      * with the SDP records found on the remote end. If there is an error
1478      * in getting the SDP records or if the process takes a long time,
1479      * {@link #ACTION_SDP_RECORD} intent is sent with an status value in
1480      * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
1481      * Detailed status error codes can be found by members of the Bluetooth package in
1482      * the AbstractionLayer class.
1483      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1484      * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
1485      * The object type will match one of the SdpXxxRecord types, depending on the UUID searched
1486      * for.
1487      *
1488      * @return False if the sanity check fails, True if the process
1489      *               of initiating an ACL connection to the remote device
1490      *               was started.
1491      */
1492     /** @hide */
sdpSearch(ParcelUuid uuid)1493     public boolean sdpSearch(ParcelUuid uuid) {
1494         final IBluetooth service = sService;
1495         if (service == null) {
1496             Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
1497             return false;
1498         }
1499         try {
1500             return service.sdpSearch(this, uuid);
1501         } catch (RemoteException e) {
1502             Log.e(TAG, "", e);
1503         }
1504         return false;
1505     }
1506 
1507     /**
1508      * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
1509      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1510      *
1511      * @return true pin has been set false for error
1512      */
setPin(byte[] pin)1513     public boolean setPin(byte[] pin) {
1514         final IBluetooth service = sService;
1515         if (service == null) {
1516             Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
1517             return false;
1518         }
1519         try {
1520             return service.setPin(this, true, pin.length, pin);
1521         } catch (RemoteException e) {
1522             Log.e(TAG, "", e);
1523         }
1524         return false;
1525     }
1526 
1527     /** @hide */
1528     @UnsupportedAppUsage
setPasskey(int passkey)1529     public boolean setPasskey(int passkey) {
1530         //TODO(BT)
1531         /*
1532         try {
1533             return sService.setPasskey(this, true, 4, passkey);
1534         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1535         return false;
1536     }
1537 
1538     /**
1539      * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
1540      *
1541      * @return true confirmation has been sent out false for error
1542      */
1543     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
setPairingConfirmation(boolean confirm)1544     public boolean setPairingConfirmation(boolean confirm) {
1545         final IBluetooth service = sService;
1546         if (service == null) {
1547             Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
1548             return false;
1549         }
1550         try {
1551             return service.setPairingConfirmation(this, confirm);
1552         } catch (RemoteException e) {
1553             Log.e(TAG, "", e);
1554         }
1555         return false;
1556     }
1557 
1558     /** @hide */
setRemoteOutOfBandData()1559     public boolean setRemoteOutOfBandData() {
1560         // TODO(BT)
1561         /*
1562         try {
1563           return sService.setRemoteOutOfBandData(this);
1564       } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1565         return false;
1566     }
1567 
1568     /** @hide */
1569     @UnsupportedAppUsage
cancelPairingUserInput()1570     public boolean cancelPairingUserInput() {
1571         final IBluetooth service = sService;
1572         if (service == null) {
1573             Log.e(TAG, "BT not enabled. Cannot create pairing user input");
1574             return false;
1575         }
1576         try {
1577             return service.cancelBondProcess(this);
1578         } catch (RemoteException e) {
1579             Log.e(TAG, "", e);
1580         }
1581         return false;
1582     }
1583 
1584     /** @hide */
1585     @UnsupportedAppUsage
isBluetoothDock()1586     public boolean isBluetoothDock() {
1587         // TODO(BT)
1588         /*
1589         try {
1590             return sService.isBluetoothDock(this);
1591         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1592         return false;
1593     }
1594 
isBluetoothEnabled()1595     boolean isBluetoothEnabled() {
1596         boolean ret = false;
1597         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1598         if (adapter != null && adapter.isEnabled()) {
1599             ret = true;
1600         }
1601         return ret;
1602     }
1603 
1604     /**
1605      * Requires {@link android.Manifest.permission#BLUETOOTH}.
1606      *
1607      * @return Whether the phonebook access is allowed to this device. Can be {@link
1608      * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
1609      * @hide
1610      */
1611     @UnsupportedAppUsage
getPhonebookAccessPermission()1612     public int getPhonebookAccessPermission() {
1613         final IBluetooth service = sService;
1614         if (service == null) {
1615             return ACCESS_UNKNOWN;
1616         }
1617         try {
1618             return service.getPhonebookAccessPermission(this);
1619         } catch (RemoteException e) {
1620             Log.e(TAG, "", e);
1621         }
1622         return ACCESS_UNKNOWN;
1623     }
1624 
1625     /**
1626      * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not
1627      * be routed to the {@link BluetoothDevice} if set to {@code true}.
1628      *
1629      * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice}
1630      * is an active device (for A2DP or HFP), the active device for that profile
1631      * will be set to null.
1632      * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP
1633      * active device is null, the {@link BluetoothDevice} will be set as the
1634      * active device for that profile.
1635      * If the {@link BluetoothDevice} is disconnected, it exits silence mode.
1636      * If the {@link BluetoothDevice} is set as the active device for A2DP or
1637      * HFP, while silence mode is enabled, then the device will exit silence mode.
1638      * If the {@link BluetoothDevice} is in silence mode, AVRCP position change
1639      * event and HFP AG indicators will be disabled.
1640      * If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot
1641      * enter silence mode.
1642      *
1643      * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1644      *
1645      * @param silence true to enter silence mode, false to exit
1646      * @return true on success, false on error.
1647      * @throws IllegalStateException if Bluetooth is not turned ON.
1648      * @hide
1649      */
1650     @SystemApi
1651     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
setSilenceMode(boolean silence)1652     public boolean setSilenceMode(boolean silence) {
1653         final IBluetooth service = sService;
1654         if (service == null) {
1655             throw new IllegalStateException("Bluetooth is not turned ON");
1656         }
1657         try {
1658             return service.setSilenceMode(this, silence);
1659         } catch (RemoteException e) {
1660             Log.e(TAG, "setSilenceMode fail", e);
1661             return false;
1662         }
1663     }
1664 
1665     /**
1666      * Check whether the {@link BluetoothDevice} is in silence mode
1667      *
1668      * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1669      *
1670      * @return true on device in silence mode, otherwise false.
1671      * @throws IllegalStateException if Bluetooth is not turned ON.
1672      * @hide
1673      */
1674     @SystemApi
1675     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
isInSilenceMode()1676     public boolean isInSilenceMode() {
1677         final IBluetooth service = sService;
1678         if (service == null) {
1679             throw new IllegalStateException("Bluetooth is not turned ON");
1680         }
1681         try {
1682             return service.getSilenceMode(this);
1683         } catch (RemoteException e) {
1684             Log.e(TAG, "isInSilenceMode fail", e);
1685             return false;
1686         }
1687     }
1688 
1689     /**
1690      * Sets whether the phonebook access is allowed to this device.
1691      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1692      *
1693      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
1694      * #ACCESS_REJECTED}.
1695      * @return Whether the value has been successfully set.
1696      * @hide
1697      */
1698     @SystemApi
1699     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
setPhonebookAccessPermission(int value)1700     public boolean setPhonebookAccessPermission(int value) {
1701         final IBluetooth service = sService;
1702         if (service == null) {
1703             return false;
1704         }
1705         try {
1706             return service.setPhonebookAccessPermission(this, value);
1707         } catch (RemoteException e) {
1708             Log.e(TAG, "", e);
1709         }
1710         return false;
1711     }
1712 
1713     /**
1714      * Requires {@link android.Manifest.permission#BLUETOOTH}.
1715      *
1716      * @return Whether the message access is allowed to this device. Can be {@link #ACCESS_UNKNOWN},
1717      * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
1718      * @hide
1719      */
1720     @UnsupportedAppUsage
getMessageAccessPermission()1721     public int getMessageAccessPermission() {
1722         final IBluetooth service = sService;
1723         if (service == null) {
1724             return ACCESS_UNKNOWN;
1725         }
1726         try {
1727             return service.getMessageAccessPermission(this);
1728         } catch (RemoteException e) {
1729             Log.e(TAG, "", e);
1730         }
1731         return ACCESS_UNKNOWN;
1732     }
1733 
1734     /**
1735      * Sets whether the message access is allowed to this device.
1736      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1737      *
1738      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
1739      * #ACCESS_REJECTED}.
1740      * @return Whether the value has been successfully set.
1741      * @hide
1742      */
1743     @UnsupportedAppUsage
setMessageAccessPermission(int value)1744     public boolean setMessageAccessPermission(int value) {
1745         final IBluetooth service = sService;
1746         if (service == null) {
1747             return false;
1748         }
1749         try {
1750             return service.setMessageAccessPermission(this, value);
1751         } catch (RemoteException e) {
1752             Log.e(TAG, "", e);
1753         }
1754         return false;
1755     }
1756 
1757     /**
1758      * Requires {@link android.Manifest.permission#BLUETOOTH}.
1759      *
1760      * @return Whether the Sim access is allowed to this device. Can be {@link #ACCESS_UNKNOWN},
1761      * {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
1762      * @hide
1763      */
getSimAccessPermission()1764     public int getSimAccessPermission() {
1765         final IBluetooth service = sService;
1766         if (service == null) {
1767             return ACCESS_UNKNOWN;
1768         }
1769         try {
1770             return service.getSimAccessPermission(this);
1771         } catch (RemoteException e) {
1772             Log.e(TAG, "", e);
1773         }
1774         return ACCESS_UNKNOWN;
1775     }
1776 
1777     /**
1778      * Sets whether the Sim access is allowed to this device.
1779      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1780      *
1781      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
1782      * #ACCESS_REJECTED}.
1783      * @return Whether the value has been successfully set.
1784      * @hide
1785      */
1786     @UnsupportedAppUsage
setSimAccessPermission(int value)1787     public boolean setSimAccessPermission(int value) {
1788         final IBluetooth service = sService;
1789         if (service == null) {
1790             return false;
1791         }
1792         try {
1793             return service.setSimAccessPermission(this, value);
1794         } catch (RemoteException e) {
1795             Log.e(TAG, "", e);
1796         }
1797         return false;
1798     }
1799 
1800     /**
1801      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
1802      * outgoing connection to this remote device on given channel.
1803      * <p>The remote device will be authenticated and communication on this
1804      * socket will be encrypted.
1805      * <p> Use this socket only if an authenticated socket link is possible.
1806      * Authentication refers to the authentication of the link key to
1807      * prevent man-in-the-middle type of attacks.
1808      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1809      * have an input and output capability or just has the ability to
1810      * display a numeric key, a secure socket connection is not possible.
1811      * In such a case, use {@link createInsecureRfcommSocket}.
1812      * For more details, refer to the Security Model section 5.2 (vol 3) of
1813      * Bluetooth Core Specification version 2.1 + EDR.
1814      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1815      * connection.
1816      * <p>Valid RFCOMM channels are in range 1 to 30.
1817      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1818      *
1819      * @param channel RFCOMM channel to connect to
1820      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1821      * @throws IOException on error, for example Bluetooth not available, or insufficient
1822      * permissions
1823      * @hide
1824      */
1825     @UnsupportedAppUsage
createRfcommSocket(int channel)1826     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
1827         if (!isBluetoothEnabled()) {
1828             Log.e(TAG, "Bluetooth is not enabled");
1829             throw new IOException();
1830         }
1831         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
1832                 null);
1833     }
1834 
1835     /**
1836      * Create an L2cap {@link BluetoothSocket} ready to start a secure
1837      * outgoing connection to this remote device on given channel.
1838      * <p>The remote device will be authenticated and communication on this
1839      * socket will be encrypted.
1840      * <p> Use this socket only if an authenticated socket link is possible.
1841      * Authentication refers to the authentication of the link key to
1842      * prevent man-in-the-middle type of attacks.
1843      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1844      * have an input and output capability or just has the ability to
1845      * display a numeric key, a secure socket connection is not possible.
1846      * In such a case, use {@link createInsecureRfcommSocket}.
1847      * For more details, refer to the Security Model section 5.2 (vol 3) of
1848      * Bluetooth Core Specification version 2.1 + EDR.
1849      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1850      * connection.
1851      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
1852      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1853      *
1854      * @param channel L2cap PSM/channel to connect to
1855      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1856      * @throws IOException on error, for example Bluetooth not available, or insufficient
1857      * permissions
1858      * @hide
1859      */
createL2capSocket(int channel)1860     public BluetoothSocket createL2capSocket(int channel) throws IOException {
1861         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
1862                 null);
1863     }
1864 
1865     /**
1866      * Create an L2cap {@link BluetoothSocket} ready to start an insecure
1867      * outgoing connection to this remote device on given channel.
1868      * <p>The remote device will be not authenticated and communication on this
1869      * socket will not be encrypted.
1870      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1871      * connection.
1872      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
1873      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1874      *
1875      * @param channel L2cap PSM/channel to connect to
1876      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1877      * @throws IOException on error, for example Bluetooth not available, or insufficient
1878      * permissions
1879      * @hide
1880      */
createInsecureL2capSocket(int channel)1881     public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException {
1882         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel,
1883                 null);
1884     }
1885 
1886     /**
1887      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
1888      * outgoing connection to this remote device using SDP lookup of uuid.
1889      * <p>This is designed to be used with {@link
1890      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
1891      * Bluetooth applications.
1892      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1893      * connection. This will also perform an SDP lookup of the given uuid to
1894      * determine which channel to connect to.
1895      * <p>The remote device will be authenticated and communication on this
1896      * socket will be encrypted.
1897      * <p> Use this socket only if an authenticated socket link is possible.
1898      * Authentication refers to the authentication of the link key to
1899      * prevent man-in-the-middle type of attacks.
1900      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1901      * have an input and output capability or just has the ability to
1902      * display a numeric key, a secure socket connection is not possible.
1903      * In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}.
1904      * For more details, refer to the Security Model section 5.2 (vol 3) of
1905      * Bluetooth Core Specification version 2.1 + EDR.
1906      * <p>Hint: If you are connecting to a Bluetooth serial board then try
1907      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
1908      * However if you are connecting to an Android peer then please generate
1909      * your own unique UUID.
1910      *
1911      * @param uuid service record uuid to lookup RFCOMM channel
1912      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1913      * @throws IOException on error, for example Bluetooth not available, or insufficient
1914      * permissions
1915      */
1916     @RequiresPermission(Manifest.permission.BLUETOOTH)
createRfcommSocketToServiceRecord(UUID uuid)1917     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
1918         if (!isBluetoothEnabled()) {
1919             Log.e(TAG, "Bluetooth is not enabled");
1920             throw new IOException();
1921         }
1922 
1923         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
1924                 new ParcelUuid(uuid));
1925     }
1926 
1927     /**
1928      * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
1929      * outgoing connection to this remote device using SDP lookup of uuid.
1930      * <p> The communication channel will not have an authenticated link key
1931      * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
1932      * devices, the link key will be encrypted, as encryption is mandatory.
1933      * For legacy devices (pre Bluetooth 2.1 devices) the link key will
1934      * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
1935      * encrypted and authenticated communication channel is desired.
1936      * <p>This is designed to be used with {@link
1937      * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
1938      * Bluetooth applications.
1939      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1940      * connection. This will also perform an SDP lookup of the given uuid to
1941      * determine which channel to connect to.
1942      * <p>The remote device will be authenticated and communication on this
1943      * socket will be encrypted.
1944      * <p>Hint: If you are connecting to a Bluetooth serial board then try
1945      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
1946      * However if you are connecting to an Android peer then please generate
1947      * your own unique UUID.
1948      *
1949      * @param uuid service record uuid to lookup RFCOMM channel
1950      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1951      * @throws IOException on error, for example Bluetooth not available, or insufficient
1952      * permissions
1953      */
1954     @RequiresPermission(Manifest.permission.BLUETOOTH)
createInsecureRfcommSocketToServiceRecord(UUID uuid)1955     public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
1956         if (!isBluetoothEnabled()) {
1957             Log.e(TAG, "Bluetooth is not enabled");
1958             throw new IOException();
1959         }
1960         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
1961                 new ParcelUuid(uuid));
1962     }
1963 
1964     /**
1965      * Construct an insecure RFCOMM socket ready to start an outgoing
1966      * connection.
1967      * Call #connect on the returned #BluetoothSocket to begin the connection.
1968      * The remote device will not be authenticated and communication on this
1969      * socket will not be encrypted.
1970      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1971      *
1972      * @param port remote port
1973      * @return An RFCOMM BluetoothSocket
1974      * @throws IOException On error, for example Bluetooth not available, or insufficient
1975      * permissions.
1976      * @hide
1977      */
1978     @UnsupportedAppUsage
createInsecureRfcommSocket(int port)1979     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
1980         if (!isBluetoothEnabled()) {
1981             Log.e(TAG, "Bluetooth is not enabled");
1982             throw new IOException();
1983         }
1984         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
1985                 null);
1986     }
1987 
1988     /**
1989      * Construct a SCO socket ready to start an outgoing connection.
1990      * Call #connect on the returned #BluetoothSocket to begin the connection.
1991      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1992      *
1993      * @return a SCO BluetoothSocket
1994      * @throws IOException on error, for example Bluetooth not available, or insufficient
1995      * permissions.
1996      * @hide
1997      */
1998     @UnsupportedAppUsage
createScoSocket()1999     public BluetoothSocket createScoSocket() throws IOException {
2000         if (!isBluetoothEnabled()) {
2001             Log.e(TAG, "Bluetooth is not enabled");
2002             throw new IOException();
2003         }
2004         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
2005     }
2006 
2007     /**
2008      * Check that a pin is valid and convert to byte array.
2009      *
2010      * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
2011      *
2012      * @param pin pin as java String
2013      * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin.
2014      * @hide
2015      */
2016     @UnsupportedAppUsage
convertPinToBytes(String pin)2017     public static byte[] convertPinToBytes(String pin) {
2018         if (pin == null) {
2019             return null;
2020         }
2021         byte[] pinBytes;
2022         try {
2023             pinBytes = pin.getBytes("UTF-8");
2024         } catch (UnsupportedEncodingException uee) {
2025             Log.e(TAG, "UTF-8 not supported?!?");  // this should not happen
2026             return null;
2027         }
2028         if (pinBytes.length <= 0 || pinBytes.length > 16) {
2029             return null;
2030         }
2031         return pinBytes;
2032     }
2033 
2034     /**
2035      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2036      * The callback is used to deliver results to Caller, such as connection status as well
2037      * as any further GATT client operations.
2038      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2039      * GATT client operations.
2040      *
2041      * @param callback GATT callback handler that will receive asynchronous callbacks.
2042      * @param autoConnect Whether to directly connect to the remote device (false) or to
2043      * automatically connect as soon as the remote device becomes available (true).
2044      * @throws IllegalArgumentException if callback is null
2045      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)2046     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2047             BluetoothGattCallback callback) {
2048         return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO));
2049     }
2050 
2051     /**
2052      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2053      * The callback is used to deliver results to Caller, such as connection status as well
2054      * as any further GATT client operations.
2055      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2056      * GATT client operations.
2057      *
2058      * @param callback GATT callback handler that will receive asynchronous callbacks.
2059      * @param autoConnect Whether to directly connect to the remote device (false) or to
2060      * automatically connect as soon as the remote device becomes available (true).
2061      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2062      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2063      * BluetoothDevice#TRANSPORT_LE}
2064      * @throws IllegalArgumentException if callback is null
2065      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)2066     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2067             BluetoothGattCallback callback, int transport) {
2068         return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK));
2069     }
2070 
2071     /**
2072      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2073      * The callback is used to deliver results to Caller, such as connection status as well
2074      * as any further GATT client operations.
2075      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2076      * GATT client operations.
2077      *
2078      * @param callback GATT callback handler that will receive asynchronous callbacks.
2079      * @param autoConnect Whether to directly connect to the remote device (false) or to
2080      * automatically connect as soon as the remote device becomes available (true).
2081      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2082      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2083      * BluetoothDevice#TRANSPORT_LE}
2084      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
2085      * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link
2086      * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
2087      * is set to true.
2088      * @throws NullPointerException if callback is null
2089      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy)2090     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2091             BluetoothGattCallback callback, int transport, int phy) {
2092         return connectGatt(context, autoConnect, callback, transport, phy, null);
2093     }
2094 
2095     /**
2096      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2097      * The callback is used to deliver results to Caller, such as connection status as well
2098      * as any further GATT client operations.
2099      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2100      * GATT client operations.
2101      *
2102      * @param callback GATT callback handler that will receive asynchronous callbacks.
2103      * @param autoConnect Whether to directly connect to the remote device (false) or to
2104      * automatically connect as soon as the remote device becomes available (true).
2105      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2106      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2107      * BluetoothDevice#TRANSPORT_LE}
2108      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
2109      * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
2110      * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
2111      * is set to true.
2112      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
2113      * an un-specified background thread.
2114      * @throws NullPointerException if callback is null
2115      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler)2116     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2117             BluetoothGattCallback callback, int transport, int phy,
2118             Handler handler) {
2119         return connectGatt(context, autoConnect, callback, transport, false, phy, handler);
2120     }
2121 
2122     /**
2123      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2124      * The callback is used to deliver results to Caller, such as connection status as well
2125      * as any further GATT client operations.
2126      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2127      * GATT client operations.
2128      *
2129      * @param callback GATT callback handler that will receive asynchronous callbacks.
2130      * @param autoConnect Whether to directly connect to the remote device (false) or to
2131      * automatically connect as soon as the remote device becomes available (true).
2132      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2133      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2134      * BluetoothDevice#TRANSPORT_LE}
2135      * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client
2136      * does not hold a GATT connection. It automatically disconnects when no other GATT connections
2137      * are active for the remote device.
2138      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
2139      * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
2140      * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
2141      * is set to true.
2142      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
2143      * an un-specified background thread.
2144      * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client
2145      * operations.
2146      * @hide
2147      */
2148     @UnsupportedAppUsage
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, boolean opportunistic, int phy, Handler handler)2149     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2150             BluetoothGattCallback callback, int transport,
2151             boolean opportunistic, int phy, Handler handler) {
2152         if (callback == null) {
2153             throw new NullPointerException("callback is null");
2154         }
2155 
2156         // TODO(Bluetooth) check whether platform support BLE
2157         //     Do the check here or in GattServer?
2158         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2159         IBluetoothManager managerService = adapter.getBluetoothManager();
2160         try {
2161             IBluetoothGatt iGatt = managerService.getBluetoothGatt();
2162             if (iGatt == null) {
2163                 // BLE is not supported
2164                 return null;
2165             }
2166             BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport, opportunistic, phy);
2167             gatt.connect(autoConnect, callback, handler);
2168             return gatt;
2169         } catch (RemoteException e) {
2170             Log.e(TAG, "", e);
2171         }
2172         return null;
2173     }
2174 
2175     /**
2176      * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
2177      * be used to start a secure outgoing connection to the remote device with the same dynamic
2178      * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
2179      * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for
2180      * peer-peer Bluetooth applications.
2181      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
2182      * <p>Application using this API is responsible for obtaining PSM value from remote device.
2183      * <p>The remote device will be authenticated and communication on this socket will be
2184      * encrypted.
2185      * <p> Use this socket if an authenticated socket link is possible. Authentication refers
2186      * to the authentication of the link key to prevent man-in-the-middle type of attacks.
2187      *
2188      * @param psm dynamic PSM value from remote device
2189      * @return a CoC #BluetoothSocket ready for an outgoing connection
2190      * @throws IOException on error, for example Bluetooth not available, or insufficient
2191      * permissions
2192      */
2193     @RequiresPermission(Manifest.permission.BLUETOOTH)
createL2capChannel(int psm)2194     public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException {
2195         if (!isBluetoothEnabled()) {
2196             Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
2197             throw new IOException();
2198         }
2199         if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm);
2200         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm,
2201                 null);
2202     }
2203 
2204     /**
2205      * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
2206      * API name, createL2capChannel.
2207      * @hide
2208      */
2209     @RequiresPermission(Manifest.permission.BLUETOOTH)
createL2capCocSocket(int transport, int psm)2210     public BluetoothSocket createL2capCocSocket(int transport, int psm) throws IOException {
2211         Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createL2capChannel");
2212         return createL2capChannel(psm);
2213     }
2214 
2215     /**
2216      * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
2217      * be used to start a secure outgoing connection to the remote device with the same dynamic
2218      * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
2219      * <p>This is designed to be used with {@link
2220      * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications.
2221      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
2222      * <p>Application using this API is responsible for obtaining PSM value from remote device.
2223      * <p> The communication channel may not have an authenticated link key, i.e. it may be subject
2224      * to man-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and
2225      * authenticated communication channel is possible.
2226      *
2227      * @param psm dynamic PSM value from remote device
2228      * @return a CoC #BluetoothSocket ready for an outgoing connection
2229      * @throws IOException on error, for example Bluetooth not available, or insufficient
2230      * permissions
2231      */
2232     @RequiresPermission(Manifest.permission.BLUETOOTH)
createInsecureL2capChannel(int psm)2233     public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
2234         if (!isBluetoothEnabled()) {
2235             Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
2236             throw new IOException();
2237         }
2238         if (DBG) {
2239             Log.d(TAG, "createInsecureL2capChannel: psm=" + psm);
2240         }
2241         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm,
2242                 null);
2243     }
2244 
2245     /**
2246      * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
2247      * API name, createInsecureL2capChannel.
2248      * @hide
2249      */
2250     @RequiresPermission(Manifest.permission.BLUETOOTH)
createInsecureL2capCocSocket(int transport, int psm)2251     public BluetoothSocket createInsecureL2capCocSocket(int transport, int psm) throws IOException {
2252         Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createInsecureL2capChannel");
2253         return createInsecureL2capChannel(psm);
2254     }
2255 
2256     /**
2257      * Set a keyed metadata of this {@link BluetoothDevice} to a
2258      * {@link String} value.
2259      * Only bonded devices's metadata will be persisted across Bluetooth
2260      * restart.
2261      * Metadata will be removed when the device's bond state is moved to
2262      * {@link #BOND_NONE}.
2263      *
2264      * @param key must be within the list of BluetoothDevice.METADATA_*
2265      * @param value a byte array data to set for key. Must be less than
2266      * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length
2267      * @return true on success, false on error
2268      * @hide
2269     */
2270     @SystemApi
2271     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
setMetadata(int key, @NonNull byte[] value)2272     public boolean setMetadata(int key, @NonNull byte[] value) {
2273         final IBluetooth service = sService;
2274         if (service == null) {
2275             Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
2276             return false;
2277         }
2278         if (value.length > METADATA_MAX_LENGTH) {
2279             throw new IllegalArgumentException("value length is " + value.length
2280                     + ", should not over " + METADATA_MAX_LENGTH);
2281         }
2282         try {
2283             return service.setMetadata(this, key, value);
2284         } catch (RemoteException e) {
2285             Log.e(TAG, "setMetadata fail", e);
2286             return false;
2287         }
2288     }
2289 
2290     /**
2291      * Get a keyed metadata for this {@link BluetoothDevice} as {@link String}
2292      *
2293      * @param key must be within the list of BluetoothDevice.METADATA_*
2294      * @return Metadata of the key as byte array, null on error or not found
2295      * @hide
2296      */
2297     @SystemApi
2298     @Nullable
2299     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
getMetadata(int key)2300     public byte[] getMetadata(int key) {
2301         final IBluetooth service = sService;
2302         if (service == null) {
2303             Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
2304             return null;
2305         }
2306         try {
2307             return service.getMetadata(this, key);
2308         } catch (RemoteException e) {
2309             Log.e(TAG, "getMetadata fail", e);
2310             return null;
2311         }
2312     }
2313 }
2314