• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.bluetooth;
18 
19 import android.annotation.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         } catch (RemoteException e) {
1334             Log.e(TAG, "", e);
1335         }
1336         return null;
1337     }
1338 
1339     /** @hide */
1340     @Retention(RetentionPolicy.SOURCE)
1341     @IntDef(value = {
1342             BluetoothStatusCodes.SUCCESS,
1343             BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
1344             BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
1345             BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
1346             BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED
1347     })
1348     public @interface SetAliasReturnValues{}
1349 
1350     /**
1351      * Sets the locally modifiable name (alias) of the remote Bluetooth device. This method
1352      * overwrites the previously stored alias. The new alias is saved in local
1353      * storage so that the change is preserved over power cycles.
1354      *
1355      * <p>This method requires the calling app to be associated with Companion Device Manager (see
1356      * {@link android.companion.CompanionDeviceManager#associate(AssociationRequest,
1357      * android.companion.CompanionDeviceManager.Callback, Handler)}) and have the
1358      * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission. Alternatively, if the
1359      * caller has the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission, they can
1360      * bypass the Companion Device Manager association requirement as well as other permission
1361      * requirements.
1362      *
1363      * @param alias is the new locally modifiable name for the remote Bluetooth device which must
1364      *              be the empty string. If null, we clear the alias.
1365      * @return whether the alias was successfully changed
1366      * @throws IllegalArgumentException if the alias is the empty string
1367      */
1368     @RequiresLegacyBluetoothPermission
1369     @RequiresBluetoothConnectPermission
1370     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
setAlias(@ullable String alias)1371     public @SetAliasReturnValues int setAlias(@Nullable String alias) {
1372         if (alias != null && alias.isEmpty()) {
1373             throw new IllegalArgumentException("alias cannot be the empty string");
1374         }
1375         final IBluetooth service = sService;
1376         if (service == null) {
1377             Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
1378             return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
1379         }
1380         try {
1381             return service.setRemoteAlias(this, alias, mAttributionSource);
1382         } catch (RemoteException e) {
1383             Log.e(TAG, "", e);
1384             throw e.rethrowFromSystemServer();
1385         }
1386     }
1387 
1388     /**
1389      * Get the most recent identified battery level of this Bluetooth device
1390      *
1391      * @return Battery level in percents from 0 to 100, {@link #BATTERY_LEVEL_BLUETOOTH_OFF} if
1392      * Bluetooth is disabled or {@link #BATTERY_LEVEL_UNKNOWN} if device is disconnected, or does
1393      * not have any battery reporting service, or return value is invalid
1394      * @hide
1395      */
1396     @UnsupportedAppUsage
1397     @RequiresLegacyBluetoothPermission
1398     @RequiresBluetoothConnectPermission
1399     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getBatteryLevel()1400     public int getBatteryLevel() {
1401         final IBluetooth service = sService;
1402         if (service == null) {
1403             Log.e(TAG, "Bluetooth disabled. Cannot get remote device battery level");
1404             return BATTERY_LEVEL_BLUETOOTH_OFF;
1405         }
1406         try {
1407             return service.getBatteryLevel(this, mAttributionSource);
1408         } catch (RemoteException e) {
1409             Log.e(TAG, "", e);
1410         }
1411         return BATTERY_LEVEL_UNKNOWN;
1412     }
1413 
1414     /**
1415      * Start the bonding (pairing) process with the remote device.
1416      * <p>This is an asynchronous call, it will return immediately. Register
1417      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
1418      * the bonding process completes, and its result.
1419      * <p>Android system services will handle the necessary user interactions
1420      * to confirm and complete the bonding process.
1421      *
1422      * @return false on immediate error, true if bonding will begin
1423      */
1424     @RequiresLegacyBluetoothAdminPermission
1425     @RequiresBluetoothConnectPermission
1426     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
createBond()1427     public boolean createBond() {
1428         return createBond(TRANSPORT_AUTO);
1429     }
1430 
1431     /**
1432      * Start the bonding (pairing) process with the remote device using the
1433      * specified transport.
1434      *
1435      * <p>This is an asynchronous call, it will return immediately. Register
1436      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
1437      * the bonding process completes, and its result.
1438      * <p>Android system services will handle the necessary user interactions
1439      * to confirm and complete the bonding process.
1440      *
1441      * @param transport The transport to use for the pairing procedure.
1442      * @return false on immediate error, true if bonding will begin
1443      * @throws IllegalArgumentException if an invalid transport was specified
1444      * @hide
1445      */
1446     @UnsupportedAppUsage
1447     @RequiresLegacyBluetoothAdminPermission
1448     @RequiresBluetoothConnectPermission
1449     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
createBond(int transport)1450     public boolean createBond(int transport) {
1451         return createBondInternal(transport, null, null);
1452     }
1453 
1454     /**
1455      * Start the bonding (pairing) process with the remote device using the
1456      * Out Of Band mechanism.
1457      *
1458      * <p>This is an asynchronous call, it will return immediately. Register
1459      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
1460      * the bonding process completes, and its result.
1461      *
1462      * <p>Android system services will handle the necessary user interactions
1463      * to confirm and complete the bonding process.
1464      *
1465      * <p>There are two possible versions of OOB Data.  This data can come in as
1466      * P192 or P256.  This is a reference to the cryptography used to generate the key.
1467      * The caller may pass one or both.  If both types of data are passed, then the
1468      * P256 data will be preferred, and thus used.
1469      *
1470      * @param transport - Transport to use
1471      * @param remoteP192Data - Out Of Band data (P192) or null
1472      * @param remoteP256Data - Out Of Band data (P256) or null
1473      * @return false on immediate error, true if bonding will begin
1474      * @hide
1475      */
1476     @SystemApi
1477     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
createBondOutOfBand(int transport, @Nullable OobData remoteP192Data, @Nullable OobData remoteP256Data)1478     public boolean createBondOutOfBand(int transport, @Nullable OobData remoteP192Data,
1479             @Nullable OobData remoteP256Data) {
1480         if (remoteP192Data == null && remoteP256Data == null) {
1481             throw new IllegalArgumentException(
1482                 "One or both arguments for the OOB data types are required to not be null."
1483                 + "  Please use createBond() instead if you do not have OOB data to pass.");
1484         }
1485         return createBondInternal(transport, remoteP192Data, remoteP256Data);
1486     }
1487 
1488     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
createBondInternal(int transport, @Nullable OobData remoteP192Data, @Nullable OobData remoteP256Data)1489     private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data,
1490             @Nullable OobData remoteP256Data) {
1491         final IBluetooth service = sService;
1492         if (service == null) {
1493             Log.w(TAG, "BT not enabled, createBondOutOfBand failed");
1494             return false;
1495         }
1496         try {
1497             return service.createBond(
1498                     this, transport, remoteP192Data, remoteP256Data, mAttributionSource);
1499         } catch (RemoteException e) {
1500             Log.e(TAG, "", e);
1501         }
1502         return false;
1503     }
1504 
1505     /**
1506      * Gets whether bonding was initiated locally
1507      *
1508      * @return true if bonding is initiated locally, false otherwise
1509      *
1510      * @hide
1511      */
1512     @UnsupportedAppUsage
1513     @RequiresLegacyBluetoothPermission
1514     @RequiresBluetoothConnectPermission
1515     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
isBondingInitiatedLocally()1516     public boolean isBondingInitiatedLocally() {
1517         final IBluetooth service = sService;
1518         if (service == null) {
1519             Log.w(TAG, "BT not enabled, isBondingInitiatedLocally failed");
1520             return false;
1521         }
1522         try {
1523             return service.isBondingInitiatedLocally(this, mAttributionSource);
1524         } catch (RemoteException e) {
1525             Log.e(TAG, "", e);
1526         }
1527         return false;
1528     }
1529 
1530     /**
1531      * Cancel an in-progress bonding request started with {@link #createBond}.
1532      *
1533      * @return true on success, false on error
1534      * @hide
1535      */
1536     @SystemApi
1537     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
cancelBondProcess()1538     public boolean cancelBondProcess() {
1539         final IBluetooth service = sService;
1540         if (service == null) {
1541             Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
1542             return false;
1543         }
1544         try {
1545             Log.i(TAG, "cancelBondProcess() for device " + getAddress()
1546                     + " called by pid: " + Process.myPid()
1547                     + " tid: " + Process.myTid());
1548             return service.cancelBondProcess(this, mAttributionSource);
1549         } catch (RemoteException e) {
1550             Log.e(TAG, "", e);
1551         }
1552         return false;
1553     }
1554 
1555     /**
1556      * Remove bond (pairing) with the remote device.
1557      * <p>Delete the link key associated with the remote device, and
1558      * immediately terminate connections to that device that require
1559      * authentication and encryption.
1560      *
1561      * @return true on success, false on error
1562      * @hide
1563      */
1564     @SystemApi
1565     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
removeBond()1566     public boolean removeBond() {
1567         final IBluetooth service = sService;
1568         if (service == null) {
1569             Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
1570             return false;
1571         }
1572         try {
1573             Log.i(TAG, "removeBond() for device " + getAddress()
1574                     + " called by pid: " + Process.myPid()
1575                     + " tid: " + Process.myTid());
1576             return service.removeBond(this, mAttributionSource);
1577         } catch (RemoteException e) {
1578             Log.e(TAG, "", e);
1579         }
1580         return false;
1581     }
1582 
1583     private static final String BLUETOOTH_BONDING_CACHE_PROPERTY =
1584             "cache_key.bluetooth.get_bond_state";
1585     private final PropertyInvalidatedCache<BluetoothDevice, Integer> mBluetoothBondCache =
1586             new PropertyInvalidatedCache<BluetoothDevice, Integer>(
1587                 8, BLUETOOTH_BONDING_CACHE_PROPERTY) {
1588                 @Override
1589                 @SuppressLint("AndroidFrameworkRequiresPermission")
1590                 protected Integer recompute(BluetoothDevice query) {
1591                     try {
1592                         return sService.getBondState(query, mAttributionSource);
1593                     } catch (RemoteException e) {
1594                         throw e.rethrowAsRuntimeException();
1595                     }
1596                 }
1597             };
1598 
1599     /** @hide */
disableBluetoothGetBondStateCache()1600     public void disableBluetoothGetBondStateCache() {
1601         mBluetoothBondCache.disableLocal();
1602     }
1603 
1604     /** @hide */
invalidateBluetoothGetBondStateCache()1605     public static void invalidateBluetoothGetBondStateCache() {
1606         PropertyInvalidatedCache.invalidateCache(BLUETOOTH_BONDING_CACHE_PROPERTY);
1607     }
1608 
1609     /**
1610      * Get the bond state of the remote device.
1611      * <p>Possible values for the bond state are:
1612      * {@link #BOND_NONE},
1613      * {@link #BOND_BONDING},
1614      * {@link #BOND_BONDED}.
1615      *
1616      * @return the bond state
1617      */
1618     @RequiresLegacyBluetoothPermission
1619     @RequiresBluetoothConnectPermission
1620     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
1621     @SuppressLint("AndroidFrameworkRequiresPermission")
getBondState()1622     public int getBondState() {
1623         final IBluetooth service = sService;
1624         if (service == null) {
1625             Log.e(TAG, "BT not enabled. Cannot get bond state");
1626             return BOND_NONE;
1627         }
1628         try {
1629             return mBluetoothBondCache.query(this);
1630         } catch (RuntimeException e) {
1631             if (e.getCause() instanceof RemoteException) {
1632                 Log.e(TAG, "", e);
1633             } else {
1634                 throw e;
1635             }
1636         }
1637         return BOND_NONE;
1638     }
1639 
1640     /**
1641      * Checks whether this bluetooth device is associated with CDM and meets the criteria to skip
1642      * the bluetooth pairing dialog because it has been already consented by the CDM prompt.
1643      *
1644      * @return true if we can bond without the dialog, false otherwise
1645      *
1646      * @hide
1647      */
1648     @SystemApi
1649     @RequiresPermission(allOf = {
1650             android.Manifest.permission.BLUETOOTH_CONNECT,
1651             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
1652     })
canBondWithoutDialog()1653     public boolean canBondWithoutDialog() {
1654         final IBluetooth service = sService;
1655         if (service == null) {
1656             Log.e(TAG, "BT not enabled. Cannot check if we can skip pairing dialog");
1657             return false;
1658         }
1659         try {
1660             if (DBG) Log.d(TAG, "canBondWithoutDialog, device: " + this);
1661             return service.canBondWithoutDialog(this, mAttributionSource);
1662         } catch (RemoteException e) {
1663             Log.e(TAG, "", e);
1664         }
1665         return false;
1666     }
1667 
1668     /**
1669      * Returns whether there is an open connection to this device.
1670      *
1671      * @return True if there is at least one open connection to this device.
1672      * @hide
1673      */
1674     @SystemApi
1675     @RequiresLegacyBluetoothPermission
1676     @RequiresBluetoothConnectPermission
1677     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
isConnected()1678     public boolean isConnected() {
1679         final IBluetooth service = sService;
1680         if (service == null) {
1681             // BT is not enabled, we cannot be connected.
1682             return false;
1683         }
1684         try {
1685             return service.getConnectionStateWithAttribution(this, mAttributionSource)
1686                     != CONNECTION_STATE_DISCONNECTED;
1687         } catch (RemoteException e) {
1688             Log.e(TAG, "", e);
1689             return false;
1690         }
1691     }
1692 
1693     /**
1694      * Returns whether there is an open connection to this device
1695      * that has been encrypted.
1696      *
1697      * @return True if there is at least one encrypted connection to this device.
1698      * @hide
1699      */
1700     @SystemApi
1701     @RequiresLegacyBluetoothPermission
1702     @RequiresBluetoothConnectPermission
1703     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
isEncrypted()1704     public boolean isEncrypted() {
1705         final IBluetooth service = sService;
1706         if (service == null) {
1707             // BT is not enabled, we cannot be connected.
1708             return false;
1709         }
1710         try {
1711             return service.getConnectionStateWithAttribution(this, mAttributionSource)
1712                     > CONNECTION_STATE_CONNECTED;
1713         } catch (RemoteException e) {
1714             Log.e(TAG, "", e);
1715             return false;
1716         }
1717     }
1718 
1719     /**
1720      * Get the Bluetooth class of the remote device.
1721      *
1722      * @return Bluetooth class object, or null on error
1723      */
1724     @RequiresLegacyBluetoothPermission
1725     @RequiresBluetoothConnectPermission
1726     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getBluetoothClass()1727     public BluetoothClass getBluetoothClass() {
1728         final IBluetooth service = sService;
1729         if (service == null) {
1730             Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
1731             return null;
1732         }
1733         try {
1734             int classInt = service.getRemoteClass(this, mAttributionSource);
1735             if (classInt == BluetoothClass.ERROR) return null;
1736             return new BluetoothClass(classInt);
1737         } catch (RemoteException e) {
1738             Log.e(TAG, "", e);
1739         }
1740         return null;
1741     }
1742 
1743     /**
1744      * Returns the supported features (UUIDs) of the remote device.
1745      *
1746      * <p>This method does not start a service discovery procedure to retrieve the UUIDs
1747      * from the remote device. Instead, the local cached copy of the service
1748      * UUIDs are returned.
1749      * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired.
1750      *
1751      * @return the supported features (UUIDs) of the remote device, or null on error
1752      */
1753     @RequiresLegacyBluetoothPermission
1754     @RequiresBluetoothConnectPermission
1755     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getUuids()1756     public ParcelUuid[] getUuids() {
1757         final IBluetooth service = sService;
1758         if (service == null || !isBluetoothEnabled()) {
1759             Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
1760             return null;
1761         }
1762         try {
1763             return service.getRemoteUuids(this, mAttributionSource);
1764         } catch (RemoteException e) {
1765             Log.e(TAG, "", e);
1766         }
1767         return null;
1768     }
1769 
1770     /**
1771      * Perform a service discovery on the remote device to get the UUIDs supported.
1772      *
1773      * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
1774      * with the UUIDs supported by the remote end. If there is an error
1775      * in getting the SDP records or if the process takes a long time, or the device is bonding and
1776      * we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the UUIDs that is
1777      * currently present in the cache. Clients should use the {@link #getUuids} to get UUIDs
1778      * if service discovery is not to be performed. If there is an ongoing bonding process,
1779      * service discovery or device inquiry, the request will be queued.
1780      *
1781      * @return False if the check fails, True if the process of initiating an ACL connection
1782      * to the remote device was started or cached UUIDs will be broadcast.
1783      */
1784     @RequiresLegacyBluetoothPermission
1785     @RequiresBluetoothConnectPermission
1786     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
fetchUuidsWithSdp()1787     public boolean fetchUuidsWithSdp() {
1788         final IBluetooth service = sService;
1789         if (service == null || !isBluetoothEnabled()) {
1790             Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
1791             return false;
1792         }
1793         try {
1794             return service.fetchRemoteUuidsWithAttribution(this, mAttributionSource);
1795         } catch (RemoteException e) {
1796             Log.e(TAG, "", e);
1797         }
1798         return false;
1799     }
1800 
1801     /**
1802      * Perform a service discovery on the remote device to get the SDP records associated
1803      * with the specified UUID.
1804      *
1805      * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent,
1806      * with the SDP records found on the remote end. If there is an error
1807      * in getting the SDP records or if the process takes a long time,
1808      * {@link #ACTION_SDP_RECORD} intent is sent with an status value in
1809      * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
1810      * Detailed status error codes can be found by members of the Bluetooth package in
1811      * the AbstractionLayer class.
1812      * <p>The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
1813      * The object type will match one of the SdpXxxRecord types, depending on the UUID searched
1814      * for.
1815      *
1816      * @return False if the check fails, True if the process
1817      *               of initiating an ACL connection to the remote device
1818      *               was started.
1819      */
1820     /** @hide */
1821     @RequiresLegacyBluetoothPermission
1822     @RequiresBluetoothConnectPermission
1823     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
sdpSearch(ParcelUuid uuid)1824     public boolean sdpSearch(ParcelUuid uuid) {
1825         final IBluetooth service = sService;
1826         if (service == null) {
1827             Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
1828             return false;
1829         }
1830         try {
1831             return service.sdpSearch(this, uuid, mAttributionSource);
1832         } catch (RemoteException e) {
1833             Log.e(TAG, "", e);
1834         }
1835         return false;
1836     }
1837 
1838     /**
1839      * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
1840      *
1841      * @return true pin has been set false for error
1842      */
1843     @RequiresLegacyBluetoothAdminPermission
1844     @RequiresBluetoothConnectPermission
1845     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
setPin(byte[] pin)1846     public boolean setPin(byte[] pin) {
1847         final IBluetooth service = sService;
1848         if (service == null) {
1849             Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
1850             return false;
1851         }
1852         try {
1853             return service.setPin(this, true, pin.length, pin, mAttributionSource);
1854         } catch (RemoteException e) {
1855             Log.e(TAG, "", e);
1856         }
1857         return false;
1858     }
1859 
1860     /**
1861      * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
1862      *
1863      * @return true pin has been set false for error
1864      * @hide
1865      */
1866     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1867     @RequiresLegacyBluetoothAdminPermission
1868     @RequiresBluetoothConnectPermission
1869     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
setPin(@onNull String pin)1870     public boolean setPin(@NonNull String pin) {
1871         byte[] pinBytes = convertPinToBytes(pin);
1872         if (pinBytes == null) {
1873             return false;
1874         }
1875         return setPin(pinBytes);
1876     }
1877 
1878     /**
1879      * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
1880      *
1881      * @return true confirmation has been sent out false for error
1882      */
1883     @RequiresPermission(allOf = {
1884             android.Manifest.permission.BLUETOOTH_CONNECT,
1885             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
1886     })
setPairingConfirmation(boolean confirm)1887     public boolean setPairingConfirmation(boolean confirm) {
1888         final IBluetooth service = sService;
1889         if (service == null) {
1890             Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
1891             return false;
1892         }
1893         try {
1894             return service.setPairingConfirmation(this, confirm, mAttributionSource);
1895         } catch (RemoteException e) {
1896             Log.e(TAG, "", e);
1897         }
1898         return false;
1899     }
1900 
1901     /**
1902      * Cancels pairing to this device
1903      *
1904      * @return true if pairing cancelled successfully, false otherwise
1905      *
1906      * @hide
1907      */
1908     @UnsupportedAppUsage
1909     @RequiresLegacyBluetoothAdminPermission
1910     @RequiresBluetoothConnectPermission
1911     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
cancelPairing()1912     public boolean cancelPairing() {
1913         final IBluetooth service = sService;
1914         if (service == null) {
1915             Log.e(TAG, "BT not enabled. Cannot cancel pairing");
1916             return false;
1917         }
1918         try {
1919             return service.cancelBondProcess(this, mAttributionSource);
1920         } catch (RemoteException e) {
1921             Log.e(TAG, "", e);
1922         }
1923         return false;
1924     }
1925 
isBluetoothEnabled()1926     boolean isBluetoothEnabled() {
1927         boolean ret = false;
1928         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1929         if (adapter != null && adapter.isEnabled()) {
1930             ret = true;
1931         }
1932         return ret;
1933     }
1934 
1935     /**
1936      * Gets whether the phonebook access is allowed for this bluetooth device
1937      *
1938      * @return Whether the phonebook access is allowed to this device. Can be {@link
1939      * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
1940      * @hide
1941      */
1942     @UnsupportedAppUsage
1943     @RequiresLegacyBluetoothPermission
1944     @RequiresBluetoothConnectPermission
1945     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getPhonebookAccessPermission()1946     public @AccessPermission int getPhonebookAccessPermission() {
1947         final IBluetooth service = sService;
1948         if (service == null) {
1949             return ACCESS_UNKNOWN;
1950         }
1951         try {
1952             return service.getPhonebookAccessPermission(this, mAttributionSource);
1953         } catch (RemoteException e) {
1954             Log.e(TAG, "", e);
1955         }
1956         return ACCESS_UNKNOWN;
1957     }
1958 
1959     /**
1960      * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not
1961      * be routed to the {@link BluetoothDevice} if set to {@code true}.
1962      *
1963      * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice}
1964      * is an active device (for A2DP or HFP), the active device for that profile
1965      * will be set to null.
1966      * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP
1967      * active device is null, the {@link BluetoothDevice} will be set as the
1968      * active device for that profile.
1969      * If the {@link BluetoothDevice} is disconnected, it exits silence mode.
1970      * If the {@link BluetoothDevice} is set as the active device for A2DP or
1971      * HFP, while silence mode is enabled, then the device will exit silence mode.
1972      * If the {@link BluetoothDevice} is in silence mode, AVRCP position change
1973      * event and HFP AG indicators will be disabled.
1974      * If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot
1975      * enter silence mode.
1976      *
1977      * @param silence true to enter silence mode, false to exit
1978      * @return true on success, false on error.
1979      * @throws IllegalStateException if Bluetooth is not turned ON.
1980      * @hide
1981      */
1982     @SystemApi
1983     @RequiresPermission(allOf = {
1984             android.Manifest.permission.BLUETOOTH_CONNECT,
1985             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
1986     })
setSilenceMode(boolean silence)1987     public boolean setSilenceMode(boolean silence) {
1988         final IBluetooth service = sService;
1989         if (service == null) {
1990             throw new IllegalStateException("Bluetooth is not turned ON");
1991         }
1992         try {
1993             return service.setSilenceMode(this, silence, mAttributionSource);
1994         } catch (RemoteException e) {
1995             Log.e(TAG, "setSilenceMode fail", e);
1996             return false;
1997         }
1998     }
1999 
2000     /**
2001      * Check whether the {@link BluetoothDevice} is in silence mode
2002      *
2003      * @return true on device in silence mode, otherwise false.
2004      * @throws IllegalStateException if Bluetooth is not turned ON.
2005      * @hide
2006      */
2007     @SystemApi
2008     @RequiresPermission(allOf = {
2009             android.Manifest.permission.BLUETOOTH_CONNECT,
2010             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
2011     })
isInSilenceMode()2012     public boolean isInSilenceMode() {
2013         final IBluetooth service = sService;
2014         if (service == null) {
2015             throw new IllegalStateException("Bluetooth is not turned ON");
2016         }
2017         try {
2018             return service.getSilenceMode(this, mAttributionSource);
2019         } catch (RemoteException e) {
2020             Log.e(TAG, "isInSilenceMode fail", e);
2021             return false;
2022         }
2023     }
2024 
2025     /**
2026      * Sets whether the phonebook access is allowed to this device.
2027      *
2028      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
2029      * #ACCESS_REJECTED}.
2030      * @return Whether the value has been successfully set.
2031      * @hide
2032      */
2033     @SystemApi
2034     @RequiresPermission(allOf = {
2035             android.Manifest.permission.BLUETOOTH_CONNECT,
2036             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
2037     })
setPhonebookAccessPermission(@ccessPermission int value)2038     public boolean setPhonebookAccessPermission(@AccessPermission int value) {
2039         final IBluetooth service = sService;
2040         if (service == null) {
2041             return false;
2042         }
2043         try {
2044             return service.setPhonebookAccessPermission(this, value, mAttributionSource);
2045         } catch (RemoteException e) {
2046             Log.e(TAG, "", e);
2047         }
2048         return false;
2049     }
2050 
2051     /**
2052      * Gets whether message access is allowed to this bluetooth device
2053      *
2054      * @return Whether the message access is allowed to this device.
2055      * @hide
2056      */
2057     @UnsupportedAppUsage
2058     @RequiresLegacyBluetoothPermission
2059     @RequiresBluetoothConnectPermission
2060     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getMessageAccessPermission()2061     public @AccessPermission int getMessageAccessPermission() {
2062         final IBluetooth service = sService;
2063         if (service == null) {
2064             return ACCESS_UNKNOWN;
2065         }
2066         try {
2067             return service.getMessageAccessPermission(this, mAttributionSource);
2068         } catch (RemoteException e) {
2069             Log.e(TAG, "", e);
2070         }
2071         return ACCESS_UNKNOWN;
2072     }
2073 
2074     /**
2075      * Sets whether the message access is allowed to this device.
2076      *
2077      * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded,
2078      * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if
2079      * the permission is not being granted.
2080      * @return Whether the value has been successfully set.
2081      * @hide
2082      */
2083     @SystemApi
2084     @RequiresPermission(allOf = {
2085             android.Manifest.permission.BLUETOOTH_CONNECT,
2086             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
2087     })
setMessageAccessPermission(@ccessPermission int value)2088     public boolean setMessageAccessPermission(@AccessPermission int value) {
2089         // Validates param value is one of the accepted constants
2090         if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) {
2091             throw new IllegalArgumentException(value + "is not a valid AccessPermission value");
2092         }
2093         final IBluetooth service = sService;
2094         if (service == null) {
2095             return false;
2096         }
2097         try {
2098             return service.setMessageAccessPermission(this, value, mAttributionSource);
2099         } catch (RemoteException e) {
2100             Log.e(TAG, "", e);
2101         }
2102         return false;
2103     }
2104 
2105     /**
2106      * Gets whether sim access is allowed for this bluetooth device
2107      *
2108      * @return Whether the Sim access is allowed to this device.
2109      * @hide
2110      */
2111     @SystemApi
2112     @RequiresLegacyBluetoothPermission
2113     @RequiresBluetoothConnectPermission
2114     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getSimAccessPermission()2115     public @AccessPermission int getSimAccessPermission() {
2116         final IBluetooth service = sService;
2117         if (service == null) {
2118             return ACCESS_UNKNOWN;
2119         }
2120         try {
2121             return service.getSimAccessPermission(this, mAttributionSource);
2122         } catch (RemoteException e) {
2123             Log.e(TAG, "", e);
2124         }
2125         return ACCESS_UNKNOWN;
2126     }
2127 
2128     /**
2129      * Sets whether the Sim access is allowed to this device.
2130      *
2131      * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded,
2132      * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if
2133      * the permission is not being granted.
2134      * @return Whether the value has been successfully set.
2135      * @hide
2136      */
2137     @SystemApi
2138     @RequiresPermission(allOf = {
2139             android.Manifest.permission.BLUETOOTH_CONNECT,
2140             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
2141     })
setSimAccessPermission(int value)2142     public boolean setSimAccessPermission(int value) {
2143         final IBluetooth service = sService;
2144         if (service == null) {
2145             return false;
2146         }
2147         try {
2148             return service.setSimAccessPermission(this, value, mAttributionSource);
2149         } catch (RemoteException e) {
2150             Log.e(TAG, "", e);
2151         }
2152         return false;
2153     }
2154 
2155     /**
2156      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
2157      * outgoing connection to this remote device on given channel.
2158      * <p>The remote device will be authenticated and communication on this
2159      * socket will be encrypted.
2160      * <p> Use this socket only if an authenticated socket link is possible.
2161      * Authentication refers to the authentication of the link key to
2162      * prevent person-in-the-middle type of attacks.
2163      * For example, for Bluetooth 2.1 devices, if any of the devices does not
2164      * have an input and output capability or just has the ability to
2165      * display a numeric key, a secure socket connection is not possible.
2166      * In such a case, use {@link createInsecureRfcommSocket}.
2167      * For more details, refer to the Security Model section 5.2 (vol 3) of
2168      * Bluetooth Core Specification version 2.1 + EDR.
2169      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
2170      * connection.
2171      * <p>Valid RFCOMM channels are in range 1 to 30.
2172      *
2173      * @param channel RFCOMM channel to connect to
2174      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
2175      * @throws IOException on error, for example Bluetooth not available, or insufficient
2176      * permissions
2177      * @hide
2178      */
2179     @UnsupportedAppUsage
2180     @RequiresLegacyBluetoothPermission
2181     @RequiresBluetoothConnectPermission
2182     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
2183     @SuppressLint("AndroidFrameworkRequiresPermission")
createRfcommSocket(int channel)2184     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
2185         if (!isBluetoothEnabled()) {
2186             Log.e(TAG, "Bluetooth is not enabled");
2187             throw new IOException();
2188         }
2189         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
2190                 null);
2191     }
2192 
2193     /**
2194      * Create an L2cap {@link BluetoothSocket} ready to start a secure
2195      * outgoing connection to this remote device on given channel.
2196      * <p>The remote device will be authenticated and communication on this
2197      * socket will be encrypted.
2198      * <p> Use this socket only if an authenticated socket link is possible.
2199      * Authentication refers to the authentication of the link key to
2200      * prevent person-in-the-middle type of attacks.
2201      * For example, for Bluetooth 2.1 devices, if any of the devices does not
2202      * have an input and output capability or just has the ability to
2203      * display a numeric key, a secure socket connection is not possible.
2204      * In such a case, use {@link createInsecureRfcommSocket}.
2205      * For more details, refer to the Security Model section 5.2 (vol 3) of
2206      * Bluetooth Core Specification version 2.1 + EDR.
2207      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
2208      * connection.
2209      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
2210      *
2211      * @param channel L2cap PSM/channel to connect to
2212      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
2213      * @throws IOException on error, for example Bluetooth not available, or insufficient
2214      * permissions
2215      * @hide
2216      */
2217     @RequiresLegacyBluetoothPermission
2218     @RequiresBluetoothConnectPermission
2219     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
2220     @SuppressLint("AndroidFrameworkRequiresPermission")
createL2capSocket(int channel)2221     public BluetoothSocket createL2capSocket(int channel) throws IOException {
2222         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
2223                 null);
2224     }
2225 
2226     /**
2227      * Create an L2cap {@link BluetoothSocket} ready to start an insecure
2228      * outgoing connection to this remote device on given channel.
2229      * <p>The remote device will be not authenticated and communication on this
2230      * socket will not be encrypted.
2231      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
2232      * connection.
2233      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
2234      *
2235      * @param channel L2cap PSM/channel to connect to
2236      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
2237      * @throws IOException on error, for example Bluetooth not available, or insufficient
2238      * permissions
2239      * @hide
2240      */
2241     @RequiresLegacyBluetoothPermission
2242     @RequiresBluetoothConnectPermission
2243     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
2244     @SuppressLint("AndroidFrameworkRequiresPermission")
createInsecureL2capSocket(int channel)2245     public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException {
2246         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel,
2247                 null);
2248     }
2249 
2250     /**
2251      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
2252      * outgoing connection to this remote device using SDP lookup of uuid.
2253      * <p>This is designed to be used with {@link
2254      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
2255      * Bluetooth applications.
2256      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
2257      * connection. This will also perform an SDP lookup of the given uuid to
2258      * determine which channel to connect to.
2259      * <p>The remote device will be authenticated and communication on this
2260      * socket will be encrypted.
2261      * <p> Use this socket only if an authenticated socket link is possible.
2262      * Authentication refers to the authentication of the link key to
2263      * prevent person-in-the-middle type of attacks.
2264      * For example, for Bluetooth 2.1 devices, if any of the devices does not
2265      * have an input and output capability or just has the ability to
2266      * display a numeric key, a secure socket connection is not possible.
2267      * In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}.
2268      * For more details, refer to the Security Model section 5.2 (vol 3) of
2269      * Bluetooth Core Specification version 2.1 + EDR.
2270      * <p>Hint: If you are connecting to a Bluetooth serial board then try
2271      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
2272      * However if you are connecting to an Android peer then please generate
2273      * your own unique UUID.
2274      *
2275      * @param uuid service record uuid to lookup RFCOMM channel
2276      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
2277      * @throws IOException on error, for example Bluetooth not available, or insufficient
2278      * permissions
2279      */
2280     @RequiresLegacyBluetoothPermission
2281     @RequiresBluetoothConnectPermission
2282     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
2283     @SuppressLint("AndroidFrameworkRequiresPermission")
createRfcommSocketToServiceRecord(UUID uuid)2284     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
2285         if (!isBluetoothEnabled()) {
2286             Log.e(TAG, "Bluetooth is not enabled");
2287             throw new IOException();
2288         }
2289 
2290         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
2291                 new ParcelUuid(uuid));
2292     }
2293 
2294     /**
2295      * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
2296      * outgoing connection to this remote device using SDP lookup of uuid.
2297      * <p> The communication channel will not have an authenticated link key
2298      * i.e it will be subject to person-in-the-middle attacks. For Bluetooth 2.1
2299      * devices, the link key will be encrypted, as encryption is mandatory.
2300      * For legacy devices (pre Bluetooth 2.1 devices) the link key will
2301      * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
2302      * encrypted and authenticated communication channel is desired.
2303      * <p>This is designed to be used with {@link
2304      * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
2305      * Bluetooth applications.
2306      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
2307      * connection. This will also perform an SDP lookup of the given uuid to
2308      * determine which channel to connect to.
2309      * <p>The remote device will be authenticated and communication on this
2310      * socket will be encrypted.
2311      * <p>Hint: If you are connecting to a Bluetooth serial board then try
2312      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
2313      * However if you are connecting to an Android peer then please generate
2314      * your own unique UUID.
2315      *
2316      * @param uuid service record uuid to lookup RFCOMM channel
2317      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
2318      * @throws IOException on error, for example Bluetooth not available, or insufficient
2319      * permissions
2320      */
2321     @RequiresLegacyBluetoothPermission
2322     @RequiresBluetoothConnectPermission
2323     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
2324     @SuppressLint("AndroidFrameworkRequiresPermission")
createInsecureRfcommSocketToServiceRecord(UUID uuid)2325     public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
2326         if (!isBluetoothEnabled()) {
2327             Log.e(TAG, "Bluetooth is not enabled");
2328             throw new IOException();
2329         }
2330         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
2331                 new ParcelUuid(uuid));
2332     }
2333 
2334     /**
2335      * Construct an insecure RFCOMM socket ready to start an outgoing
2336      * connection.
2337      * Call #connect on the returned #BluetoothSocket to begin the connection.
2338      * The remote device will not be authenticated and communication on this
2339      * socket will not be encrypted.
2340      *
2341      * @param port remote port
2342      * @return An RFCOMM BluetoothSocket
2343      * @throws IOException On error, for example Bluetooth not available, or insufficient
2344      * permissions.
2345      * @hide
2346      */
2347     @UnsupportedAppUsage(publicAlternatives = "Use "
2348             + "{@link #createInsecureRfcommSocketToServiceRecord} instead.")
2349     @RequiresLegacyBluetoothAdminPermission
2350     @RequiresBluetoothConnectPermission
2351     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
2352     @SuppressLint("AndroidFrameworkRequiresPermission")
createInsecureRfcommSocket(int port)2353     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
2354         if (!isBluetoothEnabled()) {
2355             Log.e(TAG, "Bluetooth is not enabled");
2356             throw new IOException();
2357         }
2358         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
2359                 null);
2360     }
2361 
2362     /**
2363      * Construct a SCO socket ready to start an outgoing connection.
2364      * Call #connect on the returned #BluetoothSocket to begin the connection.
2365      *
2366      * @return a SCO BluetoothSocket
2367      * @throws IOException on error, for example Bluetooth not available, or insufficient
2368      * permissions.
2369      * @hide
2370      */
2371     @UnsupportedAppUsage
2372     @RequiresLegacyBluetoothAdminPermission
2373     @RequiresBluetoothConnectPermission
2374     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
2375     @SuppressLint("AndroidFrameworkRequiresPermission")
createScoSocket()2376     public BluetoothSocket createScoSocket() throws IOException {
2377         if (!isBluetoothEnabled()) {
2378             Log.e(TAG, "Bluetooth is not enabled");
2379             throw new IOException();
2380         }
2381         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
2382     }
2383 
2384     /**
2385      * Check that a pin is valid and convert to byte array.
2386      *
2387      * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
2388      *
2389      * @param pin pin as java String
2390      * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin.
2391      * @hide
2392      */
2393     @UnsupportedAppUsage
convertPinToBytes(String pin)2394     public static byte[] convertPinToBytes(String pin) {
2395         if (pin == null) {
2396             return null;
2397         }
2398         byte[] pinBytes;
2399         try {
2400             pinBytes = pin.getBytes("UTF-8");
2401         } catch (UnsupportedEncodingException uee) {
2402             Log.e(TAG, "UTF-8 not supported?!?");  // this should not happen
2403             return null;
2404         }
2405         if (pinBytes.length <= 0 || pinBytes.length > 16) {
2406             return null;
2407         }
2408         return pinBytes;
2409     }
2410 
2411     /**
2412      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2413      * The callback is used to deliver results to Caller, such as connection status as well
2414      * as any further GATT client operations.
2415      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2416      * GATT client operations.
2417      *
2418      * @param callback GATT callback handler that will receive asynchronous callbacks.
2419      * @param autoConnect Whether to directly connect to the remote device (false) or to
2420      * automatically connect as soon as the remote device becomes available (true).
2421      * @throws IllegalArgumentException if callback is null
2422      */
2423     @RequiresBluetoothConnectPermission
2424     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)2425     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2426             BluetoothGattCallback callback) {
2427         return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO));
2428     }
2429 
2430     /**
2431      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2432      * The callback is used to deliver results to Caller, such as connection status as well
2433      * as any further GATT client operations.
2434      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2435      * GATT client operations.
2436      *
2437      * @param callback GATT callback handler that will receive asynchronous callbacks.
2438      * @param autoConnect Whether to directly connect to the remote device (false) or to
2439      * automatically connect as soon as the remote device becomes available (true).
2440      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2441      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2442      * BluetoothDevice#TRANSPORT_LE}
2443      * @throws IllegalArgumentException if callback is null
2444      */
2445     @RequiresBluetoothConnectPermission
2446     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)2447     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2448             BluetoothGattCallback callback, int transport) {
2449         return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK));
2450     }
2451 
2452     /**
2453      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2454      * The callback is used to deliver results to Caller, such as connection status as well
2455      * as any further GATT client operations.
2456      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2457      * GATT client operations.
2458      *
2459      * @param callback GATT callback handler that will receive asynchronous callbacks.
2460      * @param autoConnect Whether to directly connect to the remote device (false) or to
2461      * automatically connect as soon as the remote device becomes available (true).
2462      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2463      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2464      * BluetoothDevice#TRANSPORT_LE}
2465      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
2466      * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link
2467      * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
2468      * is set to true.
2469      * @throws NullPointerException if callback is null
2470      */
2471     @RequiresBluetoothConnectPermission
2472     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy)2473     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2474             BluetoothGattCallback callback, int transport, int phy) {
2475         return connectGatt(context, autoConnect, callback, transport, phy, null);
2476     }
2477 
2478     /**
2479      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2480      * The callback is used to deliver results to Caller, such as connection status as well
2481      * as any further GATT client operations.
2482      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2483      * GATT client operations.
2484      *
2485      * @param callback GATT callback handler that will receive asynchronous callbacks.
2486      * @param autoConnect Whether to directly connect to the remote device (false) or to
2487      * automatically connect as soon as the remote device becomes available (true).
2488      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2489      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2490      * BluetoothDevice#TRANSPORT_LE}
2491      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
2492      * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
2493      * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
2494      * is set to true.
2495      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
2496      * an un-specified background thread.
2497      * @throws NullPointerException if callback is null
2498      */
2499     @RequiresBluetoothConnectPermission
2500     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler)2501     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2502             BluetoothGattCallback callback, int transport, int phy,
2503             Handler handler) {
2504         return connectGatt(context, autoConnect, callback, transport, false, phy, handler);
2505     }
2506 
2507     /**
2508      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2509      * The callback is used to deliver results to Caller, such as connection status as well
2510      * as any further GATT client operations.
2511      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2512      * GATT client operations.
2513      *
2514      * @param callback GATT callback handler that will receive asynchronous callbacks.
2515      * @param autoConnect Whether to directly connect to the remote device (false) or to
2516      * automatically connect as soon as the remote device becomes available (true).
2517      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2518      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2519      * BluetoothDevice#TRANSPORT_LE}
2520      * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client
2521      * does not hold a GATT connection. It automatically disconnects when no other GATT connections
2522      * are active for the remote device.
2523      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
2524      * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
2525      * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
2526      * is set to true.
2527      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
2528      * an un-specified background thread.
2529      * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client
2530      * operations.
2531      * @hide
2532      */
2533     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2534     @RequiresBluetoothConnectPermission
2535     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, boolean opportunistic, int phy, Handler handler)2536     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2537             BluetoothGattCallback callback, int transport,
2538             boolean opportunistic, int phy, Handler handler) {
2539         if (callback == null) {
2540             throw new NullPointerException("callback is null");
2541         }
2542 
2543         // TODO(Bluetooth) check whether platform support BLE
2544         //     Do the check here or in GattServer?
2545         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2546         IBluetoothManager managerService = adapter.getBluetoothManager();
2547         try {
2548             IBluetoothGatt iGatt = managerService.getBluetoothGatt();
2549             if (iGatt == null) {
2550                 // BLE is not supported
2551                 return null;
2552             }
2553             BluetoothGatt gatt = new BluetoothGatt(
2554                     iGatt, this, transport, opportunistic, phy, mAttributionSource);
2555             gatt.connect(autoConnect, callback, handler);
2556             return gatt;
2557         } catch (RemoteException e) {
2558             Log.e(TAG, "", e);
2559         }
2560         return null;
2561     }
2562 
2563     /**
2564      * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
2565      * be used to start a secure outgoing connection to the remote device with the same dynamic
2566      * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
2567      * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for
2568      * peer-peer Bluetooth applications.
2569      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
2570      * <p>Application using this API is responsible for obtaining PSM value from remote device.
2571      * <p>The remote device will be authenticated and communication on this socket will be
2572      * encrypted.
2573      * <p> Use this socket if an authenticated socket link is possible. Authentication refers
2574      * to the authentication of the link key to prevent person-in-the-middle type of attacks.
2575      *
2576      * @param psm dynamic PSM value from remote device
2577      * @return a CoC #BluetoothSocket ready for an outgoing connection
2578      * @throws IOException on error, for example Bluetooth not available, or insufficient
2579      * permissions
2580      */
2581     @RequiresLegacyBluetoothPermission
2582     @RequiresBluetoothConnectPermission
2583     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
2584     @SuppressLint("AndroidFrameworkRequiresPermission")
createL2capChannel(int psm)2585     public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException {
2586         if (!isBluetoothEnabled()) {
2587             Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
2588             throw new IOException();
2589         }
2590         if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm);
2591         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm,
2592                 null);
2593     }
2594 
2595     /**
2596      * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
2597      * be used to start a secure outgoing connection to the remote device with the same dynamic
2598      * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
2599      * <p>This is designed to be used with {@link
2600      * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications.
2601      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
2602      * <p>Application using this API is responsible for obtaining PSM value from remote device.
2603      * <p> The communication channel may not have an authenticated link key, i.e. it may be subject
2604      * to person-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and
2605      * authenticated communication channel is possible.
2606      *
2607      * @param psm dynamic PSM value from remote device
2608      * @return a CoC #BluetoothSocket ready for an outgoing connection
2609      * @throws IOException on error, for example Bluetooth not available, or insufficient
2610      * permissions
2611      */
2612     @RequiresLegacyBluetoothPermission
2613     @RequiresBluetoothConnectPermission
2614     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
2615     @SuppressLint("AndroidFrameworkRequiresPermission")
createInsecureL2capChannel(int psm)2616     public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
2617         if (!isBluetoothEnabled()) {
2618             Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
2619             throw new IOException();
2620         }
2621         if (DBG) {
2622             Log.d(TAG, "createInsecureL2capChannel: psm=" + psm);
2623         }
2624         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm,
2625                 null);
2626     }
2627 
2628     /**
2629      * Set a keyed metadata of this {@link BluetoothDevice} to a
2630      * {@link String} value.
2631      * Only bonded devices's metadata will be persisted across Bluetooth
2632      * restart.
2633      * Metadata will be removed when the device's bond state is moved to
2634      * {@link #BOND_NONE}.
2635      *
2636      * @param key must be within the list of BluetoothDevice.METADATA_*
2637      * @param value a byte array data to set for key. Must be less than
2638      * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length
2639      * @return true on success, false on error
2640      * @hide
2641     */
2642     @SystemApi
2643     @RequiresPermission(allOf = {
2644             android.Manifest.permission.BLUETOOTH_CONNECT,
2645             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
2646     })
setMetadata(@etadataKey int key, @NonNull byte[] value)2647     public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) {
2648         final IBluetooth service = sService;
2649         if (service == null) {
2650             Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
2651             return false;
2652         }
2653         if (value.length > METADATA_MAX_LENGTH) {
2654             throw new IllegalArgumentException("value length is " + value.length
2655                     + ", should not over " + METADATA_MAX_LENGTH);
2656         }
2657         try {
2658             return service.setMetadata(this, key, value, mAttributionSource);
2659         } catch (RemoteException e) {
2660             Log.e(TAG, "setMetadata fail", e);
2661             return false;
2662         }
2663     }
2664 
2665     /**
2666      * Get a keyed metadata for this {@link BluetoothDevice} as {@link String}
2667      *
2668      * @param key must be within the list of BluetoothDevice.METADATA_*
2669      * @return Metadata of the key as byte array, null on error or not found
2670      * @hide
2671      */
2672     @SystemApi
2673     @Nullable
2674     @RequiresPermission(allOf = {
2675             android.Manifest.permission.BLUETOOTH_CONNECT,
2676             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
2677     })
getMetadata(@etadataKey int key)2678     public byte[] getMetadata(@MetadataKey int key) {
2679         final IBluetooth service = sService;
2680         if (service == null) {
2681             Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
2682             return null;
2683         }
2684         try {
2685             return service.getMetadata(this, key, mAttributionSource);
2686         } catch (RemoteException e) {
2687             Log.e(TAG, "getMetadata fail", e);
2688             return null;
2689         }
2690     }
2691 
2692     /**
2693      * Get the maxinum metadata key ID.
2694      *
2695      * @return the last supported metadata key
2696      * @hide
2697      */
getMaxMetadataKey()2698     public static @MetadataKey int getMaxMetadataKey() {
2699         return METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD;
2700     }
2701 }
2702