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