• 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 static android.Manifest.permission.BLUETOOTH_CONNECT;
20 import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
21 import static android.Manifest.permission.BLUETOOTH_SCAN;
22 import static android.Manifest.permission.MODIFY_PHONE_STATE;
23 
24 import android.annotation.BroadcastBehavior;
25 import android.annotation.FlaggedApi;
26 import android.annotation.IntDef;
27 import android.annotation.IntRange;
28 import android.annotation.NonNull;
29 import android.annotation.Nullable;
30 import android.annotation.RequiresPermission;
31 import android.annotation.SdkConstant;
32 import android.annotation.SdkConstant.SdkConstantType;
33 import android.annotation.SuppressLint;
34 import android.annotation.SystemApi;
35 import android.app.compat.CompatChanges;
36 import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
37 import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
38 import android.bluetooth.annotations.RequiresBluetoothScanPermission;
39 import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
40 import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
41 import android.companion.AssociationRequest;
42 import android.compat.annotation.ChangeId;
43 import android.compat.annotation.EnabledSince;
44 import android.compat.annotation.UnsupportedAppUsage;
45 import android.content.AttributionSource;
46 import android.content.Context;
47 import android.os.Build;
48 import android.os.Handler;
49 import android.os.IpcDataCache;
50 import android.os.Parcel;
51 import android.os.ParcelUuid;
52 import android.os.Parcelable;
53 import android.os.Process;
54 import android.os.RemoteException;
55 import android.util.Log;
56 import android.util.Pair;
57 
58 import com.android.bluetooth.flags.Flags;
59 
60 import java.io.IOException;
61 import java.lang.annotation.Retention;
62 import java.lang.annotation.RetentionPolicy;
63 import java.nio.charset.StandardCharsets;
64 import java.util.List;
65 import java.util.UUID;
66 
67 /**
68  * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you create a connection with
69  * the respective device or query information about it, such as the name, address, class, and
70  * bonding state.
71  *
72  * <p>This class is really just a thin wrapper for a Bluetooth hardware address. Objects of this
73  * class are immutable. Operations on this class are performed on the remote Bluetooth hardware
74  * address, using the {@link BluetoothAdapter} that was used to create this {@link BluetoothDevice}.
75  *
76  * <p>To get a {@link BluetoothDevice}, use {@link BluetoothAdapter#getRemoteDevice(String)
77  * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device of a known MAC
78  * address (which you can get through device discovery with {@link BluetoothAdapter}) or get one
79  * from the set of bonded devices returned by {@link BluetoothAdapter#getBondedDevices()
80  * BluetoothAdapter.getBondedDevices()}. You can then open a {@link BluetoothSocket} for
81  * communication with the remote device, using {@link #createRfcommSocketToServiceRecord(UUID)} over
82  * Bluetooth BR/EDR or using {@link #createL2capChannel(int)} over Bluetooth LE.
83  *
84  * <p><div class="special reference">
85  *
86  * <h3>Developer Guides</h3>
87  *
88  * <p>For more information about using Bluetooth, read the <a href=
89  * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide. </div>
90  *
91  * @see BluetoothAdapter
92  * @see BluetoothSocket
93  */
94 public final class BluetoothDevice implements Parcelable, Attributable {
95     private static final String TAG = BluetoothDevice.class.getSimpleName();
96 
97     private static final boolean DBG = false;
98 
99     /**
100      * Connection state bitmask disconnected bit as returned by getConnectionState.
101      *
102      * @hide
103      */
104     public static final int CONNECTION_STATE_DISCONNECTED = 0;
105 
106     /**
107      * Connection state bitmask connected bit as returned by getConnectionState.
108      *
109      * @hide
110      */
111     public static final int CONNECTION_STATE_CONNECTED = 1;
112 
113     /**
114      * Connection state bitmask encrypted BREDR bit as returned by getConnectionState.
115      *
116      * @hide
117      */
118     public static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2;
119 
120     /**
121      * Connection state bitmask encrypted LE bit as returned by getConnectionState.
122      *
123      * @hide
124      */
125     public static final int CONNECTION_STATE_ENCRYPTED_LE = 4;
126 
127     /**
128      * Sentinel error value for this class. Guaranteed to not equal any other integer constant in
129      * this class. Provided as a convenience for functions that require a sentinel error value, for
130      * example:
131      *
132      * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
133      * BluetoothDevice.ERROR)</code>
134      */
135     public static final int ERROR = Integer.MIN_VALUE;
136 
137     /**
138      * Broadcast Action: Remote device discovered.
139      *
140      * <p>Sent when a remote device is found during discovery.
141      *
142      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_CLASS}. Can
143      * contain the extra fields {@link #EXTRA_NAME} and/or {@link #EXTRA_RSSI} and/or {@link
144      * #EXTRA_IS_COORDINATED_SET_MEMBER} if they are available.
145      */
146     // TODO: Change API to not broadcast RSSI if not available (incoming connection)
147     @RequiresLegacyBluetoothPermission
148     @RequiresBluetoothScanPermission
149     @RequiresBluetoothLocationPermission
150     @RequiresPermission(BLUETOOTH_SCAN)
151     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
152     public static final String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
153 
154     /**
155      * Broadcast Action: Bluetooth class of a remote device has changed.
156      *
157      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_CLASS}.
158      *
159      * @see BluetoothClass
160      */
161     @RequiresLegacyBluetoothPermission
162     @RequiresBluetoothConnectPermission
163     @RequiresPermission(BLUETOOTH_CONNECT)
164     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
165     public static final String ACTION_CLASS_CHANGED =
166             "android.bluetooth.device.action.CLASS_CHANGED";
167 
168     /**
169      * Broadcast Action: Indicates a low level (ACL) connection has been established with a remote
170      * device.
171      *
172      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_TRANSPORT}.
173      *
174      * <p>ACL connections are managed automatically by the Android Bluetooth stack.
175      */
176     @RequiresLegacyBluetoothPermission
177     @RequiresBluetoothConnectPermission
178     @RequiresPermission(BLUETOOTH_CONNECT)
179     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
180     public static final String ACTION_ACL_CONNECTED =
181             "android.bluetooth.device.action.ACL_CONNECTED";
182 
183     /**
184      * Broadcast Action: Indicates that a low level (ACL) disconnection has been requested for a
185      * remote device, and it will soon be disconnected.
186      *
187      * <p>This is useful for graceful disconnection. Applications should use this intent as a hint
188      * to immediately terminate higher level connections (RFCOMM, L2CAP, or profile connections) to
189      * the remote device.
190      *
191      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
192      */
193     @RequiresLegacyBluetoothPermission
194     @RequiresBluetoothConnectPermission
195     @RequiresPermission(BLUETOOTH_CONNECT)
196     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
197     public static final String ACTION_ACL_DISCONNECT_REQUESTED =
198             "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
199 
200     /**
201      * Broadcast Action: Indicates a low level (ACL) disconnection from a remote device.
202      *
203      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_TRANSPORT}.
204      *
205      * <p>ACL connections are managed automatically by the Android Bluetooth stack.
206      */
207     @RequiresLegacyBluetoothPermission
208     @RequiresBluetoothConnectPermission
209     @RequiresPermission(BLUETOOTH_CONNECT)
210     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
211     public static final String ACTION_ACL_DISCONNECTED =
212             "android.bluetooth.device.action.ACL_DISCONNECTED";
213 
214     /**
215      * Broadcast Action: Indicates the friendly name of a remote device has been retrieved for the
216      * first time, or changed since the last retrieval.
217      *
218      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_NAME}.
219      */
220     @RequiresLegacyBluetoothPermission
221     @RequiresBluetoothConnectPermission
222     @RequiresPermission(BLUETOOTH_CONNECT)
223     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
224     public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED";
225 
226     /**
227      * Broadcast Action: Indicates the alias of a remote device has been changed.
228      *
229      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
230      */
231     @SuppressLint("ActionValue")
232     @RequiresLegacyBluetoothPermission
233     @RequiresBluetoothConnectPermission
234     @RequiresPermission(BLUETOOTH_CONNECT)
235     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
236     public static final String ACTION_ALIAS_CHANGED =
237             "android.bluetooth.device.action.ALIAS_CHANGED";
238 
239     /**
240      * Broadcast Action: Indicates a change in the bond state of a remote device. For example, if a
241      * device is bonded (paired).
242      *
243      * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link #EXTRA_BOND_STATE} and
244      * {@link #EXTRA_PREVIOUS_BOND_STATE}.
245      */
246     // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
247     // contain a hidden extra field EXTRA_UNBOND_REASON with the result code.
248     @RequiresLegacyBluetoothPermission
249     @RequiresBluetoothConnectPermission
250     @RequiresPermission(BLUETOOTH_CONNECT)
251     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
252     public static final String ACTION_BOND_STATE_CHANGED =
253             "android.bluetooth.device.action.BOND_STATE_CHANGED";
254 
255     /**
256      * Broadcast Action: Indicates the battery level of a remote device has been retrieved for the
257      * first time, or changed since the last retrieval
258      *
259      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link #EXTRA_BATTERY_LEVEL}.
260      *
261      * @hide
262      */
263     @SystemApi
264     @RequiresLegacyBluetoothPermission
265     @RequiresBluetoothConnectPermission
266     @RequiresPermission(BLUETOOTH_CONNECT)
267     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
268     @SuppressLint("ActionValue")
269     public static final String ACTION_BATTERY_LEVEL_CHANGED =
270             "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED";
271 
272     /**
273      * Broadcast Action: Indicates the audio buffer size should be switched between a low latency
274      * buffer size and a higher and larger latency buffer size. Only registered receivers will
275      * receive this intent.
276      *
277      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
278      * #EXTRA_LOW_LATENCY_BUFFER_SIZE}.
279      *
280      * @hide
281      */
282     @SuppressLint("ActionValue")
283     @RequiresBluetoothConnectPermission
284     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
285     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
286     @SystemApi
287     public static final String ACTION_SWITCH_BUFFER_SIZE =
288             "android.bluetooth.device.action.SWITCH_BUFFER_SIZE";
289 
290     /**
291      * Broadcast Action: Indicates that previously bonded device couldn't provide keys to establish
292      * encryption. This can have numerous reasons, i.e.:
293      *
294      * <ul>
295      *   <li>remote was factory reset, or removed bond
296      *   <li>spoofing attack, someone is impersonating remote device
297      *   <li>in case of LE devices, very unlikely address collision
298      * </ul>
299      *
300      * <p>Always contains the extra field {@link #EXTRA_DEVICE}
301      *
302      * <p>This method requires the calling app to have the {@link
303      * android.Manifest.permission#BLUETOOTH_CONNECT} permission. Before {@link
304      * android.os.Build.VERSION_CODES#BAKLAVA} this method also required {@link
305      * android.Manifest.permission#BLUETOOTH_PRIVILEGED}
306      */
307     @SuppressLint("ActionValue")
308     @RequiresPermission(
309             allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
310             conditional = true)
311     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
312     @BroadcastBehavior(protectedBroadcast = true)
313     @FlaggedApi(Flags.FLAG_KEY_MISSING_PUBLIC)
314     public static final String ACTION_KEY_MISSING = "android.bluetooth.device.action.KEY_MISSING";
315 
316     /**
317      * Broadcast Action: Indicates that encryption state changed
318      *
319      * <p>Always contains the extra field {@link #EXTRA_DEVICE}
320      *
321      * <p>Always contains the extra field {@link #EXTRA_TRANSPORT}
322      *
323      * <p>Always contains the extra field {@link #EXTRA_ENCRYPTION_STATUS}
324      *
325      * <p>Always contains the extra field {@link #EXTRA_ENCRYPTION_ENABLED}
326      *
327      * <p>Always contains the extra field {@link #EXTRA_KEY_SIZE}
328      *
329      * <p>Always contains the extra field {@link #EXTRA_ENCRYPTION_ALGORITHM}
330      */
331     @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST)
332     @SuppressLint("ActionValue")
333     @RequiresPermission(BLUETOOTH_CONNECT)
334     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
335     @BroadcastBehavior(protectedBroadcast = true)
336     public static final String ACTION_ENCRYPTION_CHANGE =
337             "android.bluetooth.device.action.ENCRYPTION_CHANGE";
338 
339     /**
340      * Used as an Integer extra field in {@link #ACTION_BATTERY_LEVEL_CHANGED} intent. It contains
341      * the most recently retrieved battery level information ranging from 0% to 100% for a remote
342      * device, {@link #BATTERY_LEVEL_UNKNOWN} when the valid is unknown or there is an error, {@link
343      * #BATTERY_LEVEL_BLUETOOTH_OFF} when the bluetooth is off
344      *
345      * @hide
346      */
347     @SuppressLint("ActionValue")
348     @SystemApi
349     public static final String EXTRA_BATTERY_LEVEL = "android.bluetooth.device.extra.BATTERY_LEVEL";
350 
351     /**
352      * Used as the unknown value for {@link #EXTRA_BATTERY_LEVEL} and {@link #getBatteryLevel()}
353      *
354      * @hide
355      */
356     @SystemApi public static final int BATTERY_LEVEL_UNKNOWN = -1;
357 
358     /**
359      * Used as an error value for {@link #getBatteryLevel()} to represent bluetooth is off
360      *
361      * @hide
362      */
363     @SystemApi public static final int BATTERY_LEVEL_BLUETOOTH_OFF = -100;
364 
365     /**
366      * Used as a Parcelable {@link BluetoothDevice} extra field in every intent broadcast by this
367      * class. It contains the {@link BluetoothDevice} that the intent applies to.
368      */
369     public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
370 
371     /**
372      * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link #ACTION_FOUND}
373      * intents. It contains the friendly Bluetooth name.
374      */
375     public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
376 
377     /**
378      * Used as an optional short extra field in {@link #ACTION_FOUND} intents. Contains the RSSI
379      * value of the remote device as reported by the Bluetooth hardware.
380      */
381     public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
382 
383     /**
384      * Used as a boolean extra field in {@link #ACTION_FOUND} intents. It contains the information
385      * if device is discovered as member of a coordinated set or not. Pairing with device that
386      * belongs to a set would trigger pairing with the rest of set members. See Bluetooth CSIP
387      * specification for more details.
388      */
389     public static final String EXTRA_IS_COORDINATED_SET_MEMBER =
390             "android.bluetooth.extra.IS_COORDINATED_SET_MEMBER";
391 
392     /**
393      * Used as a Parcelable {@link BluetoothClass} extra field in {@link #ACTION_FOUND} and {@link
394      * #ACTION_CLASS_CHANGED} intents.
395      */
396     public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
397 
398     /**
399      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. Contains the bond
400      * state of the remote device.
401      *
402      * <p>Possible values are: {@link #BOND_NONE}, {@link #BOND_BONDING}, {@link #BOND_BONDED}.
403      */
404     public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
405 
406     /**
407      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents. Contains the
408      * previous bond state of the remote device.
409      *
410      * <p>Possible values are: {@link #BOND_NONE}, {@link #BOND_BONDING}, {@link #BOND_BONDED}.
411      */
412     public static final String EXTRA_PREVIOUS_BOND_STATE =
413             "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
414 
415     /**
416      * Used as a boolean extra field to indicate if audio buffer size is low latency or not
417      *
418      * @hide
419      */
420     @SuppressLint("ActionValue")
421     @SystemApi
422     public static final String EXTRA_LOW_LATENCY_BUFFER_SIZE =
423             "android.bluetooth.device.extra.LOW_LATENCY_BUFFER_SIZE";
424 
425     /**
426      * Indicates the remote device is not bonded (paired).
427      *
428      * <p>There is no shared link key with the remote device, so communication (if it is allowed at
429      * all) will be unauthenticated and unencrypted.
430      */
431     public static final int BOND_NONE = 10;
432 
433     /** Indicates bonding (pairing) is in progress with the remote device. */
434     public static final int BOND_BONDING = 11;
435 
436     /**
437      * Indicates the remote device is bonded (paired).
438      *
439      * <p>A shared link keys exists locally for the remote device, so communication can be
440      * authenticated and encrypted.
441      *
442      * <p><i>Being bonded (paired) with a remote device does not necessarily mean the device is
443      * currently connected. It just means that the pending procedure was completed at some earlier
444      * time, and the link key is still stored locally, ready to use on the next connection. </i>
445      */
446     public static final int BOND_BONDED = 12;
447 
448     /**
449      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} intents for unbond reason.
450      * Possible value are : - {@link #UNBOND_REASON_AUTH_FAILED} - {@link
451      * #UNBOND_REASON_AUTH_REJECTED} - {@link #UNBOND_REASON_AUTH_CANCELED} - {@link
452      * #UNBOND_REASON_REMOTE_DEVICE_DOWN} - {@link #UNBOND_REASON_DISCOVERY_IN_PROGRESS} - {@link
453      * #UNBOND_REASON_AUTH_TIMEOUT} - {@link #UNBOND_REASON_REPEATED_ATTEMPTS} - {@link
454      * #UNBOND_REASON_REMOTE_AUTH_CANCELED} - {@link #UNBOND_REASON_REMOVED}
455      *
456      * <p>Note: Can be added as a hidden extra field for {@link #ACTION_BOND_STATE_CHANGED} when the
457      * {@link #EXTRA_BOND_STATE} is {@link #BOND_NONE}
458      *
459      * @hide
460      */
461     @SystemApi
462     @SuppressLint("ActionValue")
463     public static final String EXTRA_UNBOND_REASON = "android.bluetooth.device.extra.REASON";
464 
465     /**
466      * Use {@link EXTRA_UNBOND_REASON} instead
467      *
468      * @hide
469      */
470     @UnsupportedAppUsage public static final String EXTRA_REASON = EXTRA_UNBOND_REASON;
471 
472     /**
473      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} intents to indicate pairing
474      * method used. Possible values are: {@link #PAIRING_VARIANT_PIN}, {@link
475      * #PAIRING_VARIANT_PASSKEY_CONFIRMATION},
476      */
477     public static final String EXTRA_PAIRING_VARIANT =
478             "android.bluetooth.device.extra.PAIRING_VARIANT";
479 
480     /**
481      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} intents as the value of
482      * passkey. The Bluetooth Passkey is a 6-digit numerical value represented as integer value in
483      * the range 0x00000000 – 0x000F423F (000000 to 999999).
484      */
485     public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
486 
487     /**
488      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST} intents as the location of
489      * initiator. Possible value are: {@link #EXTRA_PAIRING_INITIATOR_FOREGROUND}, {@link
490      * #EXTRA_PAIRING_INITIATOR_BACKGROUND},
491      *
492      * @hide
493      */
494     @SystemApi
495     @SuppressLint("ActionValue")
496     public static final String EXTRA_PAIRING_INITIATOR =
497             "android.bluetooth.device.extra.PAIRING_INITIATOR";
498 
499     /**
500      * Used as an int extra field in {@link #ACTION_ENCRYPTION_CHANGE} intents as the size of the
501      * encryption key, in number of bytes. i.e. value of 16 means 16-byte, or 128 bit key size.
502      */
503     @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST)
504     @SuppressLint("ActionValue")
505     public static final String EXTRA_KEY_SIZE = "android.bluetooth.device.extra.KEY_SIZE";
506 
507     /**
508      * Used as an int extra field in {@link #ACTION_ENCRYPTION_CHANGE} intents as the algorithm used
509      * for encryption.
510      *
511      * <p>Possible values are: {@link #ENCRYPTION_ALGORITHM_NONE}, {@link #ENCRYPTION_ALGORITHM_E0},
512      * {@link #ENCRYPTION_ALGORITHM_AES}.
513      */
514     @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST)
515     @SuppressLint("ActionValue")
516     public static final String EXTRA_ENCRYPTION_ALGORITHM =
517             "android.bluetooth.device.extra.EXTRA_ENCRYPTION_ALGORITHM";
518 
519     /** Indicates that link was not encrypted using any algorithm */
520     @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST)
521     public static final int ENCRYPTION_ALGORITHM_NONE = 0;
522 
523     /** Indicates link was encrypted using E0 algorithm */
524     @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST)
525     public static final int ENCRYPTION_ALGORITHM_E0 = 1;
526 
527     /** Indicates link was encrypted using AES algorithm */
528     @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST)
529     public static final int ENCRYPTION_ALGORITHM_AES = 2;
530 
531     /**
532      * Used as an int extra field in {@link #ACTION_ENCRYPTION_CHANGE} intent. This is the status
533      * value as returned from controller in "HCI Encryption Change event" i.e. value of 0 means
534      * success.
535      */
536     @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST)
537     @SuppressLint("ActionValue")
538     public static final String EXTRA_ENCRYPTION_STATUS =
539             "android.bluetooth.device.extra.ENCRYPTION_STATUS";
540 
541     /**
542      * Used as a boolean extra field in {@link #ACTION_ENCRYPTION_CHANGE} intent. false mean
543      * encryption is OFF, true means encryption is ON
544      */
545     @FlaggedApi(Flags.FLAG_ENCRYPTION_CHANGE_BROADCAST)
546     @SuppressLint("ActionValue")
547     public static final String EXTRA_ENCRYPTION_ENABLED =
548             "android.bluetooth.device.extra.ENCRYPTION_ENABLED";
549 
550     /**
551      * Bluetooth pairing initiator, Foreground App
552      *
553      * @hide
554      */
555     @SystemApi public static final int EXTRA_PAIRING_INITIATOR_FOREGROUND = 1;
556 
557     /**
558      * Bluetooth pairing initiator, Background
559      *
560      * @hide
561      */
562     @SystemApi public static final int EXTRA_PAIRING_INITIATOR_BACKGROUND = 2;
563 
564     /** Bluetooth device type, Unknown */
565     public static final int DEVICE_TYPE_UNKNOWN = 0;
566 
567     /** Bluetooth device type, Classic - BR/EDR devices */
568     public static final int DEVICE_TYPE_CLASSIC = 1;
569 
570     /** Bluetooth device type, Low Energy - LE-only */
571     public static final int DEVICE_TYPE_LE = 2;
572 
573     /** Bluetooth device type, Dual Mode - BR/EDR/LE */
574     public static final int DEVICE_TYPE_DUAL = 3;
575 
576     /** @hide */
577     @RequiresBluetoothConnectPermission
578     @RequiresPermission(BLUETOOTH_CONNECT)
579     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
580     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
581     public static final String ACTION_SDP_RECORD = "android.bluetooth.device.action.SDP_RECORD";
582 
583     /** @hide */
584     @IntDef(
585             prefix = "METADATA_",
586             value = {
587                 METADATA_MANUFACTURER_NAME,
588                 METADATA_MODEL_NAME,
589                 METADATA_MODEL_YEAR,
590                 METADATA_SOFTWARE_VERSION,
591                 METADATA_HARDWARE_VERSION,
592                 METADATA_COMPANION_APP,
593                 METADATA_MAIN_ICON,
594                 METADATA_IS_UNTETHERED_HEADSET,
595                 METADATA_UNTETHERED_LEFT_ICON,
596                 METADATA_UNTETHERED_RIGHT_ICON,
597                 METADATA_UNTETHERED_CASE_ICON,
598                 METADATA_UNTETHERED_LEFT_BATTERY,
599                 METADATA_UNTETHERED_RIGHT_BATTERY,
600                 METADATA_UNTETHERED_CASE_BATTERY,
601                 METADATA_UNTETHERED_LEFT_CHARGING,
602                 METADATA_UNTETHERED_RIGHT_CHARGING,
603                 METADATA_UNTETHERED_CASE_CHARGING,
604                 METADATA_ENHANCED_SETTINGS_UI_URI,
605                 METADATA_DEVICE_TYPE,
606                 METADATA_MAIN_BATTERY,
607                 METADATA_MAIN_CHARGING,
608                 METADATA_MAIN_LOW_BATTERY_THRESHOLD,
609                 METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD,
610                 METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD,
611                 METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD,
612                 METADATA_SPATIAL_AUDIO,
613                 METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
614                 METADATA_LE_AUDIO,
615                 METADATA_GMCS_CCCD,
616                 METADATA_GTBS_CCCD,
617                 METADATA_EXCLUSIVE_MANAGER,
618                 METADATA_HEAD_UNIT_MANUFACTURER_NAME,
619                 METADATA_HEAD_UNIT_MODEL_NAME,
620                 METADATA_HEAD_UNIT_BUILD,
621                 METADATA_HEAD_UNIT_SOFTWARE_VERSION
622             })
623     @Retention(RetentionPolicy.SOURCE)
624     public @interface MetadataKey {}
625 
626     /**
627      * Maximum length of a metadata entry, this is to avoid exploding Bluetooth disk usage
628      *
629      * @hide
630      */
631     @SystemApi public static final int METADATA_MAX_LENGTH = 2048;
632 
633     /**
634      * Manufacturer name of this Bluetooth device Data type should be {@link String} as {@link Byte}
635      * array.
636      *
637      * @hide
638      */
639     @SystemApi public static final int METADATA_MANUFACTURER_NAME = 0;
640 
641     /**
642      * Model name of this Bluetooth device Data type should be {@link String} as {@link Byte} array.
643      *
644      * @hide
645      */
646     @SystemApi public static final int METADATA_MODEL_NAME = 1;
647 
648     /**
649      * Model year of the Bluetooth device. Data type should be {@link String} as {@link Byte} array.
650      *
651      * @hide
652      */
653     @FlaggedApi(Flags.FLAG_SUPPORT_REMOTE_DEVICE_METADATA)
654     @SystemApi
655     public static final int METADATA_MODEL_YEAR = 30;
656 
657     /**
658      * Software version of this Bluetooth device Data type should be {@link String} as {@link Byte}
659      * array.
660      *
661      * @hide
662      */
663     @SystemApi public static final int METADATA_SOFTWARE_VERSION = 2;
664 
665     /**
666      * Hardware version of this Bluetooth device Data type should be {@link String} as {@link Byte}
667      * array.
668      *
669      * @hide
670      */
671     @SystemApi public static final int METADATA_HARDWARE_VERSION = 3;
672 
673     /**
674      * Package name of the companion app, if any Data type should be {@link String} as {@link Byte}
675      * array.
676      *
677      * @hide
678      */
679     @SystemApi public static final int METADATA_COMPANION_APP = 4;
680 
681     /**
682      * URI to the main icon shown on the settings UI Data type should be {@link Byte} array.
683      *
684      * @hide
685      */
686     @SystemApi public static final int METADATA_MAIN_ICON = 5;
687 
688     /**
689      * Whether this device is an untethered headset with left, right and case Data type should be
690      * {@link String} as {@link Byte} array.
691      *
692      * @hide
693      */
694     @SystemApi public static final int METADATA_IS_UNTETHERED_HEADSET = 6;
695 
696     /**
697      * URI to icon of the left headset Data type should be {@link Byte} array.
698      *
699      * @hide
700      */
701     @SystemApi public static final int METADATA_UNTETHERED_LEFT_ICON = 7;
702 
703     /**
704      * URI to icon of the right headset Data type should be {@link Byte} array.
705      *
706      * @hide
707      */
708     @SystemApi public static final int METADATA_UNTETHERED_RIGHT_ICON = 8;
709 
710     /**
711      * URI to icon of the headset charging case Data type should be {@link Byte} array.
712      *
713      * @hide
714      */
715     @SystemApi public static final int METADATA_UNTETHERED_CASE_ICON = 9;
716 
717     /**
718      * Battery level of left headset Data type should be {@link String} 0-100 as {@link Byte} array,
719      * otherwise as invalid.
720      *
721      * @hide
722      */
723     @SystemApi public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10;
724 
725     /**
726      * Battery level of right headset Data type should be {@link String} 0-100 as {@link Byte}
727      * array, otherwise as invalid.
728      *
729      * @hide
730      */
731     @SystemApi public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11;
732 
733     /**
734      * Battery level of the headset charging case Data type should be {@link String} 0-100 as {@link
735      * Byte} array, otherwise as invalid.
736      *
737      * @hide
738      */
739     @SystemApi public static final int METADATA_UNTETHERED_CASE_BATTERY = 12;
740 
741     /**
742      * Whether the left headset is charging Data type should be {@link String} as {@link Byte}
743      * array.
744      *
745      * @hide
746      */
747     @SystemApi public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13;
748 
749     /**
750      * Whether the right headset is charging Data type should be {@link String} as {@link Byte}
751      * array.
752      *
753      * @hide
754      */
755     @SystemApi public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14;
756 
757     /**
758      * Whether the headset charging case is charging Data type should be {@link String} as {@link
759      * Byte} array.
760      *
761      * @hide
762      */
763     @SystemApi public static final int METADATA_UNTETHERED_CASE_CHARGING = 15;
764 
765     /**
766      * URI to the enhanced settings UI slice Data type should be {@link String} as {@link Byte}
767      * array, null means the UI does not exist.
768      *
769      * @hide
770      */
771     @SystemApi public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16;
772 
773     /** @hide */
774     public static final String COMPANION_TYPE_PRIMARY = "COMPANION_PRIMARY";
775 
776     /** @hide */
777     public static final String COMPANION_TYPE_SECONDARY = "COMPANION_SECONDARY";
778 
779     /** @hide */
780     public static final String COMPANION_TYPE_NONE = "COMPANION_NONE";
781 
782     /**
783      * Type of the Bluetooth device, must be within the list of BluetoothDevice.DEVICE_TYPE_* Data
784      * type should be {@link String} as {@link Byte} array.
785      *
786      * @hide
787      */
788     @SystemApi public static final int METADATA_DEVICE_TYPE = 17;
789 
790     /**
791      * Battery level of the Bluetooth device, use when the Bluetooth device does not support HFP
792      * battery indicator. Data type should be {@link String} as {@link Byte} array.
793      *
794      * @hide
795      */
796     @SystemApi public static final int METADATA_MAIN_BATTERY = 18;
797 
798     /**
799      * Whether the device is charging. Data type should be {@link String} as {@link Byte} array.
800      *
801      * @hide
802      */
803     @SystemApi public static final int METADATA_MAIN_CHARGING = 19;
804 
805     /**
806      * The battery threshold of the Bluetooth device to show low battery icon. Data type should be
807      * {@link String} as {@link Byte} array.
808      *
809      * @hide
810      */
811     @SystemApi public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20;
812 
813     /**
814      * The battery threshold of the left headset to show low battery icon. Data type should be
815      * {@link String} as {@link Byte} array.
816      *
817      * @hide
818      */
819     @SystemApi public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21;
820 
821     /**
822      * The battery threshold of the right headset to show low battery icon. Data type should be
823      * {@link String} as {@link Byte} array.
824      *
825      * @hide
826      */
827     @SystemApi public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22;
828 
829     /**
830      * The battery threshold of the case to show low battery icon. Data type should be {@link
831      * String} as {@link Byte} array.
832      *
833      * @hide
834      */
835     @SystemApi public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23;
836 
837     /**
838      * The metadata of the audio spatial data. Data type should be {@link Byte} array.
839      *
840      * @hide
841      */
842     public static final int METADATA_SPATIAL_AUDIO = 24;
843 
844     /**
845      * The metadata of the Fast Pair for any customized feature. Data type should be {@link Byte}
846      * array.
847      *
848      * @hide
849      */
850     public static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
851 
852     /**
853      * The metadata of the Fast Pair for LE Audio capable devices. Data type should be {@link Byte}
854      * array.
855      *
856      * @hide
857      */
858     @SystemApi public static final int METADATA_LE_AUDIO = 26;
859 
860     /**
861      * The UUIDs (16-bit) of registered to CCC characteristics from Media Control services. Data
862      * type should be {@link Byte} array.
863      *
864      * @hide
865      */
866     public static final int METADATA_GMCS_CCCD = 27;
867 
868     /**
869      * The UUIDs (16-bit) of registered to CCC characteristics from Telephony Bearer service. Data
870      * type should be {@link Byte} array.
871      *
872      * @hide
873      */
874     public static final int METADATA_GTBS_CCCD = 28;
875 
876     /**
877      * Specify the exclusive manager app for this BluetoothDevice.
878      *
879      * <p>If there's a manager app specified for this BluetoothDevice, and the app is currently
880      * installed and enabled on the device, that manager app shall be responsible for providing the
881      * BluetoothDevice management functionality (e.g. connect, disconnect, forget, etc.). Android
882      * Settings app or Quick Settings System UI shall not provide any management functionality for
883      * such BluetoothDevice.
884      *
885      * <p>Data type should be a {@link String} representation of the {@link ComponentName} (e.g.
886      * "com.android.settings/.SettingsActivity") or the package name (e.g. "com.android.settings")
887      * of the exclusive manager, provided as a {@link Byte} array.
888      *
889      * @hide
890      */
891     @SystemApi public static final int METADATA_EXCLUSIVE_MANAGER = 29;
892 
893     private static final int METADATA_MAX_KEY = METADATA_EXCLUSIVE_MANAGER;
894 
895     /**
896      * Head unit manufacturer name of the Bluetooth device. Data type should be {@link String} as
897      * {@link Byte} array. Should only be set/available for a car device.
898      *
899      * @hide
900      */
901     @FlaggedApi(Flags.FLAG_SUPPORT_REMOTE_DEVICE_METADATA)
902     @SystemApi
903     public static final int METADATA_HEAD_UNIT_MANUFACTURER_NAME = 31;
904 
905     /**
906      * Head unit model name of the Bluetooth device. Data type should be {@link String} as {@link
907      * Byte} array. Should only be set/available for a car device.
908      *
909      * @hide
910      */
911     @FlaggedApi(Flags.FLAG_SUPPORT_REMOTE_DEVICE_METADATA)
912     @SystemApi
913     public static final int METADATA_HEAD_UNIT_MODEL_NAME = 32;
914 
915     /**
916      * Build of the overall head unit device. Not specific to hardware or software. Example can be
917      * 'manufacturer_country'. Data type should be {@link String} as {@link Byte} array. Should only
918      * be set/available for a car device.
919      *
920      * @hide
921      */
922     @FlaggedApi(Flags.FLAG_SUPPORT_REMOTE_DEVICE_METADATA)
923     @SystemApi
924     public static final int METADATA_HEAD_UNIT_BUILD = 33;
925 
926     /**
927      * Head unit software version of the Bluetooth device. Data type should be {@link String} as
928      * {@link Byte} array. Should only be set/available for a car device.
929      *
930      * @hide
931      */
932     @FlaggedApi(Flags.FLAG_SUPPORT_REMOTE_DEVICE_METADATA)
933     @SystemApi
934     public static final int METADATA_HEAD_UNIT_SOFTWARE_VERSION = 34;
935 
936     /**
937      * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a
938      * standard Bluetooth accessory or not listed in METADATA_DEVICE_TYPE_*.
939      *
940      * @hide
941      */
942     @SystemApi public static final String DEVICE_TYPE_DEFAULT = "Default";
943 
944     /**
945      * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a watch.
946      *
947      * @hide
948      */
949     @SystemApi public static final String DEVICE_TYPE_WATCH = "Watch";
950 
951     /**
952      * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is an
953      * untethered headset.
954      *
955      * @hide
956      */
957     @SystemApi public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset";
958 
959     /**
960      * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a
961      * stylus.
962      *
963      * @hide
964      */
965     @SystemApi public static final String DEVICE_TYPE_STYLUS = "Stylus";
966 
967     /**
968      * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a
969      * speaker.
970      *
971      * @hide
972      */
973     @FlaggedApi(Flags.FLAG_SUPPORT_METADATA_DEVICE_TYPES_APIS)
974     @SystemApi
975     public static final String DEVICE_TYPE_SPEAKER = "Speaker";
976 
977     /**
978      * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a
979      * tethered headset.
980      *
981      * @hide
982      */
983     @FlaggedApi(Flags.FLAG_SUPPORT_METADATA_DEVICE_TYPES_APIS)
984     @SystemApi
985     public static final String DEVICE_TYPE_HEADSET = "Headset";
986 
987     /**
988      * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a
989      * Carkit.
990      *
991      * @hide
992      */
993     @FlaggedApi(Flags.FLAG_SUPPORT_METADATA_DEVICE_TYPES_APIS)
994     @SystemApi
995     public static final String DEVICE_TYPE_CARKIT = "Carkit";
996 
997     /**
998      * Device type which is used in METADATA_DEVICE_TYPE Indicates this Bluetooth device is a
999      * HearingAid.
1000      *
1001      * @hide
1002      */
1003     @FlaggedApi(Flags.FLAG_SUPPORT_METADATA_DEVICE_TYPES_APIS)
1004     @SystemApi
1005     public static final String DEVICE_TYPE_HEARING_AID = "HearingAid";
1006 
1007     /**
1008      * Broadcast Action: This intent is used to broadcast the {@link UUID} wrapped as a {@link
1009      * android.os.ParcelUuid} of the remote device after it has been fetched. This intent is sent
1010      * only when the UUIDs of the remote device are requested to be fetched using Service Discovery
1011      * Protocol
1012      *
1013      * <p>Always contains the extra field {@link #EXTRA_DEVICE}
1014      *
1015      * <p>Always contains the extra field {@link #EXTRA_UUID}
1016      */
1017     @RequiresLegacyBluetoothAdminPermission
1018     @RequiresBluetoothConnectPermission
1019     @RequiresPermission(BLUETOOTH_CONNECT)
1020     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1021     public static final String ACTION_UUID = "android.bluetooth.device.action.UUID";
1022 
1023     /** @hide */
1024     @RequiresBluetoothConnectPermission
1025     @RequiresPermission(BLUETOOTH_CONNECT)
1026     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1027     public static final String ACTION_MAS_INSTANCE = "android.bluetooth.device.action.MAS_INSTANCE";
1028 
1029     /**
1030      * Broadcast Action: Indicates a failure to retrieve the name of a remote device.
1031      *
1032      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
1033      *
1034      * @hide
1035      */
1036     // TODO: is this actually useful?
1037     @RequiresLegacyBluetoothPermission
1038     @RequiresBluetoothConnectPermission
1039     @RequiresPermission(BLUETOOTH_CONNECT)
1040     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1041     public static final String ACTION_NAME_FAILED = "android.bluetooth.device.action.NAME_FAILED";
1042 
1043     /** Broadcast Action: This intent is used to broadcast PAIRING REQUEST */
1044     @RequiresLegacyBluetoothAdminPermission
1045     @RequiresBluetoothConnectPermission
1046     @RequiresPermission(BLUETOOTH_CONNECT)
1047     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1048     public static final String ACTION_PAIRING_REQUEST =
1049             "android.bluetooth.device.action.PAIRING_REQUEST";
1050 
1051     /**
1052      * Starting from {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the return value of
1053      * {@link BluetoothDevice#toString()} has changed to improve privacy.
1054      */
1055     @ChangeId
1056     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
1057     private static final long CHANGE_TO_STRING_REDACTED = 265103382L;
1058 
1059     /**
1060      * Broadcast Action: This intent is used to broadcast PAIRING CANCEL
1061      *
1062      * @hide
1063      */
1064     @SystemApi
1065     @RequiresBluetoothConnectPermission
1066     @RequiresPermission(BLUETOOTH_CONNECT)
1067     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1068     @SuppressLint("ActionValue")
1069     public static final String ACTION_PAIRING_CANCEL =
1070             "android.bluetooth.device.action.PAIRING_CANCEL";
1071 
1072     /**
1073      * Broadcast Action: This intent is used to broadcast CONNECTION ACCESS REQUEST
1074      *
1075      * <p>This action will trigger a prompt for the user to accept or deny giving the permission for
1076      * this device. Permissions can be specified with {@link #EXTRA_ACCESS_REQUEST_TYPE}.
1077      *
1078      * <p>The reply will be an {@link #ACTION_CONNECTION_ACCESS_REPLY} sent to the specified {@link
1079      * #EXTRA_PACKAGE_NAME} and {@link #EXTRA_CLASS_NAME}.
1080      *
1081      * <p>This action can be cancelled with {@link #ACTION_CONNECTION_ACCESS_CANCEL}.
1082      *
1083      * @hide
1084      */
1085     @SystemApi
1086     @RequiresBluetoothConnectPermission
1087     @RequiresPermission(BLUETOOTH_CONNECT)
1088     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1089     @SuppressLint("ActionValue")
1090     public static final String ACTION_CONNECTION_ACCESS_REQUEST =
1091             "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
1092 
1093     /**
1094      * Broadcast Action: This intent is used to broadcast CONNECTION ACCESS REPLY
1095      *
1096      * <p>This action is the reply from {@link #ACTION_CONNECTION_ACCESS_REQUEST} that is sent to
1097      * the specified {@link #EXTRA_PACKAGE_NAME} and {@link #EXTRA_CLASS_NAME}.
1098      *
1099      * <p>See the extra fields {@link #EXTRA_CONNECTION_ACCESS_RESULT} and {@link
1100      * #EXTRA_ALWAYS_ALLOWED} for possible results.
1101      *
1102      * @hide
1103      */
1104     @SystemApi
1105     @RequiresBluetoothConnectPermission
1106     @RequiresPermission(BLUETOOTH_CONNECT)
1107     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1108     @SuppressLint("ActionValue")
1109     public static final String ACTION_CONNECTION_ACCESS_REPLY =
1110             "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
1111 
1112     /**
1113      * Broadcast Action: This intent is used to broadcast CONNECTION ACCESS CANCEL
1114      *
1115      * @hide
1116      */
1117     @SystemApi
1118     @RequiresBluetoothConnectPermission
1119     @RequiresPermission(BLUETOOTH_CONNECT)
1120     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1121     @SuppressLint("ActionValue")
1122     public static final String ACTION_CONNECTION_ACCESS_CANCEL =
1123             "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
1124 
1125     /**
1126      * Intent to broadcast silence mode changed. Always contains the extra field {@link
1127      * #EXTRA_DEVICE}
1128      *
1129      * @hide
1130      */
1131     @RequiresBluetoothConnectPermission
1132     @RequiresPermission(BLUETOOTH_CONNECT)
1133     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1134     @SystemApi
1135     public static final String ACTION_SILENCE_MODE_CHANGED =
1136             "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
1137 
1138     /**
1139      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST}.
1140      *
1141      * <p>Possible values are {@link #REQUEST_TYPE_PROFILE_CONNECTION}, {@link
1142      * #REQUEST_TYPE_PHONEBOOK_ACCESS}, {@link #REQUEST_TYPE_MESSAGE_ACCESS} and {@link
1143      * #REQUEST_TYPE_SIM_ACCESS}
1144      *
1145      * @hide
1146      */
1147     @SystemApi
1148     @SuppressLint("ActionValue")
1149     public static final String EXTRA_ACCESS_REQUEST_TYPE =
1150             "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE";
1151 
1152     /** @hide */
1153     @SystemApi public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1;
1154 
1155     /** @hide */
1156     @SystemApi public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
1157 
1158     /** @hide */
1159     @SystemApi public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3;
1160 
1161     /** @hide */
1162     @SystemApi public static final int REQUEST_TYPE_SIM_ACCESS = 4;
1163 
1164     /**
1165      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, Contains package
1166      * name to return reply intent to.
1167      *
1168      * @hide
1169      */
1170     public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME";
1171 
1172     /**
1173      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents, Contains class
1174      * name to return reply intent to.
1175      *
1176      * @hide
1177      */
1178     public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME";
1179 
1180     /**
1181      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
1182      *
1183      * <p>Possible values are {@link #CONNECTION_ACCESS_YES} and {@link #CONNECTION_ACCESS_NO}.
1184      *
1185      * @hide
1186      */
1187     @SystemApi
1188     @SuppressLint("ActionValue")
1189     public static final String EXTRA_CONNECTION_ACCESS_RESULT =
1190             "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
1191 
1192     /** @hide */
1193     @SystemApi public static final int CONNECTION_ACCESS_YES = 1;
1194 
1195     /** @hide */
1196     @SystemApi public static final int CONNECTION_ACCESS_NO = 2;
1197 
1198     /**
1199      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents, Contains boolean
1200      * to indicate if the allowed response is once-for-all so that next request will be granted
1201      * without asking user again.
1202      *
1203      * @hide
1204      */
1205     @SystemApi
1206     @SuppressLint("ActionValue")
1207     public static final String EXTRA_ALWAYS_ALLOWED =
1208             "android.bluetooth.device.extra.ALWAYS_ALLOWED";
1209 
1210     /**
1211      * A bond attempt succeeded
1212      *
1213      * @hide
1214      */
1215     public static final int BOND_SUCCESS = 0;
1216 
1217     /**
1218      * A bond attempt failed because pins did not match, or remote device did not respond to pin
1219      * request in time
1220      *
1221      * @hide
1222      */
1223     @SystemApi public static final int UNBOND_REASON_AUTH_FAILED = 1;
1224 
1225     /**
1226      * A bond attempt failed because the other side explicitly rejected bonding
1227      *
1228      * @hide
1229      */
1230     @SystemApi public static final int UNBOND_REASON_AUTH_REJECTED = 2;
1231 
1232     /**
1233      * A bond attempt failed because we canceled the bonding process
1234      *
1235      * @hide
1236      */
1237     @SystemApi public static final int UNBOND_REASON_AUTH_CANCELED = 3;
1238 
1239     /**
1240      * A bond attempt failed because we could not contact the remote device
1241      *
1242      * @hide
1243      */
1244     @SystemApi public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
1245 
1246     /**
1247      * A bond attempt failed because a discovery is in progress
1248      *
1249      * @hide
1250      */
1251     @SystemApi public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
1252 
1253     /**
1254      * A bond attempt failed because of authentication timeout
1255      *
1256      * @hide
1257      */
1258     @SystemApi public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
1259 
1260     /**
1261      * A bond attempt failed because of repeated attempts
1262      *
1263      * @hide
1264      */
1265     @SystemApi public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
1266 
1267     /**
1268      * A bond attempt failed because we received an Authentication Cancel by remote end
1269      *
1270      * @hide
1271      */
1272     @SystemApi public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
1273 
1274     /**
1275      * An existing bond was explicitly revoked
1276      *
1277      * @hide
1278      */
1279     @SystemApi public static final int UNBOND_REASON_REMOVED = 9;
1280 
1281     /** The user will be prompted to enter a pin or an app will enter a pin for user. */
1282     public static final int PAIRING_VARIANT_PIN = 0;
1283 
1284     /**
1285      * The user will be prompted to enter a passkey
1286      *
1287      * @hide
1288      */
1289     @SystemApi public static final int PAIRING_VARIANT_PASSKEY = 1;
1290 
1291     /**
1292      * The user will be prompted to confirm the passkey displayed on the screen or an app will
1293      * confirm the passkey for the user.
1294      */
1295     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
1296 
1297     /**
1298      * The user will be prompted to accept or deny the incoming pairing request
1299      *
1300      * @hide
1301      */
1302     @SystemApi public static final int PAIRING_VARIANT_CONSENT = 3;
1303 
1304     /**
1305      * The user will be prompted to enter the passkey displayed on remote device This is used for
1306      * Bluetooth 2.1 pairing.
1307      *
1308      * @hide
1309      */
1310     @SystemApi public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
1311 
1312     /**
1313      * The user will be prompted to enter the PIN displayed on remote device. This is used for
1314      * Bluetooth 2.0 pairing.
1315      *
1316      * @hide
1317      */
1318     @SystemApi public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
1319 
1320     /**
1321      * The user will be prompted to accept or deny the OOB pairing request. This is used for
1322      * Bluetooth 2.1 secure simple pairing.
1323      *
1324      * @hide
1325      */
1326     @SystemApi public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
1327 
1328     /**
1329      * The user will be prompted to enter a 16 digit pin or an app will enter a 16 digit pin for
1330      * user.
1331      *
1332      * @hide
1333      */
1334     @SystemApi public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7;
1335 
1336     /**
1337      * Used as an extra field in {@link #ACTION_UUID} intents, Contains the {@link
1338      * android.os.ParcelUuid}s of the remote device which is a parcelable version of {@link UUID}. A
1339      * {@code null} EXTRA_UUID indicates a timeout.
1340      */
1341     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
1342 
1343     /** @hide */
1344     public static final String EXTRA_SDP_RECORD = "android.bluetooth.device.extra.SDP_RECORD";
1345 
1346     /** @hide */
1347     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1348     public static final String EXTRA_SDP_SEARCH_STATUS =
1349             "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
1350 
1351     /** @hide */
1352     @IntDef(
1353             prefix = "ACCESS_",
1354             value = {ACCESS_UNKNOWN, ACCESS_ALLOWED, ACCESS_REJECTED})
1355     @Retention(RetentionPolicy.SOURCE)
1356     public @interface AccessPermission {}
1357 
1358     /**
1359      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, {@link
1360      * #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
1361      *
1362      * @hide
1363      */
1364     @SystemApi public static final int ACCESS_UNKNOWN = 0;
1365 
1366     /**
1367      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, {@link
1368      * #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
1369      *
1370      * @hide
1371      */
1372     @SystemApi public static final int ACCESS_ALLOWED = 1;
1373 
1374     /**
1375      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission}, {@link
1376      * #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
1377      *
1378      * @hide
1379      */
1380     @SystemApi public static final int ACCESS_REJECTED = 2;
1381 
1382     /** @hide */
1383     @Retention(RetentionPolicy.SOURCE)
1384     @IntDef(
1385             prefix = {"TRANSPORT_"},
1386             value = {
1387                 TRANSPORT_AUTO,
1388                 TRANSPORT_BREDR,
1389                 TRANSPORT_LE,
1390             })
1391     public @interface Transport {}
1392 
1393     /** No preference of physical transport for GATT connections to remote dual-mode devices */
1394     public static final int TRANSPORT_AUTO = 0;
1395 
1396     /** Constant representing the BR/EDR transport. */
1397     public static final int TRANSPORT_BREDR = 1;
1398 
1399     /** Constant representing the Bluetooth Low Energy (BLE) Transport. */
1400     public static final int TRANSPORT_LE = 2;
1401 
1402     /**
1403      * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or
1404      * connection.
1405      */
1406     public static final int PHY_LE_1M = 1;
1407 
1408     /**
1409      * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or
1410      * connection.
1411      */
1412     public static final int PHY_LE_2M = 2;
1413 
1414     /**
1415      * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning
1416      * or connection.
1417      */
1418     public static final int PHY_LE_CODED = 3;
1419 
1420     /**
1421      * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available
1422      * options in a bitmask.
1423      */
1424     public static final int PHY_LE_1M_MASK = 1;
1425 
1426     /**
1427      * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available
1428      * options in a bitmask.
1429      */
1430     public static final int PHY_LE_2M_MASK = 2;
1431 
1432     /**
1433      * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many
1434      * available options in a bitmask.
1435      */
1436     public static final int PHY_LE_CODED_MASK = 4;
1437 
1438     /** No preferred coding when transmitting on the LE Coded PHY. */
1439     public static final int PHY_OPTION_NO_PREFERRED = 0;
1440 
1441     /** Prefer the S=2 coding to be used when transmitting on the LE Coded PHY. */
1442     public static final int PHY_OPTION_S2 = 1;
1443 
1444     /** Prefer the S=8 coding to be used when transmitting on the LE Coded PHY. */
1445     public static final int PHY_OPTION_S8 = 2;
1446 
1447     /** @hide */
1448     public static final String EXTRA_MAS_INSTANCE = "android.bluetooth.device.extra.MAS_INSTANCE";
1449 
1450     /**
1451      * Used as an int extra field in {@link #ACTION_ACL_CONNECTED}, {@link #ACTION_ACL_DISCONNECTED}
1452      * and {@link #ACTION_ENCRYPTION_CHANGE} intents to indicate which transport is connected.
1453      * Possible values are: {@link #TRANSPORT_BREDR} and {@link #TRANSPORT_LE}.
1454      */
1455     @SuppressLint("ActionValue")
1456     public static final String EXTRA_TRANSPORT = "android.bluetooth.device.extra.TRANSPORT";
1457 
1458     /** @hide */
1459     @Retention(RetentionPolicy.SOURCE)
1460     @IntDef(
1461             prefix = {"ADDRESS_TYPE_"},
1462             value = {
1463                 ADDRESS_TYPE_PUBLIC,
1464                 ADDRESS_TYPE_RANDOM,
1465                 ADDRESS_TYPE_ANONYMOUS,
1466                 ADDRESS_TYPE_UNKNOWN,
1467             })
1468     public @interface AddressType {}
1469 
1470     /** Hardware MAC Address of the device */
1471     public static final int ADDRESS_TYPE_PUBLIC = 0;
1472 
1473     /** Address is either resolvable, non-resolvable or static. */
1474     public static final int ADDRESS_TYPE_RANDOM = 1;
1475 
1476     /** Address type is unknown or unavailable */
1477     public static final int ADDRESS_TYPE_UNKNOWN = 0xFFFF;
1478 
1479     /** Address type used to indicate an anonymous advertisement. */
1480     public static final int ADDRESS_TYPE_ANONYMOUS = 0xFF;
1481 
1482     /**
1483      * Indicates default active audio device policy is applied to this device
1484      *
1485      * @hide
1486      */
1487     @SystemApi public static final int ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT = 0;
1488 
1489     /**
1490      * Indicates all profiles active audio device policy is applied to this device
1491      *
1492      * <p>all profiles are active upon device connection
1493      *
1494      * @hide
1495      */
1496     @SystemApi
1497     public static final int ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_ACTIVE_UPON_CONNECTION = 1;
1498 
1499     /**
1500      * Indicates all profiles inactive audio device policy is applied to this device
1501      *
1502      * <p>all profiles are inactive upon device connection
1503      *
1504      * @hide
1505      */
1506     @SystemApi
1507     public static final int ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_INACTIVE_UPON_CONNECTION = 2;
1508 
1509     private static final String NULL_MAC_ADDRESS = "00:00:00:00:00:00";
1510 
1511     private final String mAddress;
1512     @AddressType private final int mAddressType;
1513 
1514     private AttributionSource mAttributionSource;
1515 
getService()1516     static IBluetooth getService() {
1517         return BluetoothAdapter.getDefaultAdapter().getBluetoothService();
1518     }
1519 
1520     /**
1521      * Create a new BluetoothDevice. Bluetooth MAC address must be upper case, such as
1522      * "00:11:22:33:AA:BB", and is validated in this constructor.
1523      *
1524      * @param address valid Bluetooth MAC address
1525      * @param addressType valid address type
1526      * @throws RuntimeException Bluetooth is not available on this platform
1527      * @throws IllegalArgumentException address or addressType is invalid
1528      * @hide
1529      */
BluetoothDevice(String address, int addressType)1530     /*package*/ BluetoothDevice(String address, int addressType) {
1531         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1532             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
1533         }
1534 
1535         if (addressType != ADDRESS_TYPE_PUBLIC
1536                 && addressType != ADDRESS_TYPE_RANDOM
1537                 && addressType != ADDRESS_TYPE_ANONYMOUS) {
1538             throw new IllegalArgumentException(addressType + " is not a Bluetooth address type");
1539         }
1540 
1541         if (addressType == ADDRESS_TYPE_ANONYMOUS && !NULL_MAC_ADDRESS.equals(address)) {
1542             throw new IllegalArgumentException(
1543                     "Invalid address for anonymous address type: "
1544                             + BluetoothUtils.toAnonymizedAddress(address));
1545         }
1546 
1547         mAddress = address;
1548         mAddressType = addressType;
1549         mAttributionSource = AttributionSource.myAttributionSource();
1550     }
1551 
1552     /**
1553      * Create a new BluetoothDevice. Bluetooth MAC address must be upper case, such as
1554      * "00:11:22:33:AA:BB", and is validated in this constructor.
1555      *
1556      * @param address valid Bluetooth MAC address
1557      * @throws RuntimeException Bluetooth is not available on this platform
1558      * @throws IllegalArgumentException address is invalid
1559      * @hide
1560      */
1561     @UnsupportedAppUsage
BluetoothDevice(String address)1562     /*package*/ BluetoothDevice(String address) {
1563         this(address, ADDRESS_TYPE_PUBLIC);
1564     }
1565 
1566     /**
1567      * Create a new BluetoothDevice.
1568      *
1569      * @param in valid parcel
1570      * @throws RuntimeException Bluetooth is not available on this platform
1571      * @throws IllegalArgumentException address is invalid
1572      * @hide
1573      */
1574     @UnsupportedAppUsage
BluetoothDevice(Parcel in)1575     /*package*/ BluetoothDevice(Parcel in) {
1576         this(in.readString(), in.readInt());
1577     }
1578 
1579     /** @hide */
setAttributionSource(@onNull AttributionSource attributionSource)1580     public void setAttributionSource(@NonNull AttributionSource attributionSource) {
1581         mAttributionSource = attributionSource;
1582     }
1583 
1584     /**
1585      * Method should never be used anywhere. Only exception is from {@link Intent} Used to set the
1586      * device current attribution source
1587      *
1588      * @param attributionSource The associated {@link AttributionSource} for this device in this
1589      *     process
1590      * @hide
1591      */
1592     @SystemApi
prepareToEnterProcess(@onNull AttributionSource attributionSource)1593     public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) {
1594         setAttributionSource(attributionSource);
1595     }
1596 
1597     @Override
equals(@ullable Object o)1598     public boolean equals(@Nullable Object o) {
1599         if (o instanceof BluetoothDevice) {
1600             return mAddress.equals(((BluetoothDevice) o).getAddress());
1601         }
1602         return false;
1603     }
1604 
1605     @Override
hashCode()1606     public int hashCode() {
1607         return mAddress.hashCode();
1608     }
1609 
1610     /**
1611      * Returns a string representation of this BluetoothDevice.
1612      *
1613      * <p>For apps targeting {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} (API level 34)
1614      * or higher, this returns the MAC address of the device redacted by replacing the hexadecimal
1615      * digits of leftmost 4 bytes (in big endian order) with "XX", e.g., "XX:XX:XX:XX:12:34". For
1616      * apps targeting earlier versions, the MAC address is returned without redaction.
1617      *
1618      * <p>Warning: The return value of {@link #toString()} may change in the future. It is intended
1619      * to be used in logging statements. Thus apps should never rely on the return value of {@link
1620      * #toString()} in their logic. Always use other appropriate APIs instead (e.g., use {@link
1621      * #getAddress()} to get the MAC address).
1622      *
1623      * @return string representation of this BluetoothDevice
1624      */
1625     @Override
toString()1626     public String toString() {
1627         if (!CompatChanges.isChangeEnabled(CHANGE_TO_STRING_REDACTED)) {
1628             return mAddress;
1629         }
1630         return getAnonymizedAddress();
1631     }
1632 
1633     @Override
describeContents()1634     public int describeContents() {
1635         return 0;
1636     }
1637 
1638     public static final @NonNull Creator<BluetoothDevice> CREATOR =
1639             new Creator<>() {
1640                 public BluetoothDevice createFromParcel(Parcel in) {
1641                     return new BluetoothDevice(in);
1642                 }
1643 
1644                 public BluetoothDevice[] newArray(int size) {
1645                     return new BluetoothDevice[size];
1646                 }
1647             };
1648 
1649     @Override
writeToParcel(Parcel out, int flags)1650     public void writeToParcel(Parcel out, int flags) {
1651         BluetoothUtils.writeStringToParcel(out, mAddress);
1652         out.writeInt(mAddressType);
1653     }
1654 
1655     /**
1656      * Returns the hardware address of this BluetoothDevice.
1657      *
1658      * <p>For example, "00:11:22:AA:BB:CC".
1659      *
1660      * @return Bluetooth hardware address as string
1661      */
getAddress()1662     public String getAddress() {
1663         if (DBG) Log.d(TAG, "getAddress: mAddress=" + this);
1664         return mAddress;
1665     }
1666 
1667     /**
1668      * Returns the address type of this BluetoothDevice, one of {@link #ADDRESS_TYPE_PUBLIC}, {@link
1669      * #ADDRESS_TYPE_RANDOM}, {@link #ADDRESS_TYPE_ANONYMOUS}, or {@link #ADDRESS_TYPE_UNKNOWN}.
1670      *
1671      * @return Bluetooth address type
1672      */
getAddressType()1673     public @AddressType int getAddressType() {
1674         if (DBG) Log.d(TAG, "mAddressType: " + mAddressType);
1675         return mAddressType;
1676     }
1677 
1678     /**
1679      * Returns the anonymized hardware address of this BluetoothDevice. The first three octets will
1680      * be suppressed for anonymization.
1681      *
1682      * <p>For example, "XX:XX:XX:AA:BB:CC".
1683      *
1684      * @return Anonymized bluetooth hardware address as string
1685      * @hide
1686      */
1687     @SystemApi
1688     @NonNull
getAnonymizedAddress()1689     public String getAnonymizedAddress() {
1690         return BluetoothUtils.toAnonymizedAddress(mAddress);
1691     }
1692 
1693     /**
1694      * Returns the identity address of this BluetoothDevice.
1695      *
1696      * <p>For example, "00:11:22:AA:BB:CC".
1697      *
1698      * @return Bluetooth identity address as a string
1699      * @hide
1700      */
1701     @SystemApi
1702     @RequiresBluetoothConnectPermission
1703     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getIdentityAddress()1704     public @Nullable String getIdentityAddress() {
1705         if (DBG) log("getIdentityAddress()");
1706         final IBluetooth service = getService();
1707         if (service == null || !isBluetoothEnabled()) {
1708             Log.e(TAG, "BT not enabled. Cannot get identity address");
1709         } else {
1710             try {
1711                 return service.getIdentityAddress(mAddress);
1712             } catch (RemoteException e) {
1713                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
1714             }
1715         }
1716         return null;
1717     }
1718 
1719     /**
1720      * Returns the identity address and identity address type of this BluetoothDevice. An identity
1721      * address is a public or static random Bluetooth LE device address that serves as a unique
1722      * identifier.
1723      *
1724      * @return a {@link BluetoothAddress} containing identity address and identity address type. If
1725      *     Bluetooth is not enabled or identity address type is not available, it will return a
1726      *     {@link BluetoothAddress} containing {@link #ADDRESS_TYPE_UNKNOWN} device for the identity
1727      *     address type.
1728      */
1729     @FlaggedApi(Flags.FLAG_IDENTITY_ADDRESS_TYPE_API)
1730     @RequiresBluetoothConnectPermission
1731     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
1732     @NonNull
getIdentityAddressWithType()1733     public BluetoothAddress getIdentityAddressWithType() {
1734         if (DBG) log("getIdentityAddressWithType()");
1735         final IBluetooth service = getService();
1736         if (service == null || !isBluetoothEnabled()) {
1737             Log.e(TAG, "BT not enabled. Cannot get identity address with type");
1738         } else {
1739             try {
1740                 return service.getIdentityAddressWithType(mAddress);
1741             } catch (RemoteException e) {
1742                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
1743             }
1744         }
1745         return new BluetoothAddress(null, BluetoothDevice.ADDRESS_TYPE_UNKNOWN);
1746     }
1747 
1748     /**
1749      * Get the friendly Bluetooth name of the remote device.
1750      *
1751      * <p>The local adapter will automatically retrieve remote names when performing a device scan,
1752      * and will cache them. This method just returns the name for this device from the cache.
1753      *
1754      * @return the Bluetooth name, or null if there was a problem.
1755      */
1756     @RequiresLegacyBluetoothPermission
1757     @RequiresBluetoothConnectPermission
1758     @RequiresPermission(BLUETOOTH_CONNECT)
getName()1759     public String getName() {
1760         if (DBG) log("getName()");
1761         final IBluetooth service = getService();
1762         if (service == null || !isBluetoothEnabled()) {
1763             Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
1764             if (DBG) log(Log.getStackTraceString(new Throwable()));
1765         } else {
1766             try {
1767                 String name = service.getRemoteName(this, mAttributionSource);
1768                 if (name != null) {
1769                     // remove whitespace characters from the name
1770                     return name.replace('\t', ' ').replace('\n', ' ').replace('\r', ' ');
1771                 }
1772             } catch (RemoteException e) {
1773                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
1774             }
1775         }
1776         return null;
1777     }
1778 
1779     /**
1780      * Get the Bluetooth device type of the remote device.
1781      *
1782      * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} {@link
1783      *     #DEVICE_TYPE_DUAL}. {@link #DEVICE_TYPE_UNKNOWN} if it's not available
1784      */
1785     @RequiresLegacyBluetoothPermission
1786     @RequiresBluetoothConnectPermission
1787     @RequiresPermission(BLUETOOTH_CONNECT)
getType()1788     public int getType() {
1789         if (DBG) log("getType()");
1790         final IBluetooth service = getService();
1791         if (service == null || !isBluetoothEnabled()) {
1792             Log.e(TAG, "BT not enabled. Cannot get Remote Device type");
1793             if (DBG) log(Log.getStackTraceString(new Throwable()));
1794         } else {
1795             try {
1796                 return service.getRemoteType(this, mAttributionSource);
1797             } catch (RemoteException e) {
1798                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
1799             }
1800         }
1801         return DEVICE_TYPE_UNKNOWN;
1802     }
1803 
1804     /**
1805      * Get the locally modifiable name (alias) of the remote Bluetooth device.
1806      *
1807      * @return the Bluetooth alias, the friendly device name if no alias, or null if there was a
1808      *     problem
1809      */
1810     @Nullable
1811     @RequiresLegacyBluetoothPermission
1812     @RequiresBluetoothConnectPermission
1813     @RequiresPermission(BLUETOOTH_CONNECT)
getAlias()1814     public String getAlias() {
1815         if (DBG) log("getAlias()");
1816         final IBluetooth service = getService();
1817         if (service == null || !isBluetoothEnabled()) {
1818             Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias");
1819             if (DBG) log(Log.getStackTraceString(new Throwable()));
1820         } else {
1821             try {
1822                 String alias = service.getRemoteAlias(this, mAttributionSource);
1823                 if (alias == null) {
1824                     return getName();
1825                 }
1826                 return alias.replace('\t', ' ').replace('\n', ' ').replace('\r', ' ');
1827             } catch (RemoteException e) {
1828                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
1829             }
1830         }
1831         return null;
1832     }
1833 
1834     /** @hide */
1835     @Retention(RetentionPolicy.SOURCE)
1836     @IntDef(
1837             value = {
1838                 BluetoothStatusCodes.SUCCESS,
1839                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
1840                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
1841                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
1842                 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED
1843             })
1844     public @interface SetAliasReturnValues {}
1845 
1846     /**
1847      * Sets the locally modifiable name (alias) of the remote Bluetooth device. This method
1848      * overwrites the previously stored alias. The new alias is saved in local storage so that the
1849      * change is preserved over power cycles.
1850      *
1851      * <p>This method requires the calling app to have the {@link
1852      * android.Manifest.permission#BLUETOOTH_CONNECT} permission. Additionally, an app must either
1853      * have the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} or be associated with the
1854      * Companion Device manager (see {@link android.companion.CompanionDeviceManager#associate(
1855      * AssociationRequest, android.companion.CompanionDeviceManager.Callback, Handler)})
1856      *
1857      * @param alias is the new locally modifiable name for the remote Bluetooth device which must be
1858      *     the empty string. If null, we clear the alias.
1859      * @return whether the alias was successfully changed
1860      * @throws IllegalArgumentException if the alias is the empty string
1861      */
1862     @RequiresLegacyBluetoothPermission
1863     @RequiresBluetoothConnectPermission
1864     @RequiresPermission(
1865             allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
1866             conditional = true)
setAlias(@ullable String alias)1867     public @SetAliasReturnValues int setAlias(@Nullable String alias) {
1868         if (alias != null && alias.isEmpty()) {
1869             throw new IllegalArgumentException("alias cannot be the empty string");
1870         }
1871         if (DBG) log("setAlias(" + alias + ")");
1872         final IBluetooth service = getService();
1873         if (service == null || !isBluetoothEnabled()) {
1874             Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
1875             if (DBG) log(Log.getStackTraceString(new Throwable()));
1876         } else {
1877             try {
1878                 return service.setRemoteAlias(this, alias, mAttributionSource);
1879             } catch (RemoteException e) {
1880                 Log.e(TAG, "", e);
1881             }
1882         }
1883         return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
1884     }
1885 
1886     /**
1887      * Get the most recent identified battery level of this Bluetooth device
1888      *
1889      * @return Battery level in percents from 0 to 100, {@link #BATTERY_LEVEL_BLUETOOTH_OFF} if
1890      *     Bluetooth is disabled or {@link #BATTERY_LEVEL_UNKNOWN} if device is disconnected, or
1891      *     does not have any battery reporting service, or return value is invalid
1892      * @hide
1893      */
1894     @SystemApi
1895     @RequiresLegacyBluetoothPermission
1896     @RequiresBluetoothConnectPermission
1897     @RequiresPermission(BLUETOOTH_CONNECT)
getBatteryLevel()1898     public @IntRange(from = -100, to = 100) int getBatteryLevel() {
1899         if (DBG) log("getBatteryLevel()");
1900         final IBluetooth service = getService();
1901         if (service == null || !isBluetoothEnabled()) {
1902             Log.e(TAG, "Bluetooth disabled. Cannot get remote device battery level");
1903             if (DBG) log(Log.getStackTraceString(new Throwable()));
1904         } else {
1905             try {
1906                 return service.getBatteryLevel(this, mAttributionSource);
1907             } catch (RemoteException e) {
1908                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
1909             }
1910         }
1911         return BATTERY_LEVEL_BLUETOOTH_OFF;
1912     }
1913 
1914     /**
1915      * Start the bonding (pairing) process with the remote device.
1916      *
1917      * <p>This is an asynchronous call, it will return immediately. Register for {@link
1918      * #ACTION_BOND_STATE_CHANGED} intents to be notified when the bonding process completes, and
1919      * its result.
1920      *
1921      * <p>Android system services will handle the necessary user interactions to confirm and
1922      * complete the bonding process.
1923      *
1924      * @return false on immediate error, true if bonding will begin
1925      */
1926     @RequiresLegacyBluetoothAdminPermission
1927     @RequiresBluetoothConnectPermission
1928     @RequiresPermission(BLUETOOTH_CONNECT)
createBond()1929     public boolean createBond() {
1930         return createBond(TRANSPORT_AUTO);
1931     }
1932 
1933     /**
1934      * Start the bonding (pairing) process with the remote device using the specified transport.
1935      *
1936      * <p>This is an asynchronous call, it will return immediately. Register for {@link
1937      * #ACTION_BOND_STATE_CHANGED} intents to be notified when the bonding process completes, and
1938      * its result.
1939      *
1940      * <p>Android system services will handle the necessary user interactions to confirm and
1941      * complete the bonding process.
1942      *
1943      * @param transport The transport to use for the pairing procedure.
1944      * @return false on immediate error, true if bonding will begin
1945      * @throws IllegalArgumentException if an invalid transport was specified
1946      * @hide
1947      */
1948     @SystemApi
1949     @RequiresLegacyBluetoothAdminPermission
1950     @RequiresBluetoothConnectPermission
1951     @RequiresPermission(BLUETOOTH_CONNECT)
createBond(int transport)1952     public boolean createBond(int transport) {
1953         if (DBG) log("createBond()");
1954         final IBluetooth service = getService();
1955         if (service == null || !isBluetoothEnabled()) {
1956             Log.w(TAG, "BT not enabled, createBond failed");
1957             if (DBG) log(Log.getStackTraceString(new Throwable()));
1958         } else if (NULL_MAC_ADDRESS.equals(mAddress)) {
1959             Log.e(TAG, "Unable to create bond, invalid address " + mAddress);
1960         } else {
1961             try {
1962                 return service.createBond(this, transport, mAttributionSource);
1963             } catch (RemoteException e) {
1964                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
1965             }
1966         }
1967         return false;
1968     }
1969 
1970     /**
1971      * Start the bonding (pairing) process with the remote device using the Out Of Band mechanism.
1972      *
1973      * <p>This is an asynchronous call, it will return immediately. Register for {@link
1974      * #ACTION_BOND_STATE_CHANGED} intents to be notified when the bonding process completes, and
1975      * its result.
1976      *
1977      * <p>Android system services will handle the necessary user interactions to confirm and
1978      * complete the bonding process.
1979      *
1980      * <p>There are two possible versions of OOB Data. This data can come in as P192 or P256. This
1981      * is a reference to the cryptography used to generate the key. The caller may pass one or both.
1982      * If both types of data are passed, then the P256 data will be preferred, and thus used.
1983      *
1984      * @param transport - Transport to use
1985      * @param remoteP192Data - Out Of Band data (P192) or null
1986      * @param remoteP256Data - Out Of Band data (P256) or null
1987      * @return false on immediate error, true if bonding will begin
1988      * @hide
1989      */
1990     @SystemApi
1991     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
createBondOutOfBand( int transport, @Nullable OobData remoteP192Data, @Nullable OobData remoteP256Data)1992     public boolean createBondOutOfBand(
1993             int transport, @Nullable OobData remoteP192Data, @Nullable OobData remoteP256Data) {
1994         if (DBG) log("createBondOutOfBand()");
1995         final IBluetooth service = getService();
1996 
1997         if (remoteP192Data == null && remoteP256Data == null) {
1998             throw new IllegalArgumentException(
1999                     "One or both arguments for the OOB data types are required to not be null. "
2000                         + " Please use createBond() instead if you do not have OOB data to pass.");
2001         }
2002         if (service == null || !isBluetoothEnabled()) {
2003             Log.w(TAG, "BT not enabled, createBondOutOfBand failed");
2004             if (DBG) log(Log.getStackTraceString(new Throwable()));
2005         } else if (NULL_MAC_ADDRESS.equals(mAddress)) {
2006             Log.e(TAG, "Unable to create bond Out of Band, invalid address " + mAddress);
2007         } else {
2008             try {
2009                 return service.createBondOutOfBand(
2010                         this, transport, remoteP192Data, remoteP256Data, mAttributionSource);
2011             } catch (RemoteException e) {
2012                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2013             }
2014         }
2015         return false;
2016     }
2017 
2018     /**
2019      * Gets whether bonding was initiated locally
2020      *
2021      * @return true if bonding is initiated locally, false otherwise
2022      * @hide
2023      */
2024     @SystemApi
2025     @RequiresLegacyBluetoothPermission
2026     @RequiresBluetoothConnectPermission
2027     @RequiresPermission(BLUETOOTH_CONNECT)
isBondingInitiatedLocally()2028     public boolean isBondingInitiatedLocally() {
2029         if (DBG) log("isBondingInitiatedLocally()");
2030         final IBluetooth service = getService();
2031         if (service == null || !isBluetoothEnabled()) {
2032             Log.w(TAG, "BT not enabled, isBondingInitiatedLocally failed");
2033             if (DBG) log(Log.getStackTraceString(new Throwable()));
2034         } else {
2035             try {
2036                 return service.isBondingInitiatedLocally(this, mAttributionSource);
2037             } catch (RemoteException e) {
2038                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2039             }
2040         }
2041         return false;
2042     }
2043 
2044     /**
2045      * Cancel an in-progress bonding request started with {@link #createBond}.
2046      *
2047      * @return true on success, false on error
2048      * @hide
2049      */
2050     @SystemApi
2051     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
cancelBondProcess()2052     public boolean cancelBondProcess() {
2053         if (DBG) log("cancelBondProcess()");
2054         final IBluetooth service = getService();
2055         if (service == null || !isBluetoothEnabled()) {
2056             Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
2057             if (DBG) log(Log.getStackTraceString(new Throwable()));
2058         } else {
2059             Log.i(
2060                     TAG,
2061                     "cancelBondProcess() for"
2062                             + (" device " + this)
2063                             + (" called by pid: " + Process.myPid())
2064                             + (" tid: " + Process.myTid()));
2065             try {
2066                 return service.cancelBondProcess(this, mAttributionSource);
2067             } catch (RemoteException e) {
2068                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2069             }
2070         }
2071         return false;
2072     }
2073 
2074     /**
2075      * Remove bond (pairing) with the remote device.
2076      *
2077      * <p>Delete the link key associated with the remote device, and immediately terminate
2078      * connections to that device that require authentication and encryption.
2079      *
2080      * @return true on success, false on error
2081      * @hide
2082      */
2083     @SystemApi
2084     @RequiresPermission(BLUETOOTH_CONNECT)
removeBond()2085     public boolean removeBond() {
2086         if (DBG) log("removeBond()");
2087         final IBluetooth service = getService();
2088         if (service == null || !isBluetoothEnabled()) {
2089             Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
2090             if (DBG) log(Log.getStackTraceString(new Throwable()));
2091         } else {
2092             Log.i(
2093                     TAG,
2094                     "removeBond() for"
2095                             + (" device " + this)
2096                             + (" called by pid: " + Process.myPid())
2097                             + (" tid: " + Process.myTid()));
2098             try {
2099                 return service.removeBond(this, mAttributionSource);
2100             } catch (RemoteException e) {
2101                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2102             }
2103         }
2104         return false;
2105     }
2106 
2107     /**
2108      * There are several instances of IpcDataCache used in this class. BluetoothCache wraps up the
2109      * common code. All caches are created with a maximum of eight entries, and the key is in the
2110      * bluetooth module. The name is set to the api.
2111      */
2112     private static class BluetoothCache<Q, R> extends IpcDataCache<Q, R> {
BluetoothCache(String api, IpcDataCache.QueryHandler query)2113         BluetoothCache(String api, IpcDataCache.QueryHandler query) {
2114             super(8, IpcDataCache.MODULE_BLUETOOTH, api, api, query);
2115         }
2116     }
2117     ;
2118 
2119     /**
2120      * Invalidate a bluetooth cache. This method is just a short-hand wrapper that enforces the
2121      * bluetooth module.
2122      */
invalidateCache(@onNull String api)2123     private static void invalidateCache(@NonNull String api) {
2124         IpcDataCache.invalidateCache(IpcDataCache.MODULE_BLUETOOTH, api);
2125     }
2126 
2127     private static final IpcDataCache.QueryHandler<
2128                     Pair<IBluetooth, Pair<AttributionSource, BluetoothDevice>>, Integer>
2129             sBluetoothBondQuery =
2130                     new IpcDataCache.QueryHandler<>() {
2131                         @RequiresLegacyBluetoothPermission
2132                         @RequiresBluetoothConnectPermission
2133                         @RequiresPermission(BLUETOOTH_CONNECT)
2134                         @Override
2135                         public Integer apply(
2136                                 Pair<IBluetooth, Pair<AttributionSource, BluetoothDevice>>
2137                                         pairQuery) {
2138                             IBluetooth service = pairQuery.first;
2139                             AttributionSource source = pairQuery.second.first;
2140                             BluetoothDevice device = pairQuery.second.second;
2141                             if (DBG) {
2142                                 log("getBondState(" + device + ") uncached");
2143                             }
2144                             try {
2145                                 return service.getBondState(device, source);
2146                             } catch (RemoteException e) {
2147                                 throw e.rethrowAsRuntimeException();
2148                             }
2149                         }
2150                     };
2151 
2152     private static final String GET_BOND_STATE_API = "BluetoothDevice_getBondState";
2153 
2154     private static final BluetoothCache<
2155                     Pair<IBluetooth, Pair<AttributionSource, BluetoothDevice>>, Integer>
2156             sBluetoothBondCache = new BluetoothCache<>(GET_BOND_STATE_API, sBluetoothBondQuery);
2157 
2158     /** @hide */
disableBluetoothGetBondStateCache()2159     public void disableBluetoothGetBondStateCache() {
2160         sBluetoothBondCache.disableForCurrentProcess();
2161     }
2162 
2163     /** @hide */
invalidateBluetoothGetBondStateCache()2164     public static void invalidateBluetoothGetBondStateCache() {
2165         invalidateCache(GET_BOND_STATE_API);
2166     }
2167 
2168     /**
2169      * Get the bond state of the remote device.
2170      *
2171      * <p>Possible values for the bond state are: {@link #BOND_NONE}, {@link #BOND_BONDING}, {@link
2172      * #BOND_BONDED}.
2173      *
2174      * @return the bond state
2175      */
2176     @RequiresLegacyBluetoothPermission
2177     @RequiresBluetoothConnectPermission
2178     @RequiresPermission(BLUETOOTH_CONNECT)
2179     @SuppressLint("AndroidFrameworkRequiresPermission") // IpcDataCache prevent lint enforcement
getBondState()2180     public int getBondState() {
2181         if (DBG) log("getBondState(" + this + ")");
2182         final IBluetooth service = getService();
2183         if (service == null) {
2184             Log.e(TAG, "BT not enabled. Cannot get bond state");
2185             if (DBG) log(Log.getStackTraceString(new Throwable()));
2186         } else {
2187             try {
2188                 return sBluetoothBondCache.query(
2189                         new Pair<>(service, new Pair<>(mAttributionSource, BluetoothDevice.this)));
2190             } catch (RuntimeException e) {
2191                 if (!(e.getCause() instanceof RemoteException)) {
2192                     throw e;
2193                 }
2194                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2195             }
2196         }
2197         return BOND_NONE;
2198     }
2199 
2200     /**
2201      * Checks whether this bluetooth device is associated with CDM and meets the criteria to skip
2202      * the bluetooth pairing dialog because it has been already consented by the CDM prompt.
2203      *
2204      * @return true if we can bond without the dialog, false otherwise
2205      * @hide
2206      */
2207     @SystemApi
2208     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
canBondWithoutDialog()2209     public boolean canBondWithoutDialog() {
2210         if (DBG) log("canBondWithoutDialog, device: " + this);
2211         final IBluetooth service = getService();
2212         if (service == null || !isBluetoothEnabled()) {
2213             Log.e(TAG, "BT not enabled. Cannot check if we can skip pairing dialog");
2214             if (DBG) log(Log.getStackTraceString(new Throwable()));
2215         } else {
2216             try {
2217                 return service.canBondWithoutDialog(this, mAttributionSource);
2218             } catch (RemoteException e) {
2219                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2220             }
2221         }
2222         return false;
2223     }
2224 
2225     /**
2226      * Gets the package name of the application that initiate bonding with this device
2227      *
2228      * @return package name of the application, or null of no application initiate bonding with this
2229      *     device
2230      * @hide
2231      */
2232     @SystemApi
2233     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getPackageNameOfBondingApplication()2234     public @Nullable String getPackageNameOfBondingApplication() {
2235         if (DBG) log("getPackageNameOfBondingApplication()");
2236         final IBluetooth service = getService();
2237         if (service == null || !isBluetoothEnabled()) {
2238             Log.w(TAG, "BT not enabled, getPackageNameOfBondingApplication failed");
2239             if (DBG) log(Log.getStackTraceString(new Throwable()));
2240         } else {
2241             try {
2242                 return service.getPackageNameOfBondingApplication(this, mAttributionSource);
2243             } catch (RemoteException e) {
2244                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2245             }
2246         }
2247         return null;
2248     }
2249 
2250     /** @hide */
2251     @Retention(RetentionPolicy.SOURCE)
2252     @IntDef(
2253             value = {
2254                 BluetoothStatusCodes.SUCCESS,
2255                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
2256                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
2257                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
2258                 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED
2259             })
2260     public @interface ConnectionReturnValues {}
2261 
2262     /**
2263      * Connects all user enabled and supported bluetooth profiles between the local and remote
2264      * device. If no profiles are user enabled (e.g. first connection), we connect all supported
2265      * profiles. If the device is not already connected, this will page the device before initiating
2266      * profile connections. Connection is asynchronous and you should listen to each profile's
2267      * broadcast intent ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful.
2268      * For example, to verify a2dp is connected, you would listen for {@link
2269      * BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED}
2270      *
2271      * @return whether the messages were successfully sent to try to connect all profiles
2272      * @throws IllegalArgumentException if the device address is invalid
2273      * @hide
2274      */
2275     @SystemApi
2276     @RequiresBluetoothConnectPermission
2277     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED, MODIFY_PHONE_STATE})
connect()2278     public @ConnectionReturnValues int connect() {
2279         if (DBG) log("connect()");
2280         if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) {
2281             throw new IllegalArgumentException("device cannot have an invalid address");
2282         }
2283         final IBluetooth service = getService();
2284         if (service == null || !isBluetoothEnabled()) {
2285             Log.e(TAG, "BT not enabled. Cannot connect to remote device.");
2286             if (DBG) log(Log.getStackTraceString(new Throwable()));
2287         } else {
2288             try {
2289                 return service.connectAllEnabledProfiles(this, mAttributionSource);
2290             } catch (RemoteException e) {
2291                 Log.e(TAG, "", e);
2292             }
2293         }
2294         return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
2295     }
2296 
2297     /**
2298      * Disconnects all connected bluetooth profiles between the local and remote device.
2299      * Disconnection is asynchronous, so you should listen to each profile's broadcast intent
2300      * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example,
2301      * to verify a2dp is disconnected, you would listen for {@link
2302      * BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED}. Once all profiles have disconnected, the ACL
2303      * link should come down and {@link #ACTION_ACL_DISCONNECTED} should be broadcast.
2304      *
2305      * <p>In the rare event that one or more profiles fail to disconnect, call this method again to
2306      * send another request to disconnect each connected profile.
2307      *
2308      * @return whether the messages were successfully sent to try to disconnect all profiles
2309      * @throws IllegalArgumentException if the device address is invalid
2310      * @hide
2311      */
2312     @SystemApi
2313     @RequiresBluetoothConnectPermission
2314     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
disconnect()2315     public @ConnectionReturnValues int disconnect() {
2316         if (DBG) log("disconnect()");
2317         if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) {
2318             throw new IllegalArgumentException("device cannot have an invalid address");
2319         }
2320         final IBluetooth service = getService();
2321         if (service == null || !isBluetoothEnabled()) {
2322             Log.e(TAG, "BT not enabled. Cannot disconnect to remote device.");
2323             if (DBG) log(Log.getStackTraceString(new Throwable()));
2324         } else {
2325             try {
2326                 return service.disconnectAllEnabledProfiles(this, mAttributionSource);
2327             } catch (RemoteException e) {
2328                 Log.e(TAG, "", e);
2329             }
2330         }
2331         return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
2332     }
2333 
2334     /**
2335      * Returns whether there is an open connection to this device.
2336      *
2337      * @return True if there is at least one open connection to this device.
2338      * @hide
2339      */
2340     @SystemApi
2341     @RequiresLegacyBluetoothPermission
2342     @RequiresBluetoothConnectPermission
2343     @RequiresPermission(BLUETOOTH_CONNECT)
isConnected()2344     public boolean isConnected() {
2345         if (DBG) log("isConnected()");
2346         final IBluetooth service = getService();
2347         if (service == null || !isBluetoothEnabled()) {
2348             Log.w(TAG, "Proxy not attached to service");
2349             if (DBG) log(Log.getStackTraceString(new Throwable()));
2350         } else {
2351             try {
2352                 return service.getConnectionState(this, mAttributionSource)
2353                         != CONNECTION_STATE_DISCONNECTED;
2354             } catch (RemoteException e) {
2355                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2356             }
2357         }
2358         // BT is not enabled, we cannot be connected.
2359         return false;
2360     }
2361 
2362     /**
2363      * Returns the ACL connection handle associated with an open connection to this device on the
2364      * given transport.
2365      *
2366      * <p>This handle is a unique identifier for the connection while it remains active. Refer to
2367      * the Bluetooth Core Specification Version 5.4 Vol 4 Part E Section 5.3.1 Controller Handles
2368      * for details.
2369      *
2370      * @return the ACL handle, or {@link BluetoothDevice#ERROR} if no connection currently exists on
2371      *     the given transport.
2372      * @hide
2373      */
2374     @SystemApi
2375     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getConnectionHandle(@ransport int transport)2376     public int getConnectionHandle(@Transport int transport) {
2377         if (DBG) {
2378             log("getConnectionHandle()");
2379         }
2380         final IBluetooth service = getService();
2381         if (service == null || !isBluetoothEnabled()) {
2382             Log.w(TAG, "Proxy not attached to service");
2383             if (DBG) {
2384                 log(Log.getStackTraceString(new Throwable()));
2385             }
2386         } else {
2387             try {
2388                 return service.getConnectionHandle(this, transport, mAttributionSource);
2389             } catch (RemoteException e) {
2390                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2391             }
2392         }
2393         // BT is not enabled, we cannot be connected.
2394         return BluetoothDevice.ERROR;
2395     }
2396 
2397     /**
2398      * Returns whether there is an open connection to this device that has been encrypted.
2399      *
2400      * @return True if there is at least one encrypted connection to this device.
2401      * @hide
2402      */
2403     @SystemApi
2404     @RequiresLegacyBluetoothPermission
2405     @RequiresBluetoothConnectPermission
2406     @RequiresPermission(BLUETOOTH_CONNECT)
isEncrypted()2407     public boolean isEncrypted() {
2408         if (DBG) log("isEncrypted()");
2409         final IBluetooth service = getService();
2410         if (service == null || !isBluetoothEnabled()) {
2411             Log.w(TAG, "Proxy not attached to service");
2412             if (DBG) log(Log.getStackTraceString(new Throwable()));
2413         } else {
2414             try {
2415                 return service.getConnectionState(this, mAttributionSource)
2416                         > CONNECTION_STATE_CONNECTED;
2417             } catch (RemoteException e) {
2418                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2419             }
2420         }
2421         // BT is not enabled, we cannot be encrypted.
2422         return false;
2423     }
2424 
2425     /**
2426      * Get the Bluetooth class of the remote device.
2427      *
2428      * @return Bluetooth class object, or null on error
2429      */
2430     @RequiresLegacyBluetoothPermission
2431     @RequiresBluetoothConnectPermission
2432     @RequiresPermission(BLUETOOTH_CONNECT)
getBluetoothClass()2433     public BluetoothClass getBluetoothClass() {
2434         if (DBG) log("getBluetoothClass()");
2435         final IBluetooth service = getService();
2436         if (service == null || !isBluetoothEnabled()) {
2437             Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
2438             if (DBG) log(Log.getStackTraceString(new Throwable()));
2439         } else {
2440             try {
2441                 int classInt = service.getRemoteClass(this, mAttributionSource);
2442                 if (classInt == BluetoothClass.ERROR) return null;
2443                 return new BluetoothClass(classInt);
2444             } catch (RemoteException e) {
2445                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2446             }
2447         }
2448         return null;
2449     }
2450 
2451     /**
2452      * Returns the supported features (UUIDs) of the remote device.
2453      *
2454      * <p>This method does not start a service discovery procedure to retrieve the UUIDs from the
2455      * remote device. Instead, the local cached copy of the service UUIDs are returned.
2456      *
2457      * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired.
2458      *
2459      * @return the supported features (UUIDs) of the remote device, or null on error
2460      */
2461     @RequiresLegacyBluetoothPermission
2462     @RequiresBluetoothConnectPermission
2463     @RequiresPermission(BLUETOOTH_CONNECT)
getUuids()2464     public ParcelUuid[] getUuids() {
2465         if (DBG) log("getUuids()");
2466         final IBluetooth service = getService();
2467         if (service == null || !isBluetoothEnabled()) {
2468             Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
2469             if (DBG) log(Log.getStackTraceString(new Throwable()));
2470         } else {
2471             try {
2472                 List<ParcelUuid> parcels = service.getRemoteUuids(this, mAttributionSource);
2473                 return parcels != null ? parcels.toArray(new ParcelUuid[parcels.size()]) : null;
2474             } catch (RemoteException e) {
2475                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2476             }
2477         }
2478         return null;
2479     }
2480 
2481     /**
2482      * Perform a service discovery on the remote device to get the UUIDs supported.
2483      *
2484      * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent, with the UUIDs supported
2485      * by the remote end. If there is an error in getting the SDP records or if the process takes a
2486      * long time, or the device is bonding and we have its UUIDs cached, {@link #ACTION_UUID} intent
2487      * is sent with the UUIDs that is currently present in the cache. Clients should use the {@link
2488      * #getUuids} to get UUIDs if service discovery is not to be performed. If there is an ongoing
2489      * bonding process, service discovery or device inquiry, the request will be queued.
2490      *
2491      * @return False if the check fails, True if the process of initiating an ACL connection to the
2492      *     remote device was started or cached UUIDs will be broadcast.
2493      */
2494     @RequiresLegacyBluetoothPermission
2495     @RequiresBluetoothConnectPermission
2496     @RequiresPermission(BLUETOOTH_CONNECT)
2497     @SuppressLint("AndroidFrameworkRequiresPermission") // See fetchUuidsWithSdp(int) for reason
fetchUuidsWithSdp()2498     public boolean fetchUuidsWithSdp() {
2499         return fetchUuidsWithSdp(TRANSPORT_AUTO);
2500     }
2501 
2502     /**
2503      * Perform a service discovery on the remote device to get the UUIDs supported with the specific
2504      * transport.
2505      *
2506      * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent, with the UUIDs supported
2507      * by the remote end. If there is an error in getting the SDP or GATT records or if the process
2508      * takes a long time, or the device is bonding and we have its UUIDs cached, {@link
2509      * #ACTION_UUID} intent is sent with the UUIDs that is currently present in the cache. Clients
2510      * should use the {@link #getUuids} to get UUIDs if service discovery is not to be performed. If
2511      * there is an ongoing bonding process, service discovery or device inquiry, the request will be
2512      * queued.
2513      *
2514      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission only when
2515      * {@code transport} is not {@code #TRANSPORT_AUTO}.
2516      *
2517      * <p>The {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission is always enforced.
2518      *
2519      * @param transport - provide type of transport (e.g. LE or Classic).
2520      * @return False if the check fails, True if the process of initiating an ACL connection to the
2521      *     remote device was started or cached UUIDs will be broadcast with the specific transport.
2522      * @hide
2523      */
2524     @SystemApi
2525     @RequiresPermission(
2526             allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
2527             conditional = true)
fetchUuidsWithSdp(@ransport int transport)2528     public boolean fetchUuidsWithSdp(@Transport int transport) {
2529         if (DBG) log("fetchUuidsWithSdp()");
2530         final IBluetooth service = getService();
2531         if (service == null || !isBluetoothEnabled()) {
2532             Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
2533             if (DBG) log(Log.getStackTraceString(new Throwable()));
2534         } else {
2535             try {
2536                 return service.fetchRemoteUuids(this, transport, mAttributionSource);
2537             } catch (RemoteException e) {
2538                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2539             }
2540         }
2541         return false;
2542     }
2543 
2544     /**
2545      * Perform a service discovery on the remote device to get the SDP records associated with the
2546      * specified UUID.
2547      *
2548      * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent, with the SDP
2549      * records found on the remote end. If there is an error in getting the SDP records or if the
2550      * process takes a long time, {@link #ACTION_SDP_RECORD} intent is sent with an status value in
2551      * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0. Detailed status error codes can be found
2552      * by members of the Bluetooth package in the AbstractionLayer class.
2553      *
2554      * <p>The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}. The object
2555      * type will match one of the SdpXxxRecord types, depending on the UUID searched for.
2556      *
2557      * @return False if the check fails, True if the process of initiating an ACL connection to the
2558      *     remote device was started.
2559      */
2560     /** @hide */
2561     @RequiresLegacyBluetoothPermission
2562     @RequiresBluetoothConnectPermission
2563     @RequiresPermission(BLUETOOTH_CONNECT)
sdpSearch(ParcelUuid uuid)2564     public boolean sdpSearch(ParcelUuid uuid) {
2565         if (DBG) log("sdpSearch()");
2566         final IBluetooth service = getService();
2567         if (service == null || !isBluetoothEnabled()) {
2568             Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
2569             if (DBG) log(Log.getStackTraceString(new Throwable()));
2570         } else {
2571             try {
2572                 return service.sdpSearch(this, uuid, mAttributionSource);
2573             } catch (RemoteException e) {
2574                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2575             }
2576         }
2577         return false;
2578     }
2579 
2580     /**
2581      * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
2582      *
2583      * @return true pin has been set false for error
2584      */
2585     @RequiresLegacyBluetoothAdminPermission
2586     @RequiresBluetoothConnectPermission
2587     @RequiresPermission(BLUETOOTH_CONNECT)
setPin(byte[] pin)2588     public boolean setPin(byte[] pin) {
2589         if (DBG) log("setPin()");
2590         final IBluetooth service = getService();
2591         if (service == null || !isBluetoothEnabled()) {
2592             Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
2593             if (DBG) log(Log.getStackTraceString(new Throwable()));
2594         } else {
2595             try {
2596                 return service.setPin(this, true, pin.length, pin, mAttributionSource);
2597             } catch (RemoteException e) {
2598                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2599             }
2600         }
2601         return false;
2602     }
2603 
2604     /**
2605      * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
2606      *
2607      * @return true pin has been set false for error
2608      * @hide
2609      */
2610     @SystemApi
2611     @RequiresLegacyBluetoothAdminPermission
2612     @RequiresBluetoothConnectPermission
2613     @RequiresPermission(BLUETOOTH_CONNECT)
setPin(@onNull String pin)2614     public boolean setPin(@NonNull String pin) {
2615         byte[] pinBytes = convertPinToBytes(pin);
2616         if (pinBytes == null) {
2617             return false;
2618         }
2619         return setPin(pinBytes);
2620     }
2621 
2622     /**
2623      * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
2624      *
2625      * @return true confirmation has been sent out false for error
2626      */
2627     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
setPairingConfirmation(boolean confirm)2628     public boolean setPairingConfirmation(boolean confirm) {
2629         if (DBG) log("setPairingConfirmation()");
2630         final IBluetooth service = getService();
2631         if (service == null || !isBluetoothEnabled()) {
2632             Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
2633             if (DBG) log(Log.getStackTraceString(new Throwable()));
2634         } else {
2635             try {
2636                 return service.setPairingConfirmation(this, confirm, mAttributionSource);
2637             } catch (RemoteException e) {
2638                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2639             }
2640         }
2641         return false;
2642     }
2643 
isBluetoothEnabled()2644     boolean isBluetoothEnabled() {
2645         boolean ret = false;
2646         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2647         if (adapter != null && adapter.isEnabled()) {
2648             ret = true;
2649         }
2650         return ret;
2651     }
2652 
2653     /**
2654      * Gets whether the phonebook access is allowed for this bluetooth device
2655      *
2656      * @return Whether the phonebook access is allowed to this device. Can be {@link
2657      *     #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
2658      * @hide
2659      */
2660     @SystemApi
2661     @RequiresLegacyBluetoothPermission
2662     @RequiresBluetoothConnectPermission
2663     @RequiresPermission(BLUETOOTH_CONNECT)
getPhonebookAccessPermission()2664     public @AccessPermission int getPhonebookAccessPermission() {
2665         if (DBG) log("getPhonebookAccessPermission()");
2666         final IBluetooth service = getService();
2667         if (service == null || !isBluetoothEnabled()) {
2668             Log.w(TAG, "Proxy not attached to service");
2669             if (DBG) log(Log.getStackTraceString(new Throwable()));
2670         } else {
2671             try {
2672                 return service.getPhonebookAccessPermission(this, mAttributionSource);
2673             } catch (RemoteException e) {
2674                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2675             }
2676         }
2677         return ACCESS_UNKNOWN;
2678     }
2679 
2680     /**
2681      * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not be routed to the
2682      * {@link BluetoothDevice} if set to {@code true}.
2683      *
2684      * <p>When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice} is
2685      * an active device (for A2DP or HFP), the active device for that profile will be set to null.
2686      * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP active device is
2687      * null, the {@link BluetoothDevice} will be set as the active device for that profile. If the
2688      * {@link BluetoothDevice} is disconnected, it exits silence mode. If the {@link
2689      * BluetoothDevice} is set as the active device for A2DP or HFP, while silence mode is enabled,
2690      * then the device will exit silence mode. If the {@link BluetoothDevice} is in silence mode,
2691      * AVRCP position change event and HFP AG indicators will be disabled. If the {@link
2692      * BluetoothDevice} is not connected with A2DP or HFP, it cannot enter silence mode.
2693      *
2694      * @param silence true to enter silence mode, false to exit
2695      * @return true on success, false on error.
2696      * @throws IllegalStateException if Bluetooth is not turned ON.
2697      * @hide
2698      */
2699     @SystemApi
2700     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
setSilenceMode(boolean silence)2701     public boolean setSilenceMode(boolean silence) {
2702         if (DBG) log("setSilenceMode()");
2703         final IBluetooth service = getService();
2704         if (service == null || !isBluetoothEnabled()) {
2705             throw new IllegalStateException("Bluetooth is not turned ON");
2706         } else {
2707             try {
2708                 return service.setSilenceMode(this, silence, mAttributionSource);
2709             } catch (RemoteException e) {
2710                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2711             }
2712         }
2713         return false;
2714     }
2715 
2716     /**
2717      * Check whether the {@link BluetoothDevice} is in silence mode
2718      *
2719      * @return true on device in silence mode, otherwise false.
2720      * @throws IllegalStateException if Bluetooth is not turned ON.
2721      * @hide
2722      */
2723     @SystemApi
2724     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
isInSilenceMode()2725     public boolean isInSilenceMode() {
2726         if (DBG) log("isInSilenceMode()");
2727         final IBluetooth service = getService();
2728         if (service == null || !isBluetoothEnabled()) {
2729             throw new IllegalStateException("Bluetooth is not turned ON");
2730         } else {
2731             try {
2732                 return service.getSilenceMode(this, mAttributionSource);
2733             } catch (RemoteException e) {
2734                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2735             }
2736         }
2737         return false;
2738     }
2739 
2740     /**
2741      * Sets whether the phonebook access is allowed to this device.
2742      *
2743      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
2744      *     #ACCESS_REJECTED}.
2745      * @return Whether the value has been successfully set.
2746      * @hide
2747      */
2748     @SystemApi
2749     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
setPhonebookAccessPermission(@ccessPermission int value)2750     public boolean setPhonebookAccessPermission(@AccessPermission int value) {
2751         if (DBG) log("setPhonebookAccessPermission()");
2752         final IBluetooth service = getService();
2753         if (service == null || !isBluetoothEnabled()) {
2754             Log.w(TAG, "Proxy not attached to service");
2755             if (DBG) log(Log.getStackTraceString(new Throwable()));
2756         } else {
2757             try {
2758                 return service.setPhonebookAccessPermission(this, value, mAttributionSource);
2759             } catch (RemoteException e) {
2760                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2761             }
2762         }
2763         return false;
2764     }
2765 
2766     /**
2767      * Gets whether message access is allowed to this bluetooth device
2768      *
2769      * @return Whether the message access is allowed to this device.
2770      * @hide
2771      */
2772     @SystemApi
2773     @RequiresLegacyBluetoothPermission
2774     @RequiresBluetoothConnectPermission
2775     @RequiresPermission(BLUETOOTH_CONNECT)
getMessageAccessPermission()2776     public @AccessPermission int getMessageAccessPermission() {
2777         if (DBG) log("getMessageAccessPermission()");
2778         final IBluetooth service = getService();
2779         if (service == null || !isBluetoothEnabled()) {
2780             Log.w(TAG, "Proxy not attached to service");
2781             if (DBG) log(Log.getStackTraceString(new Throwable()));
2782         } else {
2783             try {
2784                 return service.getMessageAccessPermission(this, mAttributionSource);
2785             } catch (RemoteException e) {
2786                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2787             }
2788         }
2789         return ACCESS_UNKNOWN;
2790     }
2791 
2792     /**
2793      * Sets whether the message access is allowed to this device.
2794      *
2795      * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded, {@link
2796      *     #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if the
2797      *     permission is not being granted.
2798      * @return Whether the value has been successfully set.
2799      * @hide
2800      */
2801     @SystemApi
2802     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
setMessageAccessPermission(@ccessPermission int value)2803     public boolean setMessageAccessPermission(@AccessPermission int value) {
2804         // Validates param value is one of the accepted constants
2805         if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) {
2806             throw new IllegalArgumentException(value + "is not a valid AccessPermission value");
2807         }
2808         if (DBG) log("setMessageAccessPermission()");
2809         final IBluetooth service = getService();
2810         if (service == null || !isBluetoothEnabled()) {
2811             Log.w(TAG, "Proxy not attached to service");
2812             if (DBG) log(Log.getStackTraceString(new Throwable()));
2813         } else {
2814             try {
2815                 return service.setMessageAccessPermission(this, value, mAttributionSource);
2816             } catch (RemoteException e) {
2817                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2818             }
2819         }
2820         return false;
2821     }
2822 
2823     /**
2824      * Gets whether sim access is allowed for this bluetooth device
2825      *
2826      * @return Whether the Sim access is allowed to this device.
2827      * @hide
2828      */
2829     @SystemApi
2830     @RequiresLegacyBluetoothPermission
2831     @RequiresBluetoothConnectPermission
2832     @RequiresPermission(BLUETOOTH_CONNECT)
getSimAccessPermission()2833     public @AccessPermission int getSimAccessPermission() {
2834         if (DBG) log("getSimAccessPermission()");
2835         final IBluetooth service = getService();
2836         if (service == null || !isBluetoothEnabled()) {
2837             Log.w(TAG, "Proxy not attached to service");
2838             if (DBG) log(Log.getStackTraceString(new Throwable()));
2839         } else {
2840             try {
2841                 return service.getSimAccessPermission(this, mAttributionSource);
2842             } catch (RemoteException e) {
2843                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2844             }
2845         }
2846         return ACCESS_UNKNOWN;
2847     }
2848 
2849     /**
2850      * Sets whether the Sim access is allowed to this device.
2851      *
2852      * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded, {@link
2853      *     #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if the
2854      *     permission is not being granted.
2855      * @return Whether the value has been successfully set.
2856      * @hide
2857      */
2858     @SystemApi
2859     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
setSimAccessPermission(int value)2860     public boolean setSimAccessPermission(int value) {
2861         if (DBG) log("setSimAccessPermission()");
2862         final IBluetooth service = getService();
2863         if (service == null || !isBluetoothEnabled()) {
2864             Log.w(TAG, "Proxy not attached to service");
2865             if (DBG) log(Log.getStackTraceString(new Throwable()));
2866         } else {
2867             try {
2868                 return service.setSimAccessPermission(this, value, mAttributionSource);
2869             } catch (RemoteException e) {
2870                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2871             }
2872         }
2873         return false;
2874     }
2875 
2876     /**
2877      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure outgoing connection to this
2878      * remote device on given channel.
2879      *
2880      * <p>The remote device will be authenticated and communication on this socket will be
2881      * encrypted.
2882      *
2883      * <p>Use this socket only if an authenticated socket link is possible. Authentication refers to
2884      * the authentication of the link key to prevent person-in-the-middle type of attacks. For
2885      * example, for Bluetooth 2.1 devices, if any of the devices does not have an input and output
2886      * capability or just has the ability to display a numeric key, a secure socket connection is
2887      * not possible. In such a case, use {@link createInsecureRfcommSocket}. For more details, refer
2888      * to the Security Model section 5.2 (vol 3) of Bluetooth Core Specification version 2.1 + EDR.
2889      *
2890      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
2891      *
2892      * <p>Valid RFCOMM channels are in range 1 to 30.
2893      *
2894      * @param channel RFCOMM channel to connect to
2895      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
2896      * @throws IOException on error, for example Bluetooth not available, or insufficient
2897      *     permissions
2898      * @hide
2899      */
2900     @UnsupportedAppUsage
2901     @RequiresLegacyBluetoothPermission
createRfcommSocket(int channel)2902     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
2903         if (!isBluetoothEnabled()) {
2904             Log.e(TAG, "Bluetooth is not enabled");
2905             throw new IOException();
2906         }
2907         return new BluetoothSocket(this, BluetoothSocket.TYPE_RFCOMM, true, true, channel, null);
2908     }
2909 
2910     /**
2911      * Create an L2cap {@link BluetoothSocket} ready to start a secure outgoing connection to this
2912      * remote device on given channel.
2913      *
2914      * <p>The remote device will be authenticated and communication on this socket will be
2915      * encrypted.
2916      *
2917      * <p>Use this socket only if an authenticated socket link is possible. Authentication refers to
2918      * the authentication of the link key to prevent person-in-the-middle type of attacks. For
2919      * example, for Bluetooth 2.1 devices, if any of the devices does not have an input and output
2920      * capability or just has the ability to display a numeric key, a secure socket connection is
2921      * not possible. In such a case, use {@link createInsecureRfcommSocket}. For more details, refer
2922      * to the Security Model section 5.2 (vol 3) of Bluetooth Core Specification version 2.1 + EDR.
2923      *
2924      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
2925      *
2926      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
2927      *
2928      * @param channel L2cap PSM/channel to connect to
2929      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
2930      * @throws IOException on error, for example Bluetooth not available, or insufficient
2931      *     permissions
2932      * @hide
2933      */
2934     @RequiresLegacyBluetoothPermission
createL2capSocket(int channel)2935     public BluetoothSocket createL2capSocket(int channel) throws IOException {
2936         return new BluetoothSocket(this, BluetoothSocket.TYPE_L2CAP, true, true, channel, null);
2937     }
2938 
2939     /**
2940      * Create an L2cap {@link BluetoothSocket} ready to start an insecure outgoing connection to
2941      * this remote device on given channel.
2942      *
2943      * <p>The remote device will be not authenticated and communication on this socket will not be
2944      * encrypted.
2945      *
2946      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
2947      *
2948      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
2949      *
2950      * @param channel L2cap PSM/channel to connect to
2951      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
2952      * @throws IOException on error, for example Bluetooth not available, or insufficient
2953      *     permissions
2954      * @hide
2955      */
2956     @RequiresLegacyBluetoothPermission
createInsecureL2capSocket(int channel)2957     public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException {
2958         return new BluetoothSocket(this, BluetoothSocket.TYPE_L2CAP, false, false, channel, null);
2959     }
2960 
2961     /**
2962      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure outgoing connection to this
2963      * remote device using SDP lookup of uuid.
2964      *
2965      * <p>This is designed to be used with {@link
2966      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer Bluetooth applications.
2967      *
2968      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. This will also
2969      * perform an SDP lookup of the given uuid to determine which channel to connect to.
2970      *
2971      * <p>The remote device will be authenticated and communication on this socket will be
2972      * encrypted.
2973      *
2974      * <p>Use this socket only if an authenticated socket link is possible. Authentication refers to
2975      * the authentication of the link key to prevent person-in-the-middle type of attacks. For
2976      * example, for Bluetooth 2.1 devices, if any of the devices does not have an input and output
2977      * capability or just has the ability to display a numeric key, a secure socket connection is
2978      * not possible. In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}. For
2979      * more details, refer to the Security Model section 5.2 (vol 3) of Bluetooth Core Specification
2980      * version 2.1 + EDR.
2981      *
2982      * <p>Hint: If you are connecting to a Bluetooth serial board then try using the well-known SPP
2983      * UUID 00001101-0000-1000-8000-00805F9B34FB. However if you are connecting to an Android peer
2984      * then please generate your own unique UUID.
2985      *
2986      * @param uuid service record uuid to lookup RFCOMM channel
2987      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
2988      * @throws IOException on error, for example Bluetooth not available, or insufficient
2989      *     permissions
2990      */
2991     @RequiresLegacyBluetoothPermission
createRfcommSocketToServiceRecord(UUID uuid)2992     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
2993         if (!isBluetoothEnabled()) {
2994             Log.e(TAG, "Bluetooth is not enabled");
2995             throw new IOException();
2996         }
2997 
2998         return new BluetoothSocket(
2999                 this, BluetoothSocket.TYPE_RFCOMM, true, true, -1, new ParcelUuid(uuid));
3000     }
3001 
3002     /**
3003      * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure outgoing
3004      * connection to this remote device using SDP lookup of uuid.
3005      *
3006      * <p>The communication channel will not have an authenticated link key i.e. it will be subject
3007      * to person-in-the-middle attacks. For Bluetooth 2.1 devices, the link key will be encrypted,
3008      * as encryption is mandatory. For legacy devices (pre Bluetooth 2.1 devices) the link key will
3009      * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an encrypted and
3010      * authenticated communication channel is desired.
3011      *
3012      * <p>This is designed to be used with {@link
3013      * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer Bluetooth
3014      * applications.
3015      *
3016      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection. This will also
3017      * perform an SDP lookup of the given uuid to determine which channel to connect to.
3018      *
3019      * <p>The remote device will be authenticated and communication on this socket will be
3020      * encrypted.
3021      *
3022      * <p>Hint: If you are connecting to a Bluetooth serial board then try using the well-known SPP
3023      * UUID 00001101-0000-1000-8000-00805F9B34FB. However if you are connecting to an Android peer
3024      * then please generate your own unique UUID.
3025      *
3026      * @param uuid service record uuid to lookup RFCOMM channel
3027      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
3028      * @throws IOException on error, for example Bluetooth not available, or insufficient
3029      *     permissions
3030      */
3031     @RequiresLegacyBluetoothPermission
createInsecureRfcommSocketToServiceRecord(UUID uuid)3032     public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
3033         if (!isBluetoothEnabled()) {
3034             Log.e(TAG, "Bluetooth is not enabled");
3035             throw new IOException();
3036         }
3037         return new BluetoothSocket(
3038                 this, BluetoothSocket.TYPE_RFCOMM, false, false, -1, new ParcelUuid(uuid));
3039     }
3040 
3041     /**
3042      * Construct an insecure RFCOMM socket ready to start an outgoing connection. Call #connect on
3043      * the returned #BluetoothSocket to begin the connection. The remote device will not be
3044      * authenticated and communication on this socket will not be encrypted.
3045      *
3046      * @param port remote port
3047      * @return An RFCOMM BluetoothSocket
3048      * @throws IOException On error, for example Bluetooth not available, or insufficient
3049      *     permissions.
3050      * @hide
3051      */
3052     @UnsupportedAppUsage(
3053             publicAlternatives =
3054                     "Use " + "{@link #createInsecureRfcommSocketToServiceRecord} instead.")
3055     @RequiresLegacyBluetoothAdminPermission
createInsecureRfcommSocket(int port)3056     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
3057         if (!isBluetoothEnabled()) {
3058             Log.e(TAG, "Bluetooth is not enabled");
3059             throw new IOException();
3060         }
3061         return new BluetoothSocket(this, BluetoothSocket.TYPE_RFCOMM, false, false, port, null);
3062     }
3063 
3064     /**
3065      * Construct a SCO socket ready to start an outgoing connection. Call #connect on the returned
3066      * #BluetoothSocket to begin the connection.
3067      *
3068      * @return a SCO BluetoothSocket
3069      * @throws IOException on error, for example Bluetooth not available, or insufficient
3070      *     permissions.
3071      * @hide
3072      */
3073     @UnsupportedAppUsage
3074     @RequiresLegacyBluetoothAdminPermission
createScoSocket()3075     public BluetoothSocket createScoSocket() throws IOException {
3076         if (!isBluetoothEnabled()) {
3077             Log.e(TAG, "Bluetooth is not enabled");
3078             throw new IOException();
3079         }
3080         return new BluetoothSocket(this, BluetoothSocket.TYPE_SCO, true, true, -1, null);
3081     }
3082 
3083     /**
3084      * Check that a pin is valid and convert to byte array.
3085      *
3086      * <p>Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
3087      *
3088      * @param pin pin as java String
3089      * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin.
3090      * @hide
3091      */
3092     @UnsupportedAppUsage
convertPinToBytes(String pin)3093     public static byte[] convertPinToBytes(String pin) {
3094         if (pin == null) {
3095             return null;
3096         }
3097         byte[] pinBytes = pin.getBytes(StandardCharsets.UTF_8);
3098         if (pinBytes.length <= 0 || pinBytes.length > 16) {
3099             return null;
3100         }
3101         return pinBytes;
3102     }
3103 
3104     /**
3105      * Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is
3106      * used to deliver results to Caller, such as connection status as well as any further GATT
3107      * client operations. The method returns a BluetoothGatt instance. You can use BluetoothGatt to
3108      * conduct GATT client operations.
3109      *
3110      * @param callback GATT callback handler that will receive asynchronous callbacks.
3111      * @param autoConnect Whether to directly connect to the remote device (false) or to
3112      *     automatically connect as soon as the remote device becomes available (true).
3113      * @throws IllegalArgumentException if callback is null
3114      */
3115     @RequiresBluetoothConnectPermission
3116     @RequiresPermission(BLUETOOTH_CONNECT)
connectGatt( Context context, boolean autoConnect, BluetoothGattCallback callback)3117     public BluetoothGatt connectGatt(
3118             Context context, boolean autoConnect, BluetoothGattCallback callback) {
3119         return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO));
3120     }
3121 
3122     /**
3123      * Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is
3124      * used to deliver results to Caller, such as connection status as well as any further GATT
3125      * client operations. The method returns a BluetoothGatt instance. You can use BluetoothGatt to
3126      * conduct GATT client operations.
3127      *
3128      * @param callback GATT callback handler that will receive asynchronous callbacks.
3129      * @param autoConnect Whether to directly connect to the remote device (false) or to
3130      *     automatically connect as soon as the remote device becomes available (true).
3131      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
3132      *     BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
3133      *     BluetoothDevice#TRANSPORT_LE}
3134      * @throws IllegalArgumentException if callback is null
3135      */
3136     @RequiresBluetoothConnectPermission
3137     @RequiresPermission(BLUETOOTH_CONNECT)
connectGatt( Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)3138     public BluetoothGatt connectGatt(
3139             Context context, boolean autoConnect, BluetoothGattCallback callback, int transport) {
3140         return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK));
3141     }
3142 
3143     /**
3144      * Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is
3145      * used to deliver results to Caller, such as connection status as well as any further GATT
3146      * client operations. The method returns a BluetoothGatt instance. You can use BluetoothGatt to
3147      * conduct GATT client operations.
3148      *
3149      * @param callback GATT callback handler that will receive asynchronous callbacks.
3150      * @param autoConnect Whether to directly connect to the remote device (false) or to
3151      *     automatically connect as soon as the remote device becomes available (true).
3152      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
3153      *     BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
3154      *     BluetoothDevice#TRANSPORT_LE}
3155      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
3156      *     BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link
3157      *     BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code
3158      *     autoConnect} is set to true.
3159      * @throws NullPointerException if callback is null
3160      */
3161     @RequiresBluetoothConnectPermission
3162     @RequiresPermission(BLUETOOTH_CONNECT)
connectGatt( Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy)3163     public BluetoothGatt connectGatt(
3164             Context context,
3165             boolean autoConnect,
3166             BluetoothGattCallback callback,
3167             int transport,
3168             int phy) {
3169         return connectGatt(context, autoConnect, callback, transport, phy, null);
3170     }
3171 
3172     /**
3173      * Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is
3174      * used to deliver results to Caller, such as connection status as well as any further GATT
3175      * client operations. The method returns a BluetoothGatt instance. You can use BluetoothGatt to
3176      * conduct GATT client operations.
3177      *
3178      * @param callback GATT callback handler that will receive asynchronous callbacks.
3179      * @param autoConnect Whether to directly connect to the remote device (false) or to
3180      *     automatically connect as soon as the remote device becomes available (true).
3181      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
3182      *     BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
3183      *     BluetoothDevice#TRANSPORT_LE}
3184      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
3185      *     BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
3186      *     BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code
3187      *     autoConnect} is set to true.
3188      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
3189      *     an un-specified background thread.
3190      * @throws NullPointerException if callback is null
3191      */
3192     @RequiresBluetoothConnectPermission
3193     @RequiresPermission(BLUETOOTH_CONNECT)
connectGatt( Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler)3194     public BluetoothGatt connectGatt(
3195             Context context,
3196             boolean autoConnect,
3197             BluetoothGattCallback callback,
3198             int transport,
3199             int phy,
3200             Handler handler) {
3201         return connectGatt(context, autoConnect, callback, transport, false, phy, handler);
3202     }
3203 
3204     /**
3205      * Connect to GATT Server hosted by this device. Caller acts as GATT client. The callback is
3206      * used to deliver results to Caller, such as connection status as well as any further GATT
3207      * client operations. The method returns a BluetoothGatt instance. You can use BluetoothGatt to
3208      * conduct GATT client operations.
3209      *
3210      * @param callback GATT callback handler that will receive asynchronous callbacks.
3211      * @param autoConnect Whether to directly connect to the remote device (false) or to
3212      *     automatically connect as soon as the remote device becomes available (true).
3213      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
3214      *     BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
3215      *     BluetoothDevice#TRANSPORT_LE}
3216      * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client
3217      *     does not hold a GATT connection. It automatically disconnects when no other GATT
3218      *     connections are active for the remote device.
3219      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
3220      *     BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
3221      *     BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code
3222      *     autoConnect} is set to true.
3223      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
3224      *     an un-specified background thread.
3225      * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client
3226      *     operations.
3227      * @hide
3228      */
3229     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
3230     @RequiresBluetoothConnectPermission
3231     @RequiresPermission(BLUETOOTH_CONNECT)
connectGatt( Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, boolean opportunistic, int phy, Handler handler)3232     public BluetoothGatt connectGatt(
3233             Context context,
3234             boolean autoConnect,
3235             BluetoothGattCallback callback,
3236             int transport,
3237             boolean opportunistic,
3238             int phy,
3239             Handler handler) {
3240         if (callback == null) {
3241             throw new NullPointerException("callback is null");
3242         }
3243 
3244         // TODO(Bluetooth) check whether platform support BLE
3245         //     Do the check here or in GattServer?
3246         IBluetoothGatt iGatt = BluetoothAdapter.getDefaultAdapter().getBluetoothGatt();
3247         if (iGatt == null) {
3248             // BLE is not supported
3249             return null;
3250         } else if (NULL_MAC_ADDRESS.equals(mAddress)) {
3251             Log.e(TAG, "Unable to connect gatt, invalid address " + mAddress);
3252             return null;
3253         }
3254         BluetoothGatt gatt =
3255                 new BluetoothGatt(iGatt, this, transport, opportunistic, phy, mAttributionSource);
3256         gatt.connect(autoConnect, callback, handler);
3257         return gatt;
3258     }
3259 
3260     /**
3261      * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
3262      * be used to start a secure outgoing connection to the remote device with the same dynamic
3263      * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
3264      *
3265      * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for
3266      * peer-peer Bluetooth applications.
3267      *
3268      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
3269      *
3270      * <p>Application using this API is responsible for obtaining PSM value from remote device.
3271      *
3272      * <p>The remote device will be authenticated and communication on this socket will be
3273      * encrypted.
3274      *
3275      * <p>Use this socket if an authenticated socket link is possible. Authentication refers to the
3276      * authentication of the link key to prevent person-in-the-middle type of attacks.
3277      *
3278      * @param psm dynamic PSM value from remote device
3279      * @return a CoC #BluetoothSocket ready for an outgoing connection
3280      * @throws IOException on error, for example Bluetooth not available, or insufficient
3281      *     permissions
3282      */
3283     @RequiresLegacyBluetoothPermission
createL2capChannel(int psm)3284     public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException {
3285         if (!isBluetoothEnabled()) {
3286             Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
3287             throw new IOException();
3288         }
3289         if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm);
3290         return new BluetoothSocket(this, BluetoothSocket.TYPE_L2CAP_LE, true, true, psm, null);
3291     }
3292 
3293     /**
3294      * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
3295      * be used to start a secure outgoing connection to the remote device with the same dynamic
3296      * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
3297      *
3298      * <p>This is designed to be used with {@link
3299      * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications.
3300      *
3301      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
3302      *
3303      * <p>Application using this API is responsible for obtaining PSM value from remote device.
3304      *
3305      * <p>The communication channel may not have an authenticated link key, i.e. it may be subject
3306      * to person-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and
3307      * authenticated communication channel is possible.
3308      *
3309      * @param psm dynamic PSM value from remote device
3310      * @return a CoC #BluetoothSocket ready for an outgoing connection
3311      * @throws IOException on error, for example Bluetooth not available, or insufficient
3312      *     permissions
3313      */
3314     @RequiresLegacyBluetoothPermission
createInsecureL2capChannel(int psm)3315     public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
3316         if (!isBluetoothEnabled()) {
3317             Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
3318             throw new IOException();
3319         }
3320         if (DBG) {
3321             Log.d(TAG, "createInsecureL2capChannel: psm=" + psm);
3322         }
3323         return new BluetoothSocket(this, BluetoothSocket.TYPE_L2CAP_LE, false, false, psm, null);
3324     }
3325 
3326     /**
3327      * Creates a client socket to connect to a remote Bluetooth server with the specified socket
3328      * settings {@link BluetoothSocketSettings} This API is used to connect to a remote server
3329      * hosted using {@link BluetoothAdapter#listenUsingSocketSettings}.
3330      *
3331      * <ul>
3332      *   <li>For `BluetoothSocket.TYPE_RFCOMM`: The RFCOMM UUID must be provided using {@link
3333      *       BluetoothSocketSettings#setRfcommUuid()}.
3334      *   <li>For `BluetoothSocket.TYPE_LE`: The L2cap protocol/service multiplexer (PSM) value must
3335      *       be provided using {@link BluetoothSocketSettings#setL2capPsm()}.
3336      * </ul>
3337      *
3338      * <p>Application using this API is responsible for obtaining protocol/service multiplexer (psm)
3339      * value from remote device.
3340      *
3341      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
3342      *
3343      * @param settings Bluetooth socket settings {@link BluetoothSocketSettings}.
3344      * @return a {@link BluetoothSocket} ready for an outgoing connection.
3345      * @throws IllegalArgumentException if BluetoothSocket#TYPE_RFCOMM socket with no UUID is passed
3346      *     as input or if BluetoothSocket#TYPE_LE with invalid PSM is passed.
3347      * @throws IOException on error, for example Bluetooth not available.
3348      */
3349     @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
createUsingSocketSettings( @onNull BluetoothSocketSettings settings)3350     public @NonNull BluetoothSocket createUsingSocketSettings(
3351             @NonNull BluetoothSocketSettings settings) throws IOException {
3352         if (!isBluetoothEnabled()) {
3353             Log.e(TAG, "createUsingSocketSettings: Bluetooth is not enabled");
3354             throw new IOException();
3355         }
3356         if (DBG) {
3357             Log.d(TAG, "createUsingSocketSettings: =" + settings.getL2capPsm());
3358         }
3359         ParcelUuid uuid = null;
3360         int psm = settings.getL2capPsm();
3361         if (settings.getSocketType() == BluetoothSocket.TYPE_RFCOMM) {
3362             if (settings.getRfcommUuid() == null) {
3363                 throw new IllegalArgumentException("null uuid");
3364             }
3365             uuid = new ParcelUuid(settings.getRfcommUuid());
3366         } else if (settings.getSocketType() == BluetoothSocket.TYPE_LE) {
3367             if (psm < 128 || psm > 255) {
3368                 throw new IllegalArgumentException("Invalid PSM/Channel value: " + psm);
3369             }
3370         }
3371         if (settings.getDataPath() == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
3372             return new BluetoothSocket(
3373                     this,
3374                     settings.getSocketType(),
3375                     settings.isAuthenticationRequired(),
3376                     settings.isEncryptionRequired(),
3377                     psm,
3378                     uuid);
3379         } else {
3380             return new BluetoothSocket(
3381                     this,
3382                     settings.getSocketType(),
3383                     settings.isAuthenticationRequired(),
3384                     settings.isEncryptionRequired(),
3385                     psm,
3386                     uuid,
3387                     false,
3388                     false,
3389                     settings.getDataPath(),
3390                     settings.getSocketName(),
3391                     settings.getHubId(),
3392                     settings.getEndpointId(),
3393                     settings.getRequestedMaximumPacketSize());
3394         }
3395     }
3396 
3397     /**
3398      * Set a keyed metadata of this {@link BluetoothDevice} to a {@link String} value. Only bonded
3399      * devices's metadata will be persisted across Bluetooth restart. Metadata will be removed when
3400      * the device's bond state is moved to {@link #BOND_NONE}.
3401      *
3402      * @param key must be within the list of BluetoothDevice.METADATA_*
3403      * @param value a byte array data to set for key. Must be less than {@link
3404      *     BluetoothAdapter#METADATA_MAX_LENGTH} characters in length
3405      * @return true on success, false on error
3406      * @hide
3407      */
3408     @SystemApi
3409     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
setMetadata(@etadataKey int key, @NonNull byte[] value)3410     public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) {
3411         if (DBG) log("setMetadata()");
3412         final IBluetooth service = getService();
3413         if (service == null || !isBluetoothEnabled()) {
3414             Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
3415             if (DBG) log(Log.getStackTraceString(new Throwable()));
3416         } else if (value.length > METADATA_MAX_LENGTH) {
3417             throw new IllegalArgumentException(
3418                     "value length is " + value.length + ", should not over " + METADATA_MAX_LENGTH);
3419         } else {
3420             try {
3421                 return service.setMetadata(this, key, value, mAttributionSource);
3422             } catch (RemoteException e) {
3423                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
3424             }
3425         }
3426         return false;
3427     }
3428 
3429     /**
3430      * Get a keyed metadata for this {@link BluetoothDevice} as {@link String}
3431      *
3432      * @param key must be within the list of BluetoothDevice.METADATA_*
3433      * @return Metadata of the key as byte array, null on error or not found
3434      * @hide
3435      */
3436     @SystemApi
3437     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getMetadata(@etadataKey int key)3438     public @Nullable byte[] getMetadata(@MetadataKey int key) {
3439         if (DBG) log("getMetadata()");
3440         final IBluetooth service = getService();
3441         if (service == null || !isBluetoothEnabled()) {
3442             Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
3443             if (DBG) log(Log.getStackTraceString(new Throwable()));
3444         } else {
3445             try {
3446                 return service.getMetadata(this, key, mAttributionSource);
3447             } catch (RemoteException e) {
3448                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
3449             }
3450         }
3451         return null;
3452     }
3453 
3454     /**
3455      * Get the maximum metadata key ID.
3456      *
3457      * @return the last supported metadata key
3458      * @hide
3459      */
getMaxMetadataKey()3460     public static @MetadataKey int getMaxMetadataKey() {
3461         return METADATA_MAX_KEY;
3462     }
3463 
3464     /** @hide */
3465     @Retention(RetentionPolicy.SOURCE)
3466     @IntDef(
3467             prefix = {"FEATURE_"},
3468             value = {
3469                 BluetoothStatusCodes.FEATURE_NOT_CONFIGURED,
3470                 BluetoothStatusCodes.FEATURE_SUPPORTED,
3471                 BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
3472             })
3473     public @interface AudioPolicyRemoteSupport {}
3474 
3475     /** @hide */
3476     @Retention(RetentionPolicy.SOURCE)
3477     @IntDef(
3478             value = {
3479                 BluetoothStatusCodes.SUCCESS,
3480                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
3481                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
3482                 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED,
3483                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
3484                 BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED,
3485             })
3486     public @interface AudioPolicyReturnValues {}
3487 
3488     /**
3489      * Returns whether the audio policy feature is supported by both the local and the remote
3490      * device. This is configured during initiating the connection between the devices through one
3491      * of the transport protocols (e.g. HFP Vendor specific protocol). So if the API is invoked
3492      * before this initial configuration is completed, it returns {@link
3493      * BluetoothStatusCodes#FEATURE_NOT_CONFIGURED} to indicate the remote device has not yet
3494      * relayed this information. After the internal configuration, the support status will be set to
3495      * either {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} or {@link
3496      * BluetoothStatusCodes#FEATURE_SUPPORTED}. The rest of the APIs related to this feature in both
3497      * {@link BluetoothDevice} and {@link BluetoothSinkAudioPolicy} should be invoked only after
3498      * getting a {@link BluetoothStatusCodes#FEATURE_SUPPORTED} response from this API.
3499      *
3500      * <p>Note that this API is intended to be used by a client device to send these requests to the
3501      * server represented by this BluetoothDevice object.
3502      *
3503      * @return if call audio policy feature is supported by both local and remote device or not
3504      * @hide
3505      */
3506     @SystemApi
3507     @RequiresBluetoothConnectPermission
3508     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
isRequestAudioPolicyAsSinkSupported()3509     public @AudioPolicyRemoteSupport int isRequestAudioPolicyAsSinkSupported() {
3510         if (DBG) log("isRequestAudioPolicyAsSinkSupported()");
3511         final IBluetooth service = getService();
3512         if (service == null || !isBluetoothEnabled()) {
3513             Log.e(TAG, "BT not enabled. Cannot retrieve audio policy support status.");
3514             if (DBG) log(Log.getStackTraceString(new Throwable()));
3515         } else {
3516             try {
3517                 return service.isRequestAudioPolicyAsSinkSupported(this, mAttributionSource);
3518             } catch (RemoteException e) {
3519                 Log.e(TAG, "", e);
3520             }
3521         }
3522         return BluetoothStatusCodes.FEATURE_NOT_CONFIGURED;
3523     }
3524 
3525     /**
3526      * Sets call audio preferences and sends them to the remote device.
3527      *
3528      * <p>Note that the caller should check if the feature is supported by invoking {@link
3529      * BluetoothDevice#isRequestAudioPolicyAsSinkSupported} first.
3530      *
3531      * <p>This API will throw an exception if the feature is not supported but still invoked.
3532      *
3533      * <p>Note that this API is intended to be used by a client device to send these requests to the
3534      * server represented by this BluetoothDevice object.
3535      *
3536      * @param policies call audio policy preferences
3537      * @return whether audio policy was requested successfully or not
3538      * @hide
3539      */
3540     @SystemApi
3541     @RequiresBluetoothConnectPermission
3542     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
requestAudioPolicyAsSink( @onNull BluetoothSinkAudioPolicy policies)3543     public @AudioPolicyReturnValues int requestAudioPolicyAsSink(
3544             @NonNull BluetoothSinkAudioPolicy policies) {
3545         if (DBG) log("requestAudioPolicyAsSink");
3546         final IBluetooth service = getService();
3547         if (service == null || !isBluetoothEnabled()) {
3548             Log.e(TAG, "Bluetooth is not enabled. Cannot set Audio Policy.");
3549             if (DBG) log(Log.getStackTraceString(new Throwable()));
3550         } else {
3551             try {
3552                 return service.requestAudioPolicyAsSink(this, policies, mAttributionSource);
3553             } catch (RemoteException e) {
3554                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
3555             }
3556         }
3557         return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
3558     }
3559 
3560     /**
3561      * Gets the call audio preferences for the remote device.
3562      *
3563      * <p>Note that the caller should check if the feature is supported by invoking {@link
3564      * BluetoothDevice#isRequestAudioPolicyAsSinkSupported} first.
3565      *
3566      * <p>This API will throw an exception if the feature is not supported but still invoked.
3567      *
3568      * <p>This API will return null if 1. The bluetooth service is not started yet, 2. It is invoked
3569      * for a device which is not bonded, or 3. The used transport, for example, HFP Client profile
3570      * is not enabled or connected yet.
3571      *
3572      * <p>Note that this API is intended to be used by a client device to send these requests to the
3573      * server represented by this BluetoothDevice object.
3574      *
3575      * @return call audio policy as {@link BluetoothSinkAudioPolicy} object
3576      * @hide
3577      */
3578     @SystemApi
3579     @RequiresBluetoothConnectPermission
3580     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getRequestedAudioPolicyAsSink()3581     public @Nullable BluetoothSinkAudioPolicy getRequestedAudioPolicyAsSink() {
3582         if (DBG) log("getRequestedAudioPolicyAsSink");
3583         final IBluetooth service = getService();
3584         if (service == null || !isBluetoothEnabled()) {
3585             Log.e(TAG, "Bluetooth is not enabled. Cannot get Audio Policy.");
3586             if (DBG) log(Log.getStackTraceString(new Throwable()));
3587         } else {
3588             try {
3589                 return service.getRequestedAudioPolicyAsSink(this, mAttributionSource);
3590             } catch (RemoteException e) {
3591                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
3592             }
3593         }
3594         return null;
3595     }
3596 
3597     /**
3598      * Enable or disable audio low latency for this {@link BluetoothDevice}.
3599      *
3600      * @param allowed true if low latency is allowed, false if low latency is disallowed.
3601      * @return true if the value is successfully set, false if there is a error when setting the
3602      *     value.
3603      * @hide
3604      */
3605     @SystemApi
3606     @RequiresBluetoothConnectPermission
3607     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
setLowLatencyAudioAllowed(boolean allowed)3608     public boolean setLowLatencyAudioAllowed(boolean allowed) {
3609         if (DBG) log("setLowLatencyAudioAllowed(" + allowed + ")");
3610         final IBluetooth service = getService();
3611         if (service == null || !isBluetoothEnabled()) {
3612             Log.e(TAG, "Bluetooth is not enabled. Cannot allow low latency");
3613             if (DBG) log(Log.getStackTraceString(new Throwable()));
3614         } else {
3615             try {
3616                 return service.allowLowLatencyAudio(allowed, this);
3617             } catch (RemoteException e) {
3618                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
3619             }
3620         }
3621         return false;
3622     }
3623 
3624     /** @hide */
3625     @IntDef(
3626             value = {
3627                 BluetoothStatusCodes.SUCCESS,
3628                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
3629                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
3630                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
3631                 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED
3632             })
3633     @Retention(RetentionPolicy.SOURCE)
3634     public @interface SetActiveAudioDevicePolicyReturnValues {}
3635 
3636     /**
3637      * Active audio device policy for this device
3638      *
3639      * @hide
3640      */
3641     @IntDef(
3642             prefix = "ACTIVE_AUDIO_DEVICE_POLICY_",
3643             value = {
3644                 ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT,
3645                 ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_ACTIVE_UPON_CONNECTION,
3646                 ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_INACTIVE_UPON_CONNECTION
3647             })
3648     @Retention(RetentionPolicy.SOURCE)
3649     public @interface ActiveAudioDevicePolicy {}
3650 
3651     /**
3652      * Set the active audio device policy for this {@link BluetoothDevice} to indicate what {@link
3653      * ActiveAudioDevicePolicy} is applied upon device connection.
3654      *
3655      * <p>This API allows application to set the audio device profiles active policy upon
3656      * connection, only bonded device's policy will be persisted across Bluetooth restart. Policy
3657      * setting will be removed when the device's bond state is moved to {@link #BOND_NONE}.
3658      *
3659      * @param activeAudioDevicePolicy is the active audio device policy to set for this device
3660      * @return whether the policy was set properly
3661      * @throws IllegalArgumentException if this BluetoothDevice object has an invalid address
3662      * @hide
3663      */
3664     @SystemApi
3665     @RequiresBluetoothConnectPermission
3666     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
setActiveAudioDevicePolicy( @ctiveAudioDevicePolicy int activeAudioDevicePolicy)3667     public @SetActiveAudioDevicePolicyReturnValues int setActiveAudioDevicePolicy(
3668             @ActiveAudioDevicePolicy int activeAudioDevicePolicy) {
3669         if (DBG) log("setActiveAudioDevicePolicy(" + activeAudioDevicePolicy + ")");
3670         if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) {
3671             throw new IllegalArgumentException("device cannot have an invalid address");
3672         }
3673 
3674         final IBluetooth service = getService();
3675         if (service == null || !isBluetoothEnabled()) {
3676             Log.e(TAG, "Bluetooth is not enabled. Cannot set active audio device policy.");
3677             if (DBG) log(Log.getStackTraceString(new Throwable()));
3678         } else {
3679             try {
3680                 return service.setActiveAudioDevicePolicy(
3681                         this, activeAudioDevicePolicy, mAttributionSource);
3682             } catch (RemoteException e) {
3683                 Log.e(TAG, "", e);
3684             }
3685         }
3686         return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
3687     }
3688 
3689     /**
3690      * Get the active audio device policy for this {@link BluetoothDevice}.
3691      *
3692      * @return active audio device policy of the device
3693      * @hide
3694      */
3695     @SystemApi
3696     @RequiresBluetoothConnectPermission
3697     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getActiveAudioDevicePolicy()3698     public @ActiveAudioDevicePolicy int getActiveAudioDevicePolicy() {
3699         if (DBG) log("getActiveAudioDevicePolicy");
3700         final IBluetooth service = getService();
3701         if (service == null || !isBluetoothEnabled()) {
3702             Log.e(TAG, "Bluetooth is not enabled. Cannot get active audio device policy.");
3703             if (DBG) log(Log.getStackTraceString(new Throwable()));
3704         } else {
3705             try {
3706                 return service.getActiveAudioDevicePolicy(this, mAttributionSource);
3707             } catch (RemoteException e) {
3708                 Log.e(TAG, "", e);
3709             }
3710         }
3711         return ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT;
3712     }
3713 
3714     /** @hide */
3715     @IntDef(
3716             value = {
3717                 BluetoothStatusCodes.SUCCESS,
3718                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
3719                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
3720                 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED
3721             })
3722     @Retention(RetentionPolicy.SOURCE)
3723     public @interface SetMicrophonePreferredForCallsReturnValues {}
3724 
3725     /**
3726      * Sets whether this {@link BluetoothDevice} should be the preferred microphone for calls.
3727      *
3728      * <p>This API is for Bluetooth audio devices and only sets a preference. The caller is
3729      * responsible for changing the audio input routing to reflect the preference.
3730      *
3731      * @param enabled {@code true} to set the device as the preferred microphone for calls, {@code
3732      *     false} otherwise.
3733      * @return Whether the preferred microphone for calls was set properly.
3734      * @throws IllegalArgumentException if the {@link BluetoothDevice} object has an invalid
3735      *     address.
3736      * @hide
3737      */
3738     @FlaggedApi(Flags.FLAG_METADATA_API_MICROPHONE_FOR_CALL_ENABLED)
3739     @SystemApi
3740     @RequiresBluetoothConnectPermission
3741     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
setMicrophonePreferredForCalls( boolean enabled)3742     public @SetMicrophonePreferredForCallsReturnValues int setMicrophonePreferredForCalls(
3743             boolean enabled) {
3744         if (DBG) log("setMicrophonePreferredForCalls(" + enabled + ")");
3745         if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) {
3746             throw new IllegalArgumentException("device cannot have an invalid address");
3747         }
3748 
3749         final IBluetooth service = getService();
3750         if (service == null || !isBluetoothEnabled()) {
3751             Log.e(TAG, "Bluetooth is not enabled. Cannot set microphone for call enabled state.");
3752             if (DBG) log(Log.getStackTraceString(new Throwable()));
3753         } else {
3754             try {
3755                 return service.setMicrophonePreferredForCalls(this, enabled, mAttributionSource);
3756             } catch (RemoteException e) {
3757                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
3758             }
3759         }
3760         return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
3761     }
3762 
3763     /**
3764      * Gets whether this {@link BluetoothDevice} should be the preferred microphone for calls.
3765      *
3766      * <p>This API returns the configured preference for whether this device should be the preferred
3767      * microphone for calls and return {@code true} by default in case of error. It does not reflect
3768      * the current audio routing.
3769      *
3770      * @return {@code true} if the device is the preferred microphone for calls, {@code false}
3771      *     otherwise.
3772      * @hide
3773      */
3774     @FlaggedApi(Flags.FLAG_METADATA_API_MICROPHONE_FOR_CALL_ENABLED)
3775     @SystemApi
3776     @RequiresBluetoothConnectPermission
3777     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
isMicrophonePreferredForCalls()3778     public boolean isMicrophonePreferredForCalls() {
3779         if (DBG) log("isMicrophoneForCallEnabled");
3780         final IBluetooth service = getService();
3781         if (service == null || !isBluetoothEnabled()) {
3782             Log.e(TAG, "Bluetooth is not enabled. Cannot get microphone for call enabled state.");
3783             if (DBG) log(Log.getStackTraceString(new Throwable()));
3784         } else {
3785             try {
3786                 return service.isMicrophonePreferredForCalls(this, mAttributionSource);
3787             } catch (RemoteException e) {
3788                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
3789             }
3790         }
3791         return true;
3792     }
3793 
3794     /**
3795      * Get the number of times {@link ACTION_KEY_MISSING} intent is thrown for this device since
3796      * last successful encrypted connection
3797      *
3798      * @return number of times {@link ACTION_KEY_MISSING} intent is thrown for this device since
3799      *     last successful encrypted connection
3800      *
3801      * @hide
3802      */
3803     @RequiresPermission(BLUETOOTH_CONNECT)
getKeyMissingCount()3804     public int getKeyMissingCount() {
3805         final IBluetooth service = getService();
3806         if (service == null || !isBluetoothEnabled()) {
3807             Log.e(TAG, "Bluetooth is not enabled. Cannot get key missing counter.");
3808             if (DBG) log(Log.getStackTraceString(new Throwable()));
3809         } else {
3810             try {
3811                 return service.getKeyMissingCount(this, mAttributionSource);
3812             } catch (RemoteException e) {
3813                 Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
3814             }
3815         }
3816         return -1;
3817     }
3818 
log(String msg)3819     private static void log(String msg) {
3820         Log.d(TAG, msg);
3821     }
3822 
3823     /** A data class for Bluetooth address and address type. */
3824     @FlaggedApi(Flags.FLAG_IDENTITY_ADDRESS_TYPE_API)
3825     public static final class BluetoothAddress implements Parcelable {
3826         private final @Nullable String mAddress;
3827         private final @AddressType int mAddressType;
3828 
BluetoothAddress(@ullable String address, @AddressType int addressType)3829         public BluetoothAddress(@Nullable String address, @AddressType int addressType) {
3830             mAddress = address;
3831             mAddressType = addressType;
3832         }
3833 
3834         /**
3835          * Returns the address of this {@link BluetoothAddress}.
3836          *
3837          * <p>For example, "00:11:22:AA:BB:CC".
3838          *
3839          * @return Bluetooth address as string
3840          */
3841         @Nullable
getAddress()3842         public String getAddress() {
3843             return mAddress;
3844         }
3845 
3846         /**
3847          * Returns the address type of this {@link BluetoothAddress}, one of {@link
3848          * #ADDRESS_TYPE_PUBLIC}, {@link #ADDRESS_TYPE_RANDOM}, or {@link #ADDRESS_TYPE_UNKNOWN}.
3849          *
3850          * @return Bluetooth address type
3851          */
3852         @AddressType
getAddressType()3853         public int getAddressType() {
3854             return mAddressType;
3855         }
3856 
3857         @Override
describeContents()3858         public int describeContents() {
3859             return 0;
3860         }
3861 
3862         @Override
writeToParcel(@onNull Parcel out, int flags)3863         public void writeToParcel(@NonNull Parcel out, int flags) {
3864             BluetoothUtils.writeStringToParcel(out, mAddress);
3865             out.writeInt(mAddressType);
3866         }
3867 
BluetoothAddress(@onNull Parcel in)3868         private BluetoothAddress(@NonNull Parcel in) {
3869             this(in.readString(), in.readInt());
3870         }
3871 
3872         /** {@link Parcelable.Creator} interface implementation. */
3873         public static final @NonNull Parcelable.Creator<BluetoothAddress> CREATOR =
3874                 new Parcelable.Creator<BluetoothAddress>() {
3875                     public @NonNull BluetoothAddress createFromParcel(Parcel in) {
3876                         return new BluetoothAddress(in);
3877                     }
3878 
3879                     public @NonNull BluetoothAddress[] newArray(int size) {
3880                         return new BluetoothAddress[size];
3881                     }
3882                 };
3883     }
3884 }
3885