• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009-2016 The Android Open Source Project
3  * Copyright 2015 Samsung LSI
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package android.bluetooth;
19 
20 import static android.Manifest.permission.BLUETOOTH;
21 import static android.Manifest.permission.BLUETOOTH_ADVERTISE;
22 import static android.Manifest.permission.BLUETOOTH_CONNECT;
23 import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
24 import static android.Manifest.permission.BLUETOOTH_SCAN;
25 import static android.Manifest.permission.LOCAL_MAC_ADDRESS;
26 import static android.Manifest.permission.MODIFY_PHONE_STATE;
27 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
28 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
29 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
30 import static android.bluetooth.BluetoothProfile.getProfileName;
31 import static android.bluetooth.BluetoothStatusCodes.FEATURE_NOT_SUPPORTED;
32 import static android.bluetooth.BluetoothUtils.executeFromBinder;
33 import static android.bluetooth.BluetoothUtils.logRemoteException;
34 
35 import static java.util.Objects.requireNonNull;
36 
37 import android.annotation.BroadcastBehavior;
38 import android.annotation.CallbackExecutor;
39 import android.annotation.FlaggedApi;
40 import android.annotation.IntDef;
41 import android.annotation.IntRange;
42 import android.annotation.NonNull;
43 import android.annotation.Nullable;
44 import android.annotation.RequiresNoPermission;
45 import android.annotation.RequiresPermission;
46 import android.annotation.SdkConstant;
47 import android.annotation.SdkConstant.SdkConstantType;
48 import android.annotation.SuppressLint;
49 import android.annotation.SystemApi;
50 import android.app.PendingIntent;
51 import android.bluetooth.BluetoothDevice.AddressType;
52 import android.bluetooth.BluetoothDevice.Transport;
53 import android.bluetooth.BluetoothProfile.ConnectionPolicy;
54 import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
55 import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
56 import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
57 import android.bluetooth.annotations.RequiresBluetoothScanPermission;
58 import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
59 import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
60 import android.bluetooth.le.BluetoothLeAdvertiser;
61 import android.bluetooth.le.BluetoothLeScanner;
62 import android.bluetooth.le.DistanceMeasurementManager;
63 import android.bluetooth.le.PeriodicAdvertisingManager;
64 import android.bluetooth.le.ScanCallback;
65 import android.bluetooth.le.ScanFilter;
66 import android.bluetooth.le.ScanRecord;
67 import android.bluetooth.le.ScanResult;
68 import android.bluetooth.le.ScanSettings;
69 import android.compat.annotation.UnsupportedAppUsage;
70 import android.content.AttributionSource;
71 import android.content.Context;
72 import android.content.pm.PackageManager;
73 import android.os.Binder;
74 import android.os.BluetoothServiceManager;
75 import android.os.Build;
76 import android.os.Bundle;
77 import android.os.Handler;
78 import android.os.IBinder;
79 import android.os.IpcDataCache;
80 import android.os.Looper;
81 import android.os.ParcelUuid;
82 import android.os.Process;
83 import android.os.RemoteException;
84 import android.sysprop.BluetoothProperties;
85 import android.util.Log;
86 import android.util.Pair;
87 
88 import com.android.bluetooth.flags.Flags;
89 import com.android.internal.annotations.GuardedBy;
90 import com.android.modules.expresslog.Counter;
91 
92 import java.io.IOException;
93 import java.lang.annotation.Retention;
94 import java.lang.annotation.RetentionPolicy;
95 import java.time.Duration;
96 import java.util.ArrayList;
97 import java.util.Arrays;
98 import java.util.Collections;
99 import java.util.HashMap;
100 import java.util.HashSet;
101 import java.util.List;
102 import java.util.Locale;
103 import java.util.Map;
104 import java.util.Set;
105 import java.util.UUID;
106 import java.util.WeakHashMap;
107 import java.util.concurrent.ConcurrentHashMap;
108 import java.util.concurrent.Executor;
109 import java.util.concurrent.locks.ReentrantReadWriteLock;
110 import java.util.function.BiFunction;
111 import java.util.function.Consumer;
112 
113 /**
114  * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter} lets you perform
115  * fundamental Bluetooth tasks, such as initiate device discovery, query a list of bonded (paired)
116  * devices, instantiate a {@link BluetoothDevice} using a known MAC address, and create a {@link
117  * BluetoothServerSocket} to listen for connection requests from other devices, and start a scan for
118  * Bluetooth LE devices.
119  *
120  * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth adapter, call the {@link
121  * BluetoothManager#getAdapter} function on {@link BluetoothManager}. On JELLY_BEAN_MR1 and below
122  * you will need to use the static {@link #getDefaultAdapter} method instead.
123  *
124  * <p>Fundamentally, this is your starting point for all Bluetooth actions. Once you have the local
125  * adapter, you can get a set of {@link BluetoothDevice} objects representing all paired devices
126  * with {@link #getBondedDevices()}; start device discovery with {@link #startDiscovery()}; or
127  * create a {@link BluetoothServerSocket} to listen for incoming RFComm connection requests with
128  * {@link #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP
129  * Connection-oriented Channels (CoC) connection requests with {@link #listenUsingL2capChannel()};
130  * or start a scan for Bluetooth LE devices with {@link BluetoothLeScanner#startScan(ScanCallback)}
131  * using the scanner from {@link #getBluetoothLeScanner()}.
132  *
133  * <p>This class is thread safe. <div class="special reference">
134  *
135  * <h3>Developer Guides</h3>
136  *
137  * <p>For more information about using Bluetooth, read the <a href=
138  * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide. </div>
139  *
140  * @see BluetoothDevice
141  * @see BluetoothServerSocket
142  */
143 public final class BluetoothAdapter {
144     private static final String TAG = BluetoothAdapter.class.getSimpleName();
145 
146     private static final String DESCRIPTOR = "android.bluetooth.BluetoothAdapter";
147     private static final boolean DBG = true;
148     private static final boolean VDBG = false;
149 
150     /**
151      * Default MAC address reported to a client that does not have the {@link
152      * android.Manifest.permission#LOCAL_MAC_ADDRESS} permission.
153      *
154      * @hide
155      */
156     public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
157 
158     /**
159      * Sentinel error value for this class. Guaranteed to not equal any other integer constant in
160      * this class. Provided as a convenience for functions that require a sentinel error value, for
161      * example:
162      *
163      * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
164      * BluetoothAdapter.ERROR)</code>
165      */
166     public static final int ERROR = Integer.MIN_VALUE;
167 
168     /**
169      * Broadcast Action: The state of the local Bluetooth adapter has been changed.
170      *
171      * <p>For example, Bluetooth has been turned on or off.
172      *
173      * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link #EXTRA_PREVIOUS_STATE}
174      * containing the new and old states respectively.
175      */
176     @RequiresLegacyBluetoothPermission
177     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
178     public static final String ACTION_STATE_CHANGED =
179             "android.bluetooth.adapter.action.STATE_CHANGED";
180 
181     /**
182      * Used as an int extra field in {@link #ACTION_STATE_CHANGED} intents to request the current
183      * power state. Possible values are: {@link #STATE_OFF}, {@link #STATE_TURNING_ON}, {@link
184      * #STATE_ON}, {@link #STATE_TURNING_OFF},
185      */
186     public static final String EXTRA_STATE = "android.bluetooth.adapter.extra.STATE";
187 
188     /**
189      * Used as an int extra field in {@link #ACTION_STATE_CHANGED} intents to request the previous
190      * power state. Possible values are: {@link #STATE_OFF}, {@link #STATE_TURNING_ON}, {@link
191      * #STATE_ON}, {@link #STATE_TURNING_OFF}
192      */
193     public static final String EXTRA_PREVIOUS_STATE =
194             "android.bluetooth.adapter.extra.PREVIOUS_STATE";
195 
196     /** @hide */
197     @IntDef(
198             prefix = {"STATE_"},
199             value = {
200                 STATE_OFF,
201                 STATE_TURNING_ON,
202                 STATE_ON,
203                 STATE_TURNING_OFF,
204                 STATE_BLE_TURNING_ON,
205                 STATE_BLE_ON,
206                 STATE_BLE_TURNING_OFF
207             })
208     @Retention(RetentionPolicy.SOURCE)
209     public @interface InternalAdapterState {}
210 
211     /** @hide */
212     @IntDef(
213             prefix = {"STATE_"},
214             value = {
215                 STATE_OFF,
216                 STATE_TURNING_ON,
217                 STATE_ON,
218                 STATE_TURNING_OFF,
219             })
220     @Retention(RetentionPolicy.SOURCE)
221     public @interface AdapterState {}
222 
223     /** Indicates the local Bluetooth adapter is off. */
224     public static final int STATE_OFF = 10;
225 
226     /**
227      * Indicates the local Bluetooth adapter is turning on. However local clients should wait for
228      * {@link #STATE_ON} before attempting to use the adapter.
229      */
230     public static final int STATE_TURNING_ON = 11;
231 
232     /** Indicates the local Bluetooth adapter is on, and ready for use. */
233     public static final int STATE_ON = 12;
234 
235     /**
236      * Indicates the local Bluetooth adapter is turning off. Local clients should immediately
237      * attempt graceful disconnection of any remote links.
238      */
239     public static final int STATE_TURNING_OFF = 13;
240 
241     /**
242      * Indicates the local Bluetooth adapter is turning Bluetooth LE mode on.
243      *
244      * @hide
245      */
246     public static final int STATE_BLE_TURNING_ON = 14;
247 
248     /**
249      * Indicates the local Bluetooth adapter is in LE only mode.
250      *
251      * @hide
252      */
253     @SystemApi public static final int STATE_BLE_ON = 15;
254 
255     /**
256      * Indicates the local Bluetooth adapter is turning off LE only mode.
257      *
258      * @hide
259      */
260     public static final int STATE_BLE_TURNING_OFF = 16;
261 
262     /**
263      * Used as an optional extra field for the {@link PendingIntent} provided to {@link
264      * #startRfcommServer(String, UUID, PendingIntent)}. This is useful for when an application
265      * registers multiple RFCOMM listeners, and needs a way to determine which service record the
266      * incoming {@link BluetoothSocket} is using.
267      *
268      * @hide
269      */
270     @SystemApi
271     @SuppressLint("ActionValue")
272     public static final String EXTRA_RFCOMM_LISTENER_ID =
273             "android.bluetooth.adapter.extra.RFCOMM_LISTENER_ID";
274 
275     /** @hide */
276     @IntDef(
277             value = {
278                 BluetoothStatusCodes.SUCCESS,
279                 BluetoothStatusCodes.ERROR_TIMEOUT,
280                 BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
281                 BluetoothStatusCodes.RFCOMM_LISTENER_START_FAILED_UUID_IN_USE,
282                 BluetoothStatusCodes.RFCOMM_LISTENER_OPERATION_FAILED_NO_MATCHING_SERVICE_RECORD,
283                 BluetoothStatusCodes.RFCOMM_LISTENER_OPERATION_FAILED_DIFFERENT_APP,
284                 BluetoothStatusCodes.RFCOMM_LISTENER_FAILED_TO_CREATE_SERVER_SOCKET,
285                 BluetoothStatusCodes.RFCOMM_LISTENER_FAILED_TO_CLOSE_SERVER_SOCKET,
286                 BluetoothStatusCodes.RFCOMM_LISTENER_NO_SOCKET_AVAILABLE,
287             })
288     @Retention(RetentionPolicy.SOURCE)
289     public @interface RfcommListenerResult {}
290 
291     /**
292      * Human-readable string helper for AdapterState and InternalAdapterState
293      *
294      * @hide
295      */
296     @SystemApi
297     @RequiresNoPermission
nameForState(@nternalAdapterState int state)298     public static @NonNull String nameForState(@InternalAdapterState int state) {
299         switch (state) {
300             case STATE_OFF:
301                 return "OFF";
302             case STATE_TURNING_ON:
303                 return "TURNING_ON";
304             case STATE_ON:
305                 return "ON";
306             case STATE_TURNING_OFF:
307                 return "TURNING_OFF";
308             case STATE_BLE_TURNING_ON:
309                 return "BLE_TURNING_ON";
310             case STATE_BLE_ON:
311                 return "BLE_ON";
312             case STATE_BLE_TURNING_OFF:
313                 return "BLE_TURNING_OFF";
314             default:
315                 return "?!?!? (" + state + ")";
316         }
317     }
318 
319     /**
320      * Activity Action: Show a system activity that requests discoverable mode. This activity will
321      * also request the user to turn on Bluetooth if it is not currently enabled.
322      *
323      * <p>Discoverable mode is equivalent to {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows
324      * remote devices to see this Bluetooth adapter when they perform a discovery.
325      *
326      * <p>For privacy, Android is not discoverable by default.
327      *
328      * <p>The sender of this Intent can optionally use extra field {@link
329      * #EXTRA_DISCOVERABLE_DURATION} to request the duration of discoverability. Currently the
330      * default duration is 120 seconds, and maximum duration is capped at 300 seconds for each
331      * request.
332      *
333      * <p>Notification of the result of this activity is posted using the {@link
334      * android.app.Activity#onActivityResult} callback. The <code>resultCode</code> will be the
335      * duration (in seconds) of discoverability or {@link android.app.Activity#RESULT_CANCELED} if
336      * the user rejected discoverability or an error has occurred.
337      *
338      * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED} for global notification
339      * whenever the scan mode changes. For example, an application can be notified when the device
340      * has ended discoverability.
341      */
342     @RequiresLegacyBluetoothPermission
343     @RequiresBluetoothAdvertisePermission
344     @RequiresPermission(BLUETOOTH_ADVERTISE)
345     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
346     public static final String ACTION_REQUEST_DISCOVERABLE =
347             "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
348 
349     /**
350      * Used as an optional int extra field in {@link #ACTION_REQUEST_DISCOVERABLE} intents to
351      * request a specific duration for discoverability in seconds. The current default is 120
352      * seconds, and requests over 300 seconds will be capped. These values could change.
353      */
354     public static final String EXTRA_DISCOVERABLE_DURATION =
355             "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION";
356 
357     /**
358      * Activity Action: Show a system activity that allows the user to turn on Bluetooth.
359      *
360      * <p>This system activity will return once Bluetooth has completed turning on, or the user has
361      * decided not to turn Bluetooth on.
362      *
363      * <p>Notification of the result of this activity is posted using the {@link
364      * android.app.Activity#onActivityResult} callback. The <code>resultCode</code> will be {@link
365      * android.app.Activity#RESULT_OK} if Bluetooth has been turned on or {@link
366      * android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an error has
367      * occurred.
368      *
369      * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED} for global notification
370      * whenever Bluetooth is turned on or off.
371      */
372     @RequiresLegacyBluetoothPermission
373     @RequiresBluetoothConnectPermission
374     @RequiresPermission(BLUETOOTH_CONNECT)
375     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
376     public static final String ACTION_REQUEST_ENABLE =
377             "android.bluetooth.adapter.action.REQUEST_ENABLE";
378 
379     /**
380      * Activity Action: Show a system activity that allows the user to turn off Bluetooth. This is
381      * used only if permission review is enabled which is for apps targeting API less than 23
382      * require a permission review before any of the app's components can run.
383      *
384      * <p>This system activity will return once Bluetooth has completed turning off, or the user has
385      * decided not to turn Bluetooth off.
386      *
387      * <p>Notification of the result of this activity is posted using the {@link
388      * android.app.Activity#onActivityResult} callback. The <code>resultCode</code> will be {@link
389      * android.app.Activity#RESULT_OK} if Bluetooth has been turned off or {@link
390      * android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an error has
391      * occurred.
392      *
393      * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED} for global notification
394      * whenever Bluetooth is turned on or off.
395      *
396      * @hide
397      */
398     @SystemApi
399     @RequiresLegacyBluetoothPermission
400     @RequiresBluetoothConnectPermission
401     @RequiresPermission(BLUETOOTH_CONNECT)
402     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
403     @SuppressLint("ActionValue")
404     public static final String ACTION_REQUEST_DISABLE =
405             "android.bluetooth.adapter.action.REQUEST_DISABLE";
406 
407     /**
408      * Activity Action: Show a system activity that allows user to enable BLE scans even when
409      * Bluetooth is turned off.
410      *
411      * <p>Notification of result of this activity is posted using {@link
412      * android.app.Activity#onActivityResult}. The <code>resultCode</code> will be {@link
413      * android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or {@link
414      * android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an error
415      * occurred.
416      *
417      * @hide
418      */
419     @SystemApi
420     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
421     public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE =
422             "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
423 
424     /**
425      * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter has changed.
426      *
427      * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
428      * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes respectively.
429      */
430     @RequiresLegacyBluetoothPermission
431     @RequiresBluetoothScanPermission
432     @RequiresPermission(BLUETOOTH_SCAN)
433     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
434     public static final String ACTION_SCAN_MODE_CHANGED =
435             "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
436 
437     /**
438      * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} intents to request the
439      * current scan mode. Possible values are: {@link #SCAN_MODE_NONE}, {@link
440      * #SCAN_MODE_CONNECTABLE}, {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
441      */
442     public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
443 
444     /**
445      * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} intents to request the
446      * previous scan mode. Possible values are: {@link #SCAN_MODE_NONE}, {@link
447      * #SCAN_MODE_CONNECTABLE}, {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
448      */
449     public static final String EXTRA_PREVIOUS_SCAN_MODE =
450             "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
451 
452     /** @hide */
453     @IntDef(
454             prefix = {"SCAN_"},
455             value = {SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE})
456     @Retention(RetentionPolicy.SOURCE)
457     public @interface ScanMode {}
458 
459     /** @hide */
460     @IntDef(
461             value = {
462                 BluetoothStatusCodes.SUCCESS,
463                 BluetoothStatusCodes.ERROR_UNKNOWN,
464                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
465                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION
466             })
467     @Retention(RetentionPolicy.SOURCE)
468     public @interface ScanModeStatusCode {}
469 
470     /**
471      * Indicates that both inquiry scan and page scan are disabled on the local Bluetooth adapter.
472      * Therefore this device is neither discoverable nor connectable from remote Bluetooth devices.
473      */
474     public static final int SCAN_MODE_NONE = 20;
475 
476     /**
477      * Indicates that inquiry scan is disabled, but page scan is enabled on the local Bluetooth
478      * adapter. Therefore this device is not discoverable from remote Bluetooth devices, but is
479      * connectable from remote devices that have previously discovered this device.
480      */
481     public static final int SCAN_MODE_CONNECTABLE = 21;
482 
483     /**
484      * Indicates that both inquiry scan and page scan are enabled on the local Bluetooth adapter.
485      * Therefore this device is both discoverable and connectable from remote Bluetooth devices.
486      */
487     public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
488 
489     /**
490      * Used as parameter for {@link #setBluetoothHciSnoopLoggingMode}, indicates that the Bluetooth
491      * HCI snoop logging should be disabled.
492      *
493      * @hide
494      */
495     @SystemApi public static final int BT_SNOOP_LOG_MODE_DISABLED = 0;
496 
497     /**
498      * Used as parameter for {@link #setBluetoothHciSnoopLoggingMode}, indicates that the Bluetooth
499      * HCI snoop logging should be enabled without collecting potential Personally Identifiable
500      * Information and packet data.
501      *
502      * <p>See {@link #BT_SNOOP_LOG_MODE_FULL} to enable logging of all information available.
503      *
504      * @hide
505      */
506     @SystemApi public static final int BT_SNOOP_LOG_MODE_FILTERED = 1;
507 
508     /**
509      * Used as parameter for {@link #setBluetoothHciSnoopLoggingMode}, indicates that the Bluetooth
510      * HCI snoop logging should be enabled.
511      *
512      * <p>See {@link #BT_SNOOP_LOG_MODE_FILTERED} to enable logging with filtered information.
513      *
514      * @hide
515      */
516     @SystemApi public static final int BT_SNOOP_LOG_MODE_FULL = 2;
517 
518     /** @hide */
519     @IntDef(
520             value = {
521                 BT_SNOOP_LOG_MODE_DISABLED,
522                 BT_SNOOP_LOG_MODE_FILTERED,
523                 BT_SNOOP_LOG_MODE_FULL
524             })
525     @Retention(RetentionPolicy.SOURCE)
526     public @interface BluetoothSnoopLogMode {}
527 
528     /** @hide */
529     @IntDef(
530             value = {
531                 BluetoothStatusCodes.SUCCESS,
532                 BluetoothStatusCodes.ERROR_UNKNOWN,
533             })
534     @Retention(RetentionPolicy.SOURCE)
535     public @interface SetSnoopLogModeStatusCode {}
536 
537     /** @hide */
538     @IntDef(
539             prefix = "ACTIVE_DEVICE_",
540             value = {ACTIVE_DEVICE_AUDIO, ACTIVE_DEVICE_PHONE_CALL, ACTIVE_DEVICE_ALL})
541     @Retention(RetentionPolicy.SOURCE)
542     public @interface ActiveDeviceUse {}
543 
544     /**
545      * Use the specified device for audio (a2dp and hearing aid profile)
546      *
547      * @hide
548      */
549     @SystemApi public static final int ACTIVE_DEVICE_AUDIO = 0;
550 
551     /**
552      * Use the specified device for phone calls (headset profile and hearing aid profile)
553      *
554      * @hide
555      */
556     @SystemApi public static final int ACTIVE_DEVICE_PHONE_CALL = 1;
557 
558     /**
559      * Use the specified device for a2dp, hearing aid profile, and headset profile
560      *
561      * @hide
562      */
563     @SystemApi public static final int ACTIVE_DEVICE_ALL = 2;
564 
565     /** @hide */
566     @IntDef({BluetoothProfile.HEADSET, BluetoothProfile.A2DP, BluetoothProfile.HEARING_AID})
567     @Retention(RetentionPolicy.SOURCE)
568     public @interface ActiveDeviceProfile {}
569 
570     /**
571      * Broadcast Action: The local Bluetooth adapter has started the remote device discovery
572      * process.
573      *
574      * <p>This usually involves an inquiry scan of about 12 seconds, followed by a page scan of each
575      * new device to retrieve its Bluetooth name.
576      *
577      * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth
578      * devices are found.
579      *
580      * <p>Device discovery is a heavyweight procedure. New connections to remote Bluetooth devices
581      * should not be attempted while discovery is in progress, and existing connections will
582      * experience limited bandwidth and high latency. Use {@link #cancelDiscovery()} to cancel an
583      * ongoing discovery.
584      */
585     @RequiresLegacyBluetoothPermission
586     @RequiresBluetoothScanPermission
587     @RequiresPermission(BLUETOOTH_SCAN)
588     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
589     public static final String ACTION_DISCOVERY_STARTED =
590             "android.bluetooth.adapter.action.DISCOVERY_STARTED";
591 
592     /** Broadcast Action: The local Bluetooth adapter has finished the device discovery process. */
593     @RequiresLegacyBluetoothPermission
594     @RequiresBluetoothScanPermission
595     @RequiresPermission(BLUETOOTH_SCAN)
596     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
597     public static final String ACTION_DISCOVERY_FINISHED =
598             "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
599 
600     /**
601      * Broadcast Action: The local Bluetooth adapter has changed its friendly Bluetooth name.
602      *
603      * <p>This name is visible to remote Bluetooth devices.
604      *
605      * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing the name.
606      */
607     @RequiresLegacyBluetoothPermission
608     @RequiresBluetoothConnectPermission
609     @RequiresPermission(BLUETOOTH_CONNECT)
610     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
611     public static final String ACTION_LOCAL_NAME_CHANGED =
612             "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
613 
614     /**
615      * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED} intents to request the
616      * local Bluetooth name.
617      */
618     public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
619 
620     /**
621      * Intent used to broadcast the change in connection state of the local Bluetooth adapter to a
622      * profile of the remote device. When the adapter is not connected to any profiles of any remote
623      * devices and it attempts a connection to a profile this intent will be sent. Once connected,
624      * this intent will not be sent for any more connection attempts to any profiles of any remote
625      * device. When the adapter disconnects from the last profile its connected to of any remote
626      * device, this intent will be sent.
627      *
628      * <p>This intent is useful for applications that are only concerned about whether the local
629      * adapter is connected to any profile of any device and are not really concerned about which
630      * profile. For example, an application which displays an icon to display whether Bluetooth is
631      * connected or not can use this intent.
632      *
633      * <p>This intent will have 3 extras: {@link #EXTRA_CONNECTION_STATE} - The current connection
634      * state. {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state. {@link
635      * BluetoothDevice#EXTRA_DEVICE} - The remote device.
636      *
637      * <p>{@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE} can be any of
638      * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link
639      * #STATE_DISCONNECTING}.
640      */
641     @RequiresLegacyBluetoothPermission
642     @RequiresBluetoothConnectPermission
643     @RequiresPermission(BLUETOOTH_CONNECT)
644     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
645     public static final String ACTION_CONNECTION_STATE_CHANGED =
646             "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
647 
648     /**
649      * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
650      *
651      * <p>This extra represents the current connection state.
652      */
653     public static final String EXTRA_CONNECTION_STATE =
654             "android.bluetooth.adapter.extra.CONNECTION_STATE";
655 
656     /**
657      * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
658      *
659      * <p>This extra represents the previous connection state.
660      */
661     public static final String EXTRA_PREVIOUS_CONNECTION_STATE =
662             "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
663 
664     /**
665      * Broadcast Action: The Bluetooth adapter state has changed in LE only mode.
666      *
667      * @hide
668      */
669     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
670     @SystemApi
671     public static final String ACTION_BLE_STATE_CHANGED =
672             "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
673 
674     /**
675      * Intent used to broadcast the change in the Bluetooth address of the local Bluetooth adapter.
676      *
677      * <p>Always contains the extra field {@link #EXTRA_BLUETOOTH_ADDRESS} containing the Bluetooth
678      * address.
679      *
680      * <p>Note: only system level processes are allowed to send this defined broadcast.
681      *
682      * @hide
683      */
684     @RequiresBluetoothConnectPermission
685     @RequiresPermission(BLUETOOTH_CONNECT)
686     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
687     public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED =
688             "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED";
689 
690     /**
691      * Used as a String extra field in {@link #ACTION_BLUETOOTH_ADDRESS_CHANGED} intent to store the
692      * local Bluetooth address.
693      *
694      * @hide
695      */
696     public static final String EXTRA_BLUETOOTH_ADDRESS =
697             "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS";
698 
699     /**
700      * Broadcast Action: The notifys Bluetooth ACL connected event. This will be by BLE Always on
701      * enabled application to know the ACL_CONNECTED event when Bluetooth state in STATE_BLE_ON.
702      * This denotes GATT connection as Bluetooth LE is the only feature available in STATE_BLE_ON
703      *
704      * <p>This is counterpart of {@link BluetoothDevice#ACTION_ACL_CONNECTED} which works in
705      * Bluetooth state STATE_ON
706      *
707      * @hide
708      */
709     @RequiresBluetoothConnectPermission
710     @RequiresPermission(BLUETOOTH_CONNECT)
711     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
712     public static final String ACTION_BLE_ACL_CONNECTED =
713             "android.bluetooth.adapter.action.BLE_ACL_CONNECTED";
714 
715     /**
716      * Broadcast Action: The notifys Bluetooth ACL connected event. This will be by BLE Always on
717      * enabled application to know the ACL_DISCONNECTED event when Bluetooth state in STATE_BLE_ON.
718      * This denotes GATT disconnection as Bluetooth LE is the only feature available in STATE_BLE_ON
719      *
720      * <p>This is counterpart of {@link BluetoothDevice#ACTION_ACL_DISCONNECTED} which works in
721      * Bluetooth state STATE_ON
722      *
723      * @hide
724      */
725     @RequiresBluetoothConnectPermission
726     @RequiresPermission(BLUETOOTH_CONNECT)
727     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
728     public static final String ACTION_BLE_ACL_DISCONNECTED =
729             "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED";
730 
731     /** The profile is in disconnected state */
732     public static final int STATE_DISCONNECTED =
733             0; // BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED;
734 
735     /** The profile is in connecting state */
736     public static final int STATE_CONNECTING =
737             1; // BluetoothProtoEnums.CONNECTION_STATE_CONNECTING;
738 
739     /** The profile is in connected state */
740     public static final int STATE_CONNECTED = 2; // BluetoothProtoEnums.CONNECTION_STATE_CONNECTED;
741 
742     /** The profile is in disconnecting state */
743     public static final int STATE_DISCONNECTING =
744             3; // BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING;
745 
746     /** @hide */
747     @Retention(RetentionPolicy.SOURCE)
748     @IntDef(
749             prefix = {"STATE_"},
750             value = {
751                 STATE_DISCONNECTED,
752                 STATE_CONNECTING,
753                 STATE_CONNECTED,
754                 STATE_DISCONNECTING,
755             })
756     public @interface ConnectionState {}
757 
758     /**
759      * Broadcast Action: The AutoOn feature state has been changed for one user
760      *
761      * <p>Always contains the extra fields {@link #EXTRA_AUTO_ON_STATE}
762      *
763      * @hide
764      */
765     @SystemApi
766     @RequiresPermission(BLUETOOTH_PRIVILEGED)
767     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
768     @BroadcastBehavior(registeredOnly = true, protectedBroadcast = true)
769     public static final String ACTION_AUTO_ON_STATE_CHANGED =
770             "android.bluetooth.action.AUTO_ON_STATE_CHANGED";
771 
772     /**
773      * Used as an int extra field in {@link #ACTION_AUTO_ON_STATE_CHANGED} intents.
774      *
775      * <p>Possible values are: {@link #AUTO_ON_STATE_DISABLED}, {@link #AUTO_ON_STATE_ENABLED}
776      *
777      * @hide
778      */
779     @SystemApi
780     public static final String EXTRA_AUTO_ON_STATE = "android.bluetooth.extra.AUTO_ON_STATE";
781 
782     /**
783      * Indicates the AutoOn feature is OFF.
784      *
785      * @hide
786      */
787     @SystemApi
788     public static final int AUTO_ON_STATE_DISABLED = 1;
789 
790     /**
791      * Indicates the AutoOn feature is ON.
792      *
793      * @hide
794      */
795     @SystemApi
796     public static final int AUTO_ON_STATE_ENABLED = 2;
797 
798     /**
799      * Audio mode representing output only.
800      *
801      * @hide
802      */
803     @SystemApi public static final String AUDIO_MODE_OUTPUT_ONLY = "audio_mode_output_only";
804 
805     /**
806      * Audio mode representing both output and microphone input.
807      *
808      * @hide
809      */
810     @SystemApi public static final String AUDIO_MODE_DUPLEX = "audio_mode_duplex";
811 
812     /** @hide */
813     public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
814 
815     private final IBinder mToken = new Binder(DESCRIPTOR);
816 
817     /**
818      * When creating a ServerSocket using listenUsingRfcommOn() or listenUsingL2capOn() use
819      * SOCKET_CHANNEL_AUTO_STATIC to create a ServerSocket that auto assigns a channel number to the
820      * first bluetooth socket. The channel number assigned to this first Bluetooth Socket will be
821      * stored in the ServerSocket, and reused for subsequent Bluetooth sockets.
822      *
823      * @hide
824      */
825     public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2;
826 
827     /** @hide */
828     public static final Map<Integer, BiFunction<Context, BluetoothAdapter, BluetoothProfile>>
829             PROFILE_CONSTRUCTORS =
830                     Map.ofEntries(
831                             Map.entry(BluetoothProfile.HEADSET, BluetoothHeadset::new),
832                             Map.entry(BluetoothProfile.A2DP, BluetoothA2dp::new),
833                             Map.entry(BluetoothProfile.A2DP_SINK, BluetoothA2dpSink::new),
834                             Map.entry(
835                                     BluetoothProfile.AVRCP_CONTROLLER,
836                                     BluetoothAvrcpController::new),
837                             Map.entry(BluetoothProfile.HID_HOST, BluetoothHidHost::new),
838                             Map.entry(BluetoothProfile.PAN, BluetoothPan::new),
839                             Map.entry(BluetoothProfile.PBAP, BluetoothPbap::new),
840                             Map.entry(BluetoothProfile.MAP, BluetoothMap::new),
841                             Map.entry(BluetoothProfile.HEADSET_CLIENT, BluetoothHeadsetClient::new),
842                             Map.entry(BluetoothProfile.SAP, BluetoothSap::new),
843                             Map.entry(BluetoothProfile.PBAP_CLIENT, BluetoothPbapClient::new),
844                             Map.entry(BluetoothProfile.MAP_CLIENT, BluetoothMapClient::new),
845                             Map.entry(BluetoothProfile.HID_DEVICE, BluetoothHidDevice::new),
846                             Map.entry(BluetoothProfile.HAP_CLIENT, BluetoothHapClient::new),
847                             Map.entry(BluetoothProfile.HEARING_AID, BluetoothHearingAid::new),
848                             Map.entry(BluetoothProfile.LE_AUDIO, BluetoothLeAudio::new),
849                             Map.entry(
850                                     BluetoothProfile.LE_AUDIO_BROADCAST, BluetoothLeBroadcast::new),
851                             Map.entry(BluetoothProfile.VOLUME_CONTROL, BluetoothVolumeControl::new),
852                             Map.entry(
853                                     BluetoothProfile.CSIP_SET_COORDINATOR,
854                                     BluetoothCsipSetCoordinator::new),
855                             Map.entry(
856                                     BluetoothProfile.LE_CALL_CONTROL, BluetoothLeCallControl::new),
857                             Map.entry(
858                                     BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT,
859                                     BluetoothLeBroadcastAssistant::new));
860 
861     private static final int ADDRESS_LENGTH = 17;
862 
863     /** Lazily initialized singleton. Guaranteed final after first object constructed. */
864     private static BluetoothAdapter sAdapter;
865 
866     private BluetoothLeScanner mBluetoothLeScanner;
867     private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
868     private PeriodicAdvertisingManager mPeriodicAdvertisingManager;
869     private DistanceMeasurementManager mDistanceMeasurementManager;
870 
871     private final IBluetoothManager mManagerService;
872     private final AttributionSource mAttributionSource;
873 
874     // Yeah, keeping both mService and sService isn't pretty, but it's too late
875     // in the current release for a major refactoring, so we leave them both
876     // intact until this can be cleaned up in a future release
877 
878     @UnsupportedAppUsage
879     @GuardedBy("mServiceLock")
880     private IBluetooth mService;
881 
882     private static final ReentrantReadWriteLock sServiceLock = new ReentrantReadWriteLock();
883     private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
884 
885     @GuardedBy("sServiceLock")
886     private static boolean sServiceRegistered;
887 
888     @GuardedBy("sServiceLock")
889     private static IBluetooth sService;
890 
891     private final Object mLock = new Object();
892     private final Map<LeScanCallback, ScanCallback> mLeScanClients = new HashMap<>();
893     private final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
894             mMetadataListeners = new HashMap<>();
895 
896     private static final class ProfileConnection {
897         private final int mProfile;
898         private final BluetoothProfile.ServiceListener mListener;
899         private final Executor mExecutor;
900 
901         @GuardedBy("BluetoothAdapter.sProfileLock")
902         boolean mConnected = false;
903 
ProfileConnection( int profile, BluetoothProfile.ServiceListener listener, Executor executor)904         ProfileConnection(
905                 int profile, BluetoothProfile.ServiceListener listener, Executor executor) {
906             mProfile = profile;
907             mListener = listener;
908             mExecutor = executor;
909         }
910 
911         @GuardedBy("BluetoothAdapter.sProfileLock")
connect(BluetoothProfile proxy, IBinder binder)912         void connect(BluetoothProfile proxy, IBinder binder) {
913             Log.d(TAG, getProfileName(mProfile) + " connected");
914             mConnected = true;
915             proxy.onServiceConnected(binder);
916             executeFromBinder(mExecutor, () -> mListener.onServiceConnected(mProfile, proxy));
917         }
918 
919         @GuardedBy("BluetoothAdapter.sProfileLock")
disconnect(BluetoothProfile proxy)920         void disconnect(BluetoothProfile proxy) {
921             Log.d(TAG, getProfileName(mProfile) + " disconnected");
922             mConnected = false;
923             proxy.onServiceDisconnected();
924             executeFromBinder(mExecutor, () -> mListener.onServiceDisconnected(mProfile));
925         }
926     }
927 
928     private static final Object sProfileLock = new Object();
929 
930     @GuardedBy("sProfileLock")
931     private final Map<BluetoothProfile, ProfileConnection> mProfileConnections =
932             new ConcurrentHashMap<>();
933 
934     private final Handler mMainHandler = new Handler(Looper.getMainLooper());
935 
936     /**
937      * Bluetooth metadata listener. Overrides the default BluetoothMetadataListener implementation.
938      */
939     private final IBluetoothMetadataListener mBluetoothMetadataListener =
940             new IBluetoothMetadataListener.Stub() {
941                 @Override
942                 @RequiresNoPermission
943                 public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) {
944                     Attributable.setAttributionSource(device, mAttributionSource);
945                     synchronized (mMetadataListeners) {
946                         if (!mMetadataListeners.containsKey(device)) {
947                             return;
948                         }
949                         List<Pair<OnMetadataChangedListener, Executor>> list =
950                                 mMetadataListeners.get(device);
951                         for (Pair<OnMetadataChangedListener, Executor> pair : list) {
952                             OnMetadataChangedListener listener = pair.first;
953                             Executor executor = pair.second;
954                             executeFromBinder(
955                                     executor,
956                                     () -> {
957                                         listener.onMetadataChanged(device, key, value);
958                                     });
959                         }
960                     }
961                 }
962             };
963 
964     /** @hide */
965     @IntDef(
966             value = {
967                 BluetoothStatusCodes.ERROR_UNKNOWN,
968                 BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
969                 BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
970             })
971     @Retention(RetentionPolicy.SOURCE)
972     public @interface BluetoothActivityEnergyInfoCallbackError {}
973 
974     /**
975      * Interface for Bluetooth activity energy info callback. Should be implemented by applications
976      * and set when calling {@link #requestControllerActivityEnergyInfo}.
977      *
978      * @hide
979      */
980     @SystemApi
981     public interface OnBluetoothActivityEnergyInfoCallback {
982         /**
983          * Called when Bluetooth activity energy info is available. Note: this callback is triggered
984          * at most once for each call to {@link #requestControllerActivityEnergyInfo}.
985          *
986          * @param info the latest {@link BluetoothActivityEnergyInfo}
987          */
onBluetoothActivityEnergyInfoAvailable(@onNull BluetoothActivityEnergyInfo info)988         void onBluetoothActivityEnergyInfoAvailable(@NonNull BluetoothActivityEnergyInfo info);
989 
990         /**
991          * Called when the latest {@link BluetoothActivityEnergyInfo} can't be retrieved. The reason
992          * of the failure is indicated by the {@link BluetoothStatusCodes} passed as an argument to
993          * this method. Note: this callback is triggered at most once for each call to {@link
994          * #requestControllerActivityEnergyInfo}.
995          *
996          * @param error code indicating the reason for the failure
997          */
onBluetoothActivityEnergyInfoError( @luetoothActivityEnergyInfoCallbackError int error)998         void onBluetoothActivityEnergyInfoError(
999                 @BluetoothActivityEnergyInfoCallbackError int error);
1000     }
1001 
1002     private static class OnBluetoothActivityEnergyInfoProxy
1003             extends IBluetoothActivityEnergyInfoListener.Stub {
1004         private final Object mLock = new Object();
1005 
1006         @Nullable
1007         @GuardedBy("mLock")
1008         private Executor mExecutor;
1009 
1010         @Nullable
1011         @GuardedBy("mLock")
1012         private OnBluetoothActivityEnergyInfoCallback mCallback;
1013 
OnBluetoothActivityEnergyInfoProxy( Executor executor, OnBluetoothActivityEnergyInfoCallback callback)1014         OnBluetoothActivityEnergyInfoProxy(
1015                 Executor executor, OnBluetoothActivityEnergyInfoCallback callback) {
1016             mExecutor = executor;
1017             mCallback = callback;
1018         }
1019 
1020         @Override
1021         @RequiresNoPermission
onBluetoothActivityEnergyInfoAvailable(BluetoothActivityEnergyInfo info)1022         public void onBluetoothActivityEnergyInfoAvailable(BluetoothActivityEnergyInfo info) {
1023             Executor executor;
1024             OnBluetoothActivityEnergyInfoCallback callback;
1025             synchronized (mLock) {
1026                 if (mExecutor == null || mCallback == null) {
1027                     return;
1028                 }
1029                 executor = mExecutor;
1030                 callback = mCallback;
1031                 mExecutor = null;
1032                 mCallback = null;
1033             }
1034             if (info == null) {
1035                 executeFromBinder(
1036                         executor,
1037                         () -> callback.onBluetoothActivityEnergyInfoError(FEATURE_NOT_SUPPORTED));
1038             } else {
1039                 executeFromBinder(
1040                         executor, () -> callback.onBluetoothActivityEnergyInfoAvailable(info));
1041             }
1042         }
1043 
1044         /** Framework only method that is called when the service can't be reached. */
1045         @RequiresNoPermission
onError(int errorCode)1046         public void onError(int errorCode) {
1047             Executor executor;
1048             OnBluetoothActivityEnergyInfoCallback callback;
1049             synchronized (mLock) {
1050                 if (mExecutor == null || mCallback == null) {
1051                     return;
1052                 }
1053                 executor = mExecutor;
1054                 callback = mCallback;
1055                 mExecutor = null;
1056                 mCallback = null;
1057             }
1058             executeFromBinder(
1059                     executor, () -> callback.onBluetoothActivityEnergyInfoError(errorCode));
1060         }
1061     }
1062 
1063     /**
1064      * Get a handle to the default local Bluetooth adapter.
1065      *
1066      * <p>Currently Android only supports one Bluetooth adapter, but the API could be extended to
1067      * support more. This will always return the default adapter.
1068      *
1069      * @return the default local adapter, or null if Bluetooth is not supported on this hardware
1070      *     platform
1071      * @deprecated this method will continue to work, but developers are strongly encouraged to
1072      *     migrate to using {@link BluetoothManager#getAdapter()}, since that approach enables
1073      *     support for {@link Context#createAttributionContext}.
1074      */
1075     @Deprecated
1076     @RequiresNoPermission
getDefaultAdapter()1077     public static synchronized BluetoothAdapter getDefaultAdapter() {
1078         if (sAdapter == null) {
1079             sAdapter = createAdapter(AttributionSource.myAttributionSource());
1080         }
1081         return sAdapter;
1082     }
1083 
1084     /** @hide */
createAdapter(AttributionSource attributionSource)1085     public static BluetoothAdapter createAdapter(AttributionSource attributionSource) {
1086         BluetoothServiceManager manager =
1087                 BluetoothFrameworkInitializer.getBluetoothServiceManager();
1088         if (manager == null) {
1089             Log.e(TAG, "BluetoothServiceManager is null");
1090             return null;
1091         }
1092         IBluetoothManager service =
1093                 IBluetoothManager.Stub.asInterface(
1094                         manager.getBluetoothManagerServiceRegisterer().get());
1095         if (service != null) {
1096             return new BluetoothAdapter(service, attributionSource);
1097         } else {
1098             Log.e(TAG, "Bluetooth service is null");
1099             return null;
1100         }
1101     }
1102 
1103     /** Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance. */
BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource)1104     BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) {
1105         mManagerService = requireNonNull(managerService);
1106         mAttributionSource = requireNonNull(attributionSource);
1107 
1108         mQualityCallbackWrapper =
1109                 new CallbackWrapper<>(
1110                         this::registerBluetoothQualityReportCallbackFn,
1111                         this::unregisterBluetoothQualityReportCallbackFn);
1112         mAudioProfilesCallbackWrapper =
1113                 new CallbackWrapper<>(
1114                         this::registerAudioProfilesCallbackFn,
1115                         this::unregisterAudioProfilesCallbackFn);
1116         mBluetoothConnectionCallbackWrapper =
1117                 new CallbackWrapper<>(
1118                         this::registerBluetoothConnectionCallbackFn,
1119                         this::unregisterBluetoothConnectionCallbackFn);
1120 
1121         mServiceLock.writeLock().lock();
1122         try {
1123             mService = registerBluetoothManagerCallback(mManagerCallback);
1124         } finally {
1125             mServiceLock.writeLock().unlock();
1126         }
1127     }
1128 
1129     /**
1130      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware address.
1131      *
1132      * <p>Valid Bluetooth hardware addresses must be upper case, in big endian byte order, and in a
1133      * format such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is available to
1134      * validate a Bluetooth address.
1135      *
1136      * <p>A {@link BluetoothDevice} will always be returned for a valid hardware address, even if
1137      * this adapter has never seen that device.
1138      *
1139      * @param address valid Bluetooth MAC address
1140      * @throws IllegalArgumentException if address is invalid
1141      */
1142     @RequiresNoPermission
getRemoteDevice(String address)1143     public BluetoothDevice getRemoteDevice(String address) {
1144         final BluetoothDevice res = new BluetoothDevice(address);
1145         res.setAttributionSource(mAttributionSource);
1146         return res;
1147     }
1148 
1149     /**
1150      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware address and
1151      * addressType.
1152      *
1153      * <p>Valid Bluetooth hardware addresses must be upper case, in big endian byte order, and in a
1154      * format such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is available to
1155      * validate a Bluetooth address.
1156      *
1157      * <p>A {@link BluetoothDevice} will always be returned for a valid hardware address and type,
1158      * even if this adapter has never seen that device.
1159      *
1160      * @param address valid Bluetooth MAC address
1161      * @param addressType Bluetooth address type
1162      * @throws IllegalArgumentException if address is invalid
1163      */
1164     @RequiresNoPermission
1165     @NonNull
getRemoteLeDevice( @onNull String address, @AddressType int addressType)1166     public BluetoothDevice getRemoteLeDevice(
1167             @NonNull String address, @AddressType int addressType) {
1168         final BluetoothDevice res = new BluetoothDevice(address, addressType);
1169         res.setAttributionSource(mAttributionSource);
1170         return res;
1171     }
1172 
1173     /**
1174      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware address.
1175      *
1176      * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method expects the address in
1177      * network byte order (MSB first).
1178      *
1179      * <p>A {@link BluetoothDevice} will always be returned for a valid hardware address, even if
1180      * this adapter has never seen that device.
1181      *
1182      * @param address Bluetooth MAC address (6 bytes)
1183      * @throws IllegalArgumentException if address is invalid
1184      */
1185     @RequiresNoPermission
getRemoteDevice(byte[] address)1186     public BluetoothDevice getRemoteDevice(byte[] address) {
1187         if (address == null || address.length != 6) {
1188             throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
1189         }
1190         final BluetoothDevice res =
1191                 new BluetoothDevice(
1192                         String.format(
1193                                 Locale.US,
1194                                 "%02X:%02X:%02X:%02X:%02X:%02X",
1195                                 address[0],
1196                                 address[1],
1197                                 address[2],
1198                                 address[3],
1199                                 address[4],
1200                                 address[5]));
1201         res.setAttributionSource(mAttributionSource);
1202         return res;
1203     }
1204 
1205     /**
1206      * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations. Will
1207      * return null if Bluetooth is turned off or if Bluetooth LE Advertising is not supported on
1208      * this device.
1209      *
1210      * <p>Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is
1211      * supported on this device before calling this method.
1212      */
1213     @RequiresNoPermission
getBluetoothLeAdvertiser()1214     public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
1215         if (!getLeAccess()) {
1216             return null;
1217         }
1218         synchronized (mLock) {
1219             if (mBluetoothLeAdvertiser == null) {
1220                 mBluetoothLeAdvertiser = new BluetoothLeAdvertiser(this);
1221             }
1222             return mBluetoothLeAdvertiser;
1223         }
1224     }
1225 
1226     /**
1227      * Returns a {@link PeriodicAdvertisingManager} object for Bluetooth LE Periodic Advertising
1228      * operations. Will return null if Bluetooth is turned off or if Bluetooth LE Periodic
1229      * Advertising is not supported on this device.
1230      *
1231      * <p>Use {@link #isLePeriodicAdvertisingSupported()} to check whether LE Periodic Advertising
1232      * is supported on this device before calling this method.
1233      *
1234      * @hide
1235      */
1236     @RequiresNoPermission
getPeriodicAdvertisingManager()1237     public PeriodicAdvertisingManager getPeriodicAdvertisingManager() {
1238         if (!getLeAccess()) {
1239             return null;
1240         }
1241 
1242         if (!isLePeriodicAdvertisingSupported()) {
1243             return null;
1244         }
1245 
1246         synchronized (mLock) {
1247             if (mPeriodicAdvertisingManager == null) {
1248                 mPeriodicAdvertisingManager = new PeriodicAdvertisingManager(this);
1249             }
1250             return mPeriodicAdvertisingManager;
1251         }
1252     }
1253 
1254     /** Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations. */
1255     @RequiresNoPermission
getBluetoothLeScanner()1256     public BluetoothLeScanner getBluetoothLeScanner() {
1257         if (!getLeAccess()) {
1258             return null;
1259         }
1260         synchronized (mLock) {
1261             if (mBluetoothLeScanner == null) {
1262                 mBluetoothLeScanner = new BluetoothLeScanner(this);
1263             }
1264             return mBluetoothLeScanner;
1265         }
1266     }
1267 
1268     /**
1269      * Get a {@link DistanceMeasurementManager} object for distance measurement operations.
1270      *
1271      * <p>Use {@link #isDistanceMeasurementSupported()} to check whether distance measurement is
1272      * supported on this device before calling this method.
1273      *
1274      * @return a new instance of {@link DistanceMeasurementManager}, or {@code null} if Bluetooth is
1275      *     turned off
1276      * @throws UnsupportedOperationException if distance measurement is not supported on this device
1277      * @hide
1278      */
1279     @SystemApi
1280     @RequiresBluetoothConnectPermission
1281     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getDistanceMeasurementManager()1282     public @Nullable DistanceMeasurementManager getDistanceMeasurementManager() {
1283         if (!getLeAccess()) {
1284             return null;
1285         }
1286 
1287         if (isDistanceMeasurementSupported() != BluetoothStatusCodes.FEATURE_SUPPORTED) {
1288             throw new UnsupportedOperationException("Distance measurement is unsupported");
1289         }
1290 
1291         synchronized (mLock) {
1292             if (mDistanceMeasurementManager == null) {
1293                 mDistanceMeasurementManager = new DistanceMeasurementManager(this);
1294             }
1295             return mDistanceMeasurementManager;
1296         }
1297     }
1298 
1299     /**
1300      * Return true if Bluetooth is currently enabled and ready for use.
1301      *
1302      * <p>Equivalent to: <code>getBluetoothState() == STATE_ON</code>
1303      *
1304      * @return true if the local adapter is turned on
1305      */
1306     @RequiresLegacyBluetoothPermission
1307     @RequiresNoPermission
isEnabled()1308     public boolean isEnabled() {
1309         return getState() == BluetoothAdapter.STATE_ON;
1310     }
1311 
1312     /**
1313      * Return true if Bluetooth LE(Always BLE On feature) is currently enabled and ready for use
1314      *
1315      * <p>This returns true if current state is either STATE_ON or STATE_BLE_ON
1316      *
1317      * @return true if the local Bluetooth LE adapter is turned on
1318      * @hide
1319      */
1320     @SystemApi
1321     @RequiresNoPermission
isLeEnabled()1322     public boolean isLeEnabled() {
1323         final int state = getLeState();
1324         if (DBG) {
1325             Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state));
1326         }
1327         return (state == BluetoothAdapter.STATE_ON
1328                 || state == BluetoothAdapter.STATE_BLE_ON
1329                 || state == BluetoothAdapter.STATE_TURNING_ON
1330                 || state == BluetoothAdapter.STATE_TURNING_OFF);
1331     }
1332 
1333     /**
1334      * Turns off Bluetooth LE which was earlier turned on by calling enableBLE().
1335      *
1336      * <p>If the internal Adapter state is STATE_BLE_ON, this would trigger the transition to
1337      * STATE_OFF and completely shut-down Bluetooth
1338      *
1339      * <p>If the Adapter state is STATE_ON, This would unregister the existence of special Bluetooth
1340      * LE application and hence the further turning off of Bluetooth from UI would ensure the
1341      * complete turn-off of Bluetooth rather than staying back BLE only state
1342      *
1343      * <p>This is an asynchronous call: it will return immediately, and clients should listen for
1344      * {@link #ACTION_BLE_STATE_CHANGED} to be notified of subsequent adapter state changes If this
1345      * call returns true, then the adapter state will immediately transition from {@link #STATE_ON}
1346      * to {@link #STATE_TURNING_OFF}, and some time later transition to either {@link #STATE_BLE_ON}
1347      * or {@link #STATE_OFF} based on the existence of the further Always BLE ON enabled
1348      * applications If this call returns false then there was an immediate problem that will prevent
1349      * the QAdapter from being turned off - such as the QAadapter already being turned off.
1350      *
1351      * @return true to indicate success, or false on immediate error
1352      * @hide
1353      */
1354     @SystemApi
1355     @RequiresBluetoothConnectPermission
1356     @RequiresPermission(BLUETOOTH_CONNECT)
disableBLE()1357     public boolean disableBLE() {
1358         if (!isBleScanAlwaysAvailable()) {
1359             return false;
1360         }
1361         try {
1362             return mManagerService.disableBle(mAttributionSource, mToken);
1363         } catch (RemoteException e) {
1364             throw e.rethrowFromSystemServer();
1365         }
1366     }
1367 
1368     /**
1369      * Applications who want to only use Bluetooth Low Energy (BLE) can call enableBLE.
1370      *
1371      * <p>enableBLE registers the existence of an app using only LE functions.
1372      *
1373      * <p>enableBLE may enable Bluetooth to an LE only mode so that an app can use LE related
1374      * features (BluetoothGatt or BluetoothGattServer classes)
1375      *
1376      * <p>If the user disables Bluetooth while an app is registered to use LE only features,
1377      * Bluetooth will remain on in LE only mode for the app.
1378      *
1379      * <p>When Bluetooth is in LE only mode, it is not shown as ON to the UI.
1380      *
1381      * <p>This is an asynchronous call: it returns immediately, and clients should listen for {@link
1382      * #ACTION_BLE_STATE_CHANGED} to be notified of adapter state changes.
1383      *
1384      * <p>If this call returns * true, then the adapter state is either in a mode where LE is
1385      * available, or will transition from {@link #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, and
1386      * some time later transition to either {@link #STATE_OFF} or {@link #STATE_BLE_ON}.
1387      *
1388      * <p>If this call returns false then there was an immediate problem that prevents the adapter
1389      * from being turned on - such as Airplane mode.
1390      *
1391      * <p>{@link #ACTION_BLE_STATE_CHANGED} returns the Bluetooth Adapter's various states, It
1392      * includes all the classic Bluetooth Adapter states along with internal BLE only states
1393      *
1394      * @return true to indicate Bluetooth LE will be available, or false on immediate error
1395      * @hide
1396      */
1397     @SystemApi
1398     @RequiresBluetoothConnectPermission
1399     @RequiresPermission(BLUETOOTH_CONNECT)
enableBLE()1400     public boolean enableBLE() {
1401         if (!isBleScanAlwaysAvailable()) {
1402             return false;
1403         }
1404         try {
1405             return mManagerService.enableBle(mAttributionSource, mToken);
1406         } catch (RemoteException e) {
1407             throw e.rethrowFromSystemServer();
1408         }
1409     }
1410 
1411     /**
1412      * There are several instances of IpcDataCache used in this class. BluetoothCache wraps up the
1413      * common code. All caches are created with a maximum of eight entries, and the key is in the
1414      * bluetooth module. The name is set to the api.
1415      */
1416     private static class BluetoothCache<Q, R> extends IpcDataCache<Q, R> {
BluetoothCache(String api, IpcDataCache.QueryHandler query)1417         BluetoothCache(String api, IpcDataCache.QueryHandler query) {
1418             super(8, IpcDataCache.MODULE_BLUETOOTH, api, api, query);
1419         }
1420     }
1421 
1422     /**
1423      * Invalidate a bluetooth cache. This method is just a short-hand wrapper that enforces the
1424      * bluetooth module.
1425      */
invalidateCache(@onNull String api)1426     private static void invalidateCache(@NonNull String api) {
1427         IpcDataCache.invalidateCache(IpcDataCache.MODULE_BLUETOOTH, api);
1428     }
1429 
1430     private static final IpcDataCache.QueryHandler<Void, Integer> sBluetoothGetSystemStateQuery =
1431             new IpcDataCache.QueryHandler<>() {
1432                 @RequiresNoPermission
1433                 @Override
1434                 public @InternalAdapterState Integer apply(Void query) {
1435                     try {
1436                         IBluetoothManager service =
1437                                 IBluetoothManager.Stub.asInterface(
1438                                         BluetoothFrameworkInitializer.getBluetoothServiceManager()
1439                                                 .getBluetoothManagerServiceRegisterer()
1440                                                 .get());
1441                         return service.getState();
1442                     } catch (RemoteException e) {
1443                         throw e.rethrowFromSystemServer();
1444                     }
1445                 }
1446 
1447                 @RequiresNoPermission
1448                 @Override
1449                 public boolean shouldBypassCache(Void query) {
1450                     return false;
1451                 }
1452             };
1453 
1454     /** @hide */
1455     public static final String GET_SYSTEM_STATE_API = IBluetoothManager.GET_SYSTEM_STATE_API;
1456 
1457     private static final IpcDataCache<Void, Integer> sBluetoothGetSystemStateCache =
1458             new IpcDataCache<>(
1459                     1,
1460                     IBluetoothManager.IPC_CACHE_MODULE_SYSTEM,
1461                     GET_SYSTEM_STATE_API,
1462                     GET_SYSTEM_STATE_API,
1463                     sBluetoothGetSystemStateQuery);
1464 
1465     /**
1466      * Get the current state of the local Bluetooth adapter.
1467      *
1468      * <p>Possible return values are {@link #STATE_OFF}, {@link #STATE_TURNING_ON}, {@link
1469      * #STATE_ON}, {@link #STATE_TURNING_OFF}.
1470      *
1471      * @return current state of Bluetooth adapter
1472      */
1473     @RequiresLegacyBluetoothPermission
1474     @RequiresNoPermission
getState()1475     public @AdapterState int getState() {
1476         int state = sBluetoothGetSystemStateCache.query(null);
1477 
1478         // Consider all internal states as OFF
1479         if (state == BluetoothAdapter.STATE_BLE_ON
1480                 || state == BluetoothAdapter.STATE_BLE_TURNING_ON
1481                 || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
1482             if (VDBG) {
1483                 Log.d(TAG, "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF");
1484             }
1485             state = BluetoothAdapter.STATE_OFF;
1486         }
1487         if (VDBG) {
1488             Log.d(
1489                     TAG,
1490                     ""
1491                             + hashCode()
1492                             + ": getState(). Returning "
1493                             + BluetoothAdapter.nameForState(state));
1494         }
1495         return state;
1496     }
1497 
1498     /**
1499      * Get the current state of the local Bluetooth adapter
1500      *
1501      * <p>This returns current internal state of Adapter including LE ON/OFF
1502      *
1503      * <p>Possible return values are {@link #STATE_OFF}, {@link #STATE_BLE_TURNING_ON}, {@link
1504      * #STATE_BLE_ON}, {@link #STATE_TURNING_ON}, {@link #STATE_ON}, {@link #STATE_TURNING_OFF},
1505      * {@link #STATE_BLE_TURNING_OFF}.
1506      *
1507      * @return current state of Bluetooth adapter
1508      * @hide
1509      */
1510     @RequiresLegacyBluetoothPermission
1511     @RequiresNoPermission
1512     @UnsupportedAppUsage(
1513             publicAlternatives =
1514                     "Use {@link #getState()} instead to determine "
1515                             + "whether you can use BLE & BT classic.")
getLeState()1516     public @InternalAdapterState int getLeState() {
1517         int state = sBluetoothGetSystemStateCache.query(null);
1518 
1519         if (VDBG) {
1520             Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state));
1521         }
1522         return state;
1523     }
1524 
getLeAccess()1525     boolean getLeAccess() {
1526         if (getLeState() == STATE_ON) {
1527             return true;
1528         } else if (getLeState() == STATE_BLE_ON) {
1529             return true; // TODO: FILTER SYSTEM APPS HERE <--
1530         }
1531 
1532         return false;
1533     }
1534 
1535     /**
1536      * Turn on the local Bluetooth adapter&mdash;do not use without explicit user action to turn on
1537      * Bluetooth.
1538      *
1539      * <p>This powers on the underlying Bluetooth hardware, and starts all Bluetooth system
1540      * services.
1541      *
1542      * <p class="caution"><strong>Bluetooth should never be enabled without direct user
1543      * consent</strong>. If you want to turn on Bluetooth in order to create a wireless connection,
1544      * you should use the {@link #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that
1545      * requests user permission to turn on Bluetooth. The {@link #enable()} method is provided only
1546      * for applications that include a user interface for changing system settings, such as a "power
1547      * manager" app.
1548      *
1549      * <p>This is an asynchronous call: it will return immediately, and clients should listen for
1550      * {@link #ACTION_STATE_CHANGED} to be notified of subsequent adapter state changes. If this
1551      * call returns true, then the adapter state will immediately transition from {@link #STATE_OFF}
1552      * to {@link #STATE_TURNING_ON}, and some time later transition to either {@link #STATE_OFF} or
1553      * {@link #STATE_ON}. If this call returns false then there was an immediate problem that will
1554      * prevent the adapter from being turned on - such as Airplane mode, or the adapter is already
1555      * turned on.
1556      *
1557      * @return true to indicate adapter startup has begun, or false on immediate error
1558      * @deprecated Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, applications are
1559      *     not allowed to enable/disable Bluetooth. <b>Compatibility Note:</b> For applications
1560      *     targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or above, this API will always
1561      *     fail and return {@code false}. If apps are targeting an older SDK ({@link
1562      *     android.os.Build.VERSION_CODES#S} or below), they can continue to use this API.
1563      *     <p>Deprecation Exemptions:
1564      *     <ul>
1565      *       <li>Device Owner (DO), Profile Owner (PO) and system apps.
1566      *     </ul>
1567      */
1568     @Deprecated
1569     @RequiresLegacyBluetoothAdminPermission
1570     @RequiresBluetoothConnectPermission
1571     @RequiresPermission(BLUETOOTH_CONNECT)
enable()1572     public boolean enable() {
1573         if (isEnabled()) {
1574             if (DBG) {
1575                 Log.d(TAG, "enable(): BT already enabled!");
1576             }
1577             return true;
1578         }
1579         try {
1580             return mManagerService.enable(mAttributionSource);
1581         } catch (RemoteException e) {
1582             throw e.rethrowFromSystemServer();
1583         }
1584     }
1585 
1586     /**
1587      * Turn off the local Bluetooth adapter&mdash;do not use without explicit user action to turn
1588      * off Bluetooth.
1589      *
1590      * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth system services, and
1591      * powers down the underlying Bluetooth hardware.
1592      *
1593      * <p class="caution"><strong>Bluetooth should never be disabled without direct user
1594      * consent</strong>. The {@link #disable()} method is provided only for applications that
1595      * include a user interface for changing system settings, such as a "power manager" app.
1596      *
1597      * <p>This is an asynchronous call: it will return immediately, and clients should listen for
1598      * {@link #ACTION_STATE_CHANGED} to be notified of subsequent adapter state changes. If this
1599      * call returns true, then the adapter state will immediately transition from {@link #STATE_ON}
1600      * to {@link #STATE_TURNING_OFF}, and some time later transition to either {@link #STATE_OFF} or
1601      * {@link #STATE_ON}. If this call returns false then there was an immediate problem that will
1602      * prevent the adapter from being turned off - such as the adapter already being turned off.
1603      *
1604      * @return true to indicate adapter shutdown has begun, or false on immediate error
1605      * @deprecated Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, applications are
1606      *     not allowed to enable/disable Bluetooth. <b>Compatibility Note:</b> For applications
1607      *     targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or above, this API will always
1608      *     fail and return {@code false}. If apps are targeting an older SDK ({@link
1609      *     android.os.Build.VERSION_CODES#S} or below), they can continue to use this API.
1610      *     <p>Deprecation Exemptions:
1611      *     <ul>
1612      *       <li>Device Owner (DO), Profile Owner (PO) and system apps.
1613      *     </ul>
1614      */
1615     @Deprecated
1616     @RequiresLegacyBluetoothAdminPermission
1617     @RequiresBluetoothConnectPermission
1618     @RequiresPermission(BLUETOOTH_CONNECT)
1619     @SuppressLint("AndroidFrameworkRequiresPermission") // See disable(boolean) for reason
disable()1620     public boolean disable() {
1621         return disable(true);
1622     }
1623 
1624     /**
1625      * Turn off the local Bluetooth adapter and don't persist the setting.
1626      *
1627      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission only when
1628      * {@code persist} is {@code false}.
1629      *
1630      * <p>The {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission is always enforced.
1631      *
1632      * @param persist Indicate whether the off state should be persisted following the next reboot
1633      * @return true to indicate adapter shutdown has begun, or false on immediate error
1634      * @hide
1635      */
1636     @SystemApi
1637     @RequiresLegacyBluetoothAdminPermission
1638     @RequiresBluetoothConnectPermission
1639     @RequiresPermission(
1640             allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
1641             conditional = true)
disable(boolean persist)1642     public boolean disable(boolean persist) {
1643         try {
1644             return mManagerService.disable(mAttributionSource, persist);
1645         } catch (RemoteException e) {
1646             throw e.rethrowFromSystemServer();
1647         }
1648     }
1649 
1650     /**
1651      * Returns the hardware address of the local Bluetooth adapter.
1652      *
1653      * <p>For example, "00:11:22:AA:BB:CC".
1654      *
1655      * @return Bluetooth hardware address as string
1656      */
1657     @RequiresLegacyBluetoothPermission
1658     @RequiresBluetoothConnectPermission
1659     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS})
getAddress()1660     public String getAddress() {
1661         try {
1662             return mManagerService.getAddress(mAttributionSource);
1663         } catch (RemoteException e) {
1664             throw e.rethrowFromSystemServer();
1665         }
1666     }
1667 
1668     /**
1669      * Get the friendly Bluetooth name of the local Bluetooth adapter.
1670      *
1671      * <p>This name is visible to remote Bluetooth devices.
1672      *
1673      * @return the Bluetooth name, or null on error
1674      */
1675     @RequiresLegacyBluetoothPermission
1676     @RequiresBluetoothConnectPermission
1677     @RequiresPermission(BLUETOOTH_CONNECT)
getName()1678     public String getName() {
1679         try {
1680             return mManagerService.getName(mAttributionSource);
1681         } catch (RemoteException e) {
1682             throw e.rethrowFromSystemServer();
1683         }
1684     }
1685 
1686     /** @hide */
1687     @RequiresBluetoothAdvertisePermission
1688     @RequiresPermission(BLUETOOTH_ADVERTISE)
getNameLengthForAdvertise()1689     public int getNameLengthForAdvertise() {
1690         mServiceLock.readLock().lock();
1691         try {
1692             if (mService != null) {
1693                 return mService.getNameLengthForAdvertise(mAttributionSource);
1694             }
1695         } catch (RemoteException e) {
1696             logRemoteException(TAG, e);
1697         } finally {
1698             mServiceLock.readLock().unlock();
1699         }
1700         return -1;
1701     }
1702 
1703     /**
1704      * Factory reset bluetooth settings.
1705      *
1706      * @return true to indicate that the config file was successfully cleared
1707      * @hide
1708      */
1709     @SystemApi
1710     @RequiresBluetoothConnectPermission
1711     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
clearBluetooth()1712     public boolean clearBluetooth() {
1713         mServiceLock.readLock().lock();
1714         try {
1715             if (mService != null) {
1716                 if (mService.factoryReset(mAttributionSource)
1717                         && mManagerService.onFactoryReset(mAttributionSource)) {
1718                     return true;
1719                 }
1720             }
1721             Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later");
1722             BluetoothProperties.factory_reset(true);
1723         } catch (RemoteException e) {
1724             logRemoteException(TAG, e);
1725         } finally {
1726             mServiceLock.readLock().unlock();
1727         }
1728         return false;
1729     }
1730 
1731     /**
1732      * See {@link #clearBluetooth()}
1733      *
1734      * @return true to indicate that the config file was successfully cleared
1735      * @hide
1736      */
1737     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1738     @RequiresBluetoothConnectPermission
1739     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
factoryReset()1740     public boolean factoryReset() {
1741         return clearBluetooth();
1742     }
1743 
1744     /**
1745      * Get the UUIDs supported by the local Bluetooth adapter.
1746      *
1747      * @return the UUIDs supported by the local Bluetooth Adapter.
1748      * @hide
1749      */
1750     @UnsupportedAppUsage
1751     @RequiresLegacyBluetoothPermission
1752     @RequiresBluetoothConnectPermission
1753     @RequiresPermission(BLUETOOTH_CONNECT)
getUuids()1754     public @NonNull ParcelUuid[] getUuids() {
1755         List<ParcelUuid> parcels = getUuidsList();
1756         return parcels.toArray(new ParcelUuid[parcels.size()]);
1757     }
1758 
1759     /**
1760      * Get the UUIDs supported by the local Bluetooth adapter.
1761      *
1762      * @return a list of the UUIDs supported by the local Bluetooth Adapter.
1763      * @hide
1764      */
1765     @SystemApi
1766     @RequiresBluetoothConnectPermission
1767     @RequiresPermission(BLUETOOTH_CONNECT)
getUuidsList()1768     public @NonNull List<ParcelUuid> getUuidsList() {
1769         List<ParcelUuid> defaultValue = new ArrayList<>();
1770         if (getState() != STATE_ON) {
1771             return defaultValue;
1772         }
1773         mServiceLock.readLock().lock();
1774         try {
1775             if (mService != null) {
1776                 return mService.getUuids(mAttributionSource);
1777             }
1778         } catch (RemoteException e) {
1779             logRemoteException(TAG, e);
1780         } finally {
1781             mServiceLock.readLock().unlock();
1782         }
1783         return defaultValue;
1784     }
1785 
1786     /**
1787      * Set the friendly Bluetooth name of the local Bluetooth adapter.
1788      *
1789      * <p>This name is visible to remote Bluetooth devices.
1790      *
1791      * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8 encoding, although many
1792      * remote devices can only display the first 40 characters, and some may be limited to just 20.
1793      *
1794      * <p>If Bluetooth state is not {@link #STATE_ON}, this API will return false. After turning on
1795      * Bluetooth, wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} to get the updated
1796      * value.
1797      *
1798      * @param name a valid Bluetooth name
1799      * @return true if the name was set, false otherwise
1800      */
1801     @RequiresLegacyBluetoothAdminPermission
1802     @RequiresBluetoothConnectPermission
1803     @RequiresPermission(BLUETOOTH_CONNECT)
setName(String name)1804     public boolean setName(String name) {
1805         if (getState() != STATE_ON) {
1806             return false;
1807         }
1808         mServiceLock.readLock().lock();
1809         try {
1810             if (mService != null) {
1811                 return mService.setName(name, mAttributionSource);
1812             }
1813         } catch (RemoteException e) {
1814             logRemoteException(TAG, e);
1815         } finally {
1816             mServiceLock.readLock().unlock();
1817         }
1818         return false;
1819     }
1820 
1821     /**
1822      * Get the current Bluetooth scan mode of the local Bluetooth adapter.
1823      *
1824      * <p>The Bluetooth scan mode determines if the local adapter is connectable and/or discoverable
1825      * from remote Bluetooth devices.
1826      *
1827      * <p>Possible values are: {@link #SCAN_MODE_NONE}, {@link #SCAN_MODE_CONNECTABLE}, {@link
1828      * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
1829      *
1830      * <p>If Bluetooth state is not {@link #STATE_ON}, this API will return {@link #SCAN_MODE_NONE}.
1831      * After turning on Bluetooth, wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} to
1832      * get the updated value.
1833      *
1834      * @return scan mode
1835      */
1836     @RequiresLegacyBluetoothPermission
1837     @RequiresBluetoothScanPermission
1838     @RequiresPermission(BLUETOOTH_SCAN)
1839     @ScanMode
getScanMode()1840     public int getScanMode() {
1841         if (getState() != STATE_ON) {
1842             return SCAN_MODE_NONE;
1843         }
1844         mServiceLock.readLock().lock();
1845         try {
1846             if (mService != null) {
1847                 return mService.getScanMode(mAttributionSource);
1848             }
1849         } catch (RemoteException e) {
1850             logRemoteException(TAG, e);
1851         } finally {
1852             mServiceLock.readLock().unlock();
1853         }
1854         return SCAN_MODE_NONE;
1855     }
1856 
1857     /**
1858      * Set the local Bluetooth adapter connectability and discoverability.
1859      *
1860      * <p>If the scan mode is set to {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}, it will change to
1861      * {@link #SCAN_MODE_CONNECTABLE} after the discoverable timeout. The discoverable timeout can
1862      * be set with {@link #setDiscoverableTimeout} and checked with {@link #getDiscoverableTimeout}.
1863      * By default, the timeout is usually 120 seconds on phones which is enough for a remote device
1864      * to initiate and complete its discovery process.
1865      *
1866      * <p>Applications cannot set the scan mode. They should use {@link
1867      * #ACTION_REQUEST_DISCOVERABLE} instead.
1868      *
1869      * @param mode represents the desired state of the local device scan mode
1870      * @return status code indicating whether the scan mode was successfully set
1871      * @throws IllegalArgumentException if the mode is not a valid scan mode
1872      * @hide
1873      */
1874     @SystemApi
1875     @RequiresBluetoothScanPermission
1876     @RequiresPermission(allOf = {BLUETOOTH_SCAN, BLUETOOTH_PRIVILEGED})
setScanMode(@canMode int mode)1877     public @ScanModeStatusCode int setScanMode(@ScanMode int mode) {
1878         if (getState() != STATE_ON) {
1879             return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
1880         }
1881         if (mode != SCAN_MODE_NONE
1882                 && mode != SCAN_MODE_CONNECTABLE
1883                 && mode != SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
1884             throw new IllegalArgumentException("Invalid scan mode param value");
1885         }
1886         mServiceLock.readLock().lock();
1887         try {
1888             if (mService != null) {
1889                 return mService.setScanMode(mode, mAttributionSource);
1890             }
1891         } catch (RemoteException e) {
1892             logRemoteException(TAG, e);
1893         } finally {
1894             mServiceLock.readLock().unlock();
1895         }
1896         return BluetoothStatusCodes.ERROR_UNKNOWN;
1897     }
1898 
1899     /**
1900      * Get the timeout duration of the {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
1901      *
1902      * @return the duration of the discoverable timeout or null if an error has occurred
1903      */
1904     @RequiresBluetoothScanPermission
1905     @RequiresPermission(BLUETOOTH_SCAN)
getDiscoverableTimeout()1906     public @Nullable Duration getDiscoverableTimeout() {
1907         if (getState() != STATE_ON) {
1908             return null;
1909         }
1910         mServiceLock.readLock().lock();
1911         try {
1912             if (mService != null) {
1913                 long timeout = mService.getDiscoverableTimeout(mAttributionSource);
1914                 return (timeout == -1) ? null : Duration.ofSeconds(timeout);
1915             }
1916         } catch (RemoteException e) {
1917             logRemoteException(TAG, e);
1918         } finally {
1919             mServiceLock.readLock().unlock();
1920         }
1921         return null;
1922     }
1923 
1924     /**
1925      * Set the total time the Bluetooth local adapter will stay discoverable when {@link
1926      * #setScanMode} is called with {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE} mode. After this
1927      * timeout, the scan mode will fallback to {@link #SCAN_MODE_CONNECTABLE}.
1928      *
1929      * <p>If <code>timeout</code> is set to 0, no timeout will occur and the scan mode will be
1930      * persisted until a subsequent call to {@link #setScanMode}.
1931      *
1932      * @param timeout represents the total duration the local Bluetooth adapter will remain
1933      *     discoverable, or no timeout if set to 0
1934      * @return whether the timeout was successfully set
1935      * @throws IllegalArgumentException if <code>timeout</code> duration in seconds is more than
1936      *     {@link Integer#MAX_VALUE}
1937      * @hide
1938      */
1939     @SystemApi
1940     @RequiresBluetoothScanPermission
1941     @RequiresPermission(allOf = {BLUETOOTH_SCAN, BLUETOOTH_PRIVILEGED})
setDiscoverableTimeout(@onNull Duration timeout)1942     public @ScanModeStatusCode int setDiscoverableTimeout(@NonNull Duration timeout) {
1943         if (getState() != STATE_ON) {
1944             return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
1945         }
1946         if (timeout.toSeconds() > Integer.MAX_VALUE) {
1947             throw new IllegalArgumentException(
1948                     "Timeout in seconds must be less or equal to " + Integer.MAX_VALUE);
1949         }
1950         mServiceLock.readLock().lock();
1951         try {
1952             if (mService != null) {
1953                 return mService.setDiscoverableTimeout(timeout.toSeconds(), mAttributionSource);
1954             }
1955         } catch (RemoteException e) {
1956             logRemoteException(TAG, e);
1957         } finally {
1958             mServiceLock.readLock().unlock();
1959         }
1960         return BluetoothStatusCodes.ERROR_UNKNOWN;
1961     }
1962 
1963     /**
1964      * Get the end time of the latest remote device discovery process.
1965      *
1966      * @return the latest time that the bluetooth adapter was/will be in discovery mode, in
1967      *     milliseconds since the epoch. This time can be in the future if {@link #startDiscovery()}
1968      *     has been called recently.
1969      * @hide
1970      */
1971     @SystemApi
1972     @RequiresBluetoothConnectPermission
1973     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getDiscoveryEndMillis()1974     public long getDiscoveryEndMillis() {
1975         mServiceLock.readLock().lock();
1976         try {
1977             if (mService != null) {
1978                 return mService.getDiscoveryEndMillis(mAttributionSource);
1979             }
1980         } catch (RemoteException e) {
1981             logRemoteException(TAG, e);
1982         } finally {
1983             mServiceLock.readLock().unlock();
1984         }
1985         return -1;
1986     }
1987 
1988     /**
1989      * Start the remote device discovery process.
1990      *
1991      * <p>The discovery process usually involves an inquiry scan of about 12 seconds, followed by a
1992      * page scan of each new device to retrieve its Bluetooth name.
1993      *
1994      * <p>This is an asynchronous call, it will return immediately. Register for {@link
1995      * #ACTION_DISCOVERY_STARTED} and {@link #ACTION_DISCOVERY_FINISHED} intents to determine
1996      * exactly when the discovery starts and completes. Register for {@link
1997      * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices are found.
1998      *
1999      * <p>Device discovery is a heavyweight procedure. New connections to remote Bluetooth devices
2000      * should not be attempted while discovery is in progress, and existing connections will
2001      * experience limited bandwidth and high latency. Use {@link #cancelDiscovery()} to cancel an
2002      * ongoing discovery. Discovery is not managed by the Activity, but is run as a system service,
2003      * so an application should always call {@link BluetoothAdapter#cancelDiscovery()} even if it
2004      * did not directly request a discovery, just to be sure.
2005      *
2006      * <p>Device discovery will only find remote devices that are currently <i>discoverable</i>
2007      * (inquiry scan enabled). Many Bluetooth devices are not discoverable by default, and need to
2008      * be entered into a special mode.
2009      *
2010      * <p>If Bluetooth state is not {@link #STATE_ON}, this API will return false. After turning on
2011      * Bluetooth, wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} to get the updated
2012      * value.
2013      *
2014      * <p>If a device is currently bonding, this request will be queued and executed once that
2015      * device has finished bonding. If a request is already queued, this request will be ignored.
2016      *
2017      * @return true on success, false on error
2018      */
2019     @RequiresLegacyBluetoothAdminPermission
2020     @RequiresBluetoothScanPermission
2021     @RequiresBluetoothLocationPermission
2022     @RequiresPermission(BLUETOOTH_SCAN)
startDiscovery()2023     public boolean startDiscovery() {
2024         if (getState() != STATE_ON) {
2025             return false;
2026         }
2027         mServiceLock.readLock().lock();
2028         try {
2029             if (mService != null) {
2030                 return mService.startDiscovery(mAttributionSource);
2031             }
2032         } catch (RemoteException e) {
2033             logRemoteException(TAG, e);
2034         } finally {
2035             mServiceLock.readLock().unlock();
2036         }
2037         return false;
2038     }
2039 
2040     /**
2041      * Cancel the current device discovery process.
2042      *
2043      * <p>Because discovery is a heavyweight procedure for the Bluetooth adapter, this method should
2044      * always be called before attempting to connect to a remote device with {@link
2045      * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by the Activity, but
2046      * is run as a system service, so an application should always call cancel discovery even if it
2047      * did not directly request a discovery, just to be sure.
2048      *
2049      * <p>If Bluetooth state is not {@link #STATE_ON}, this API will return false. After turning on
2050      * Bluetooth, wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} to get the updated
2051      * value.
2052      *
2053      * @return true on success, false on error
2054      */
2055     @RequiresLegacyBluetoothAdminPermission
2056     @RequiresBluetoothScanPermission
2057     @RequiresPermission(BLUETOOTH_SCAN)
cancelDiscovery()2058     public boolean cancelDiscovery() {
2059         if (getState() != STATE_ON) {
2060             return false;
2061         }
2062         mServiceLock.readLock().lock();
2063         try {
2064             if (mService != null) {
2065                 return mService.cancelDiscovery(mAttributionSource);
2066             }
2067         } catch (RemoteException e) {
2068             logRemoteException(TAG, e);
2069         } finally {
2070             mServiceLock.readLock().unlock();
2071         }
2072         return false;
2073     }
2074 
2075     /**
2076      * Return true if the local Bluetooth adapter is currently in the device discovery process.
2077      *
2078      * <p>Device discovery is a heavyweight procedure. New connections to remote Bluetooth devices
2079      * should not be attempted while discovery is in progress, and existing connections will
2080      * experience limited bandwidth and high latency. Use {@link #cancelDiscovery()} to cancel an
2081      * ongoing discovery.
2082      *
2083      * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED} or {@link
2084      * #ACTION_DISCOVERY_FINISHED} to be notified when discovery starts or completes.
2085      *
2086      * <p>If Bluetooth state is not {@link #STATE_ON}, this API will return false. After turning on
2087      * Bluetooth, wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} to get the updated
2088      * value.
2089      *
2090      * @return true if discovering
2091      */
2092     @RequiresLegacyBluetoothPermission
2093     @RequiresBluetoothScanPermission
2094     @RequiresPermission(BLUETOOTH_SCAN)
isDiscovering()2095     public boolean isDiscovering() {
2096         if (getState() != STATE_ON) {
2097             return false;
2098         }
2099         mServiceLock.readLock().lock();
2100         try {
2101             if (mService != null) {
2102                 return mService.isDiscovering(mAttributionSource);
2103             }
2104         } catch (RemoteException e) {
2105             logRemoteException(TAG, e);
2106         } finally {
2107             mServiceLock.readLock().unlock();
2108         }
2109         return false;
2110     }
2111 
2112     /**
2113      * Removes the active device for the grouping of @ActiveDeviceUse specified
2114      *
2115      * @param profiles represents the purpose for which we are setting this as the active device.
2116      *     Possible values are: {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO}, {@link
2117      *     BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL}, {@link BluetoothAdapter#ACTIVE_DEVICE_ALL}
2118      * @return false on immediate error, true otherwise
2119      * @throws IllegalArgumentException if device is null or profiles is not one of {@link
2120      *     ActiveDeviceUse}
2121      * @hide
2122      */
2123     @SystemApi
2124     @RequiresBluetoothConnectPermission
2125     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED, MODIFY_PHONE_STATE})
removeActiveDevice(@ctiveDeviceUse int profiles)2126     public boolean removeActiveDevice(@ActiveDeviceUse int profiles) {
2127         if (profiles != ACTIVE_DEVICE_AUDIO
2128                 && profiles != ACTIVE_DEVICE_PHONE_CALL
2129                 && profiles != ACTIVE_DEVICE_ALL) {
2130             Log.e(TAG, "Invalid profiles param value in removeActiveDevice");
2131             throw new IllegalArgumentException(
2132                     "Profiles must be one of "
2133                             + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, "
2134                             + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or "
2135                             + "BluetoothAdapter.ACTIVE_DEVICE_ALL");
2136         }
2137         mServiceLock.readLock().lock();
2138         try {
2139             if (mService != null) {
2140                 if (DBG) Log.d(TAG, "removeActiveDevice, profiles: " + profiles);
2141                 return mService.removeActiveDevice(profiles, mAttributionSource);
2142             }
2143         } catch (RemoteException e) {
2144             logRemoteException(TAG, e);
2145         } finally {
2146             mServiceLock.readLock().unlock();
2147         }
2148 
2149         return false;
2150     }
2151 
2152     /**
2153      * Sets device as the active devices for the use cases passed into the function. Note that in
2154      * order to make a device active for LE Audio, it must be the active device for audio and phone
2155      * calls.
2156      *
2157      * @param device is the remote bluetooth device
2158      * @param profiles represents the purpose for which we are setting this as the active device.
2159      *     Possible values are: {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO}, {@link
2160      *     BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL}, {@link BluetoothAdapter#ACTIVE_DEVICE_ALL}
2161      * @return false on immediate error, true otherwise
2162      * @throws IllegalArgumentException if device is null or profiles is not one of {@link
2163      *     ActiveDeviceUse}
2164      * @hide
2165      */
2166     @SystemApi
2167     @RequiresBluetoothConnectPermission
2168     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED, MODIFY_PHONE_STATE})
setActiveDevice(@onNull BluetoothDevice device, @ActiveDeviceUse int profiles)2169     public boolean setActiveDevice(@NonNull BluetoothDevice device, @ActiveDeviceUse int profiles) {
2170         if (device == null) {
2171             Log.e(TAG, "setActiveDevice: Null device passed as parameter");
2172             throw new IllegalArgumentException("device cannot be null");
2173         }
2174         if (profiles != ACTIVE_DEVICE_AUDIO
2175                 && profiles != ACTIVE_DEVICE_PHONE_CALL
2176                 && profiles != ACTIVE_DEVICE_ALL) {
2177             Log.e(TAG, "Invalid profiles param value in setActiveDevice");
2178             throw new IllegalArgumentException(
2179                     "Profiles must be one of "
2180                             + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, "
2181                             + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or "
2182                             + "BluetoothAdapter.ACTIVE_DEVICE_ALL");
2183         }
2184         mServiceLock.readLock().lock();
2185         try {
2186             if (mService != null) {
2187                 if (DBG) {
2188                     Log.d(TAG, "setActiveDevice, device: " + device + ", profiles: " + profiles);
2189                 }
2190                 return mService.setActiveDevice(device, profiles, mAttributionSource);
2191             }
2192         } catch (RemoteException e) {
2193             logRemoteException(TAG, e);
2194         } finally {
2195             mServiceLock.readLock().unlock();
2196         }
2197 
2198         return false;
2199     }
2200 
2201     /**
2202      * Get the active devices for the BluetoothProfile specified
2203      *
2204      * @param profile is the profile from which we want the active devices. Possible values are:
2205      *     {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}, {@link
2206      *     BluetoothProfile#HEARING_AID} {@link BluetoothProfile#LE_AUDIO}
2207      * @return A list of active bluetooth devices
2208      * @throws IllegalArgumentException If profile is not one of {@link ActiveDeviceProfile}
2209      * @hide
2210      */
2211     @SystemApi
2212     @RequiresBluetoothConnectPermission
2213     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getActiveDevices(@ctiveDeviceProfile int profile)2214     public @NonNull List<BluetoothDevice> getActiveDevices(@ActiveDeviceProfile int profile) {
2215         if (profile != BluetoothProfile.HEADSET
2216                 && profile != BluetoothProfile.A2DP
2217                 && profile != BluetoothProfile.HEARING_AID
2218                 && profile != BluetoothProfile.LE_AUDIO) {
2219             Log.e(TAG, "Invalid profile param value in getActiveDevices");
2220             throw new IllegalArgumentException(
2221                     "Profiles must be one of "
2222                             + "BluetoothProfile.A2DP, "
2223                             + "BluetoothProfile.HEADSET, "
2224                             + "BluetoothProfile.HEARING_AID, or "
2225                             + "BluetoothProfile.LE_AUDIO");
2226         }
2227         mServiceLock.readLock().lock();
2228         try {
2229             if (mService != null) {
2230                 if (DBG) {
2231                     Log.d(TAG, "getActiveDevices(" + getProfileName(profile) + ")");
2232                 }
2233                 return mService.getActiveDevices(profile, mAttributionSource);
2234             }
2235         } catch (RemoteException e) {
2236             logRemoteException(TAG, e);
2237         } finally {
2238             mServiceLock.readLock().unlock();
2239         }
2240 
2241         return Collections.emptyList();
2242     }
2243 
2244     /**
2245      * Return true if the multi advertisement is supported by the chipset
2246      *
2247      * @return true if Multiple Advertisement feature is supported
2248      */
2249     @RequiresLegacyBluetoothPermission
2250     @RequiresNoPermission
isMultipleAdvertisementSupported()2251     public boolean isMultipleAdvertisementSupported() {
2252         if (getState() != STATE_ON) {
2253             return false;
2254         }
2255         mServiceLock.readLock().lock();
2256         try {
2257             if (mService != null) {
2258                 return mService.isMultiAdvertisementSupported();
2259             }
2260         } catch (RemoteException e) {
2261             logRemoteException(TAG, e);
2262         } finally {
2263             mServiceLock.readLock().unlock();
2264         }
2265         return false;
2266     }
2267 
2268     /**
2269      * Returns {@code true} if BLE scan is always available, {@code false} otherwise.
2270      *
2271      * <p>If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan}
2272      * and fetch scan results even when Bluetooth is turned off.
2273      *
2274      * <p>To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}.
2275      *
2276      * @hide
2277      */
2278     @SystemApi
2279     @RequiresNoPermission
isBleScanAlwaysAvailable()2280     public boolean isBleScanAlwaysAvailable() {
2281         try {
2282             return mManagerService.isBleScanAvailable();
2283         } catch (RemoteException e) {
2284             throw e.rethrowFromSystemServer();
2285         }
2286     }
2287 
2288     private static final IpcDataCache.QueryHandler<IBluetooth, Boolean> sBluetoothFilteringQuery =
2289             new IpcDataCache.QueryHandler<>() {
2290                 @RequiresLegacyBluetoothPermission
2291                 @RequiresNoPermission
2292                 @Override
2293                 public Boolean apply(IBluetooth serviceQuery) {
2294                     try {
2295                         return serviceQuery.isOffloadedFilteringSupported();
2296                     } catch (RemoteException e) {
2297                         throw e.rethrowAsRuntimeException();
2298                     }
2299                 }
2300                 @RequiresNoPermission
2301                 @Override
2302                 public boolean shouldBypassCache(IBluetooth serviceQuery) {
2303                     return false;
2304                 }
2305             };
2306 
2307     private static final String FILTERING_API = "BluetoothAdapter_isOffloadedFilteringSupported";
2308 
2309     private static final IpcDataCache<IBluetooth, Boolean> sBluetoothFilteringCache =
2310             new BluetoothCache<>(FILTERING_API, sBluetoothFilteringQuery);
2311 
2312     /** @hide */
2313     @RequiresNoPermission
disableIsOffloadedFilteringSupportedCache()2314     public void disableIsOffloadedFilteringSupportedCache() {
2315         sBluetoothFilteringCache.disableForCurrentProcess();
2316     }
2317 
2318     /** @hide */
invalidateIsOffloadedFilteringSupportedCache()2319     public static void invalidateIsOffloadedFilteringSupportedCache() {
2320         invalidateCache(FILTERING_API);
2321     }
2322 
2323     /**
2324      * Return true if offloaded filters are supported
2325      *
2326      * @return true if chipset supports on-chip filtering
2327      */
2328     @RequiresLegacyBluetoothPermission
2329     @RequiresNoPermission
isOffloadedFilteringSupported()2330     public boolean isOffloadedFilteringSupported() {
2331         if (!getLeAccess()) {
2332             return false;
2333         }
2334         mServiceLock.readLock().lock();
2335         try {
2336             if (mService != null) return sBluetoothFilteringCache.query(mService);
2337         } catch (RuntimeException e) {
2338             if (!(e.getCause() instanceof RemoteException)) {
2339                 throw e;
2340             }
2341             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2342         } finally {
2343             mServiceLock.readLock().unlock();
2344         }
2345         return false;
2346     }
2347 
2348     /**
2349      * Return true if offloaded scan batching is supported
2350      *
2351      * @return true if chipset supports on-chip scan batching
2352      */
2353     @RequiresLegacyBluetoothPermission
2354     @RequiresNoPermission
isOffloadedScanBatchingSupported()2355     public boolean isOffloadedScanBatchingSupported() {
2356         if (!getLeAccess()) {
2357             return false;
2358         }
2359         mServiceLock.readLock().lock();
2360         try {
2361             if (mService != null) {
2362                 return mService.isOffloadedScanBatchingSupported();
2363             }
2364         } catch (RemoteException e) {
2365             logRemoteException(TAG, e);
2366         } finally {
2367             mServiceLock.readLock().unlock();
2368         }
2369         return false;
2370     }
2371 
2372     /**
2373      * Return true if LE 2M PHY feature is supported.
2374      *
2375      * @return true if chipset supports LE 2M PHY feature
2376      */
2377     @RequiresLegacyBluetoothPermission
2378     @RequiresNoPermission
isLe2MPhySupported()2379     public boolean isLe2MPhySupported() {
2380         if (!getLeAccess()) {
2381             return false;
2382         }
2383         mServiceLock.readLock().lock();
2384         try {
2385             if (mService != null) {
2386                 return mService.isLe2MPhySupported();
2387             }
2388         } catch (RemoteException e) {
2389             logRemoteException(TAG, e);
2390         } finally {
2391             mServiceLock.readLock().unlock();
2392         }
2393         return false;
2394     }
2395 
2396     /**
2397      * Return true if LE Coded PHY feature is supported.
2398      *
2399      * @return true if chipset supports LE Coded PHY feature
2400      */
2401     @RequiresLegacyBluetoothPermission
2402     @RequiresNoPermission
isLeCodedPhySupported()2403     public boolean isLeCodedPhySupported() {
2404         if (!getLeAccess()) {
2405             return false;
2406         }
2407         mServiceLock.readLock().lock();
2408         try {
2409             if (mService != null) {
2410                 return mService.isLeCodedPhySupported();
2411             }
2412         } catch (RemoteException e) {
2413             logRemoteException(TAG, e);
2414         } finally {
2415             mServiceLock.readLock().unlock();
2416         }
2417         return false;
2418     }
2419 
2420     /**
2421      * Return true if LE Extended Advertising feature is supported.
2422      *
2423      * @return true if chipset supports LE Extended Advertising feature
2424      */
2425     @RequiresLegacyBluetoothPermission
2426     @RequiresNoPermission
isLeExtendedAdvertisingSupported()2427     public boolean isLeExtendedAdvertisingSupported() {
2428         if (!getLeAccess()) {
2429             return false;
2430         }
2431         mServiceLock.readLock().lock();
2432         try {
2433             if (mService != null) {
2434                 return mService.isLeExtendedAdvertisingSupported();
2435             }
2436         } catch (RemoteException e) {
2437             logRemoteException(TAG, e);
2438         } finally {
2439             mServiceLock.readLock().unlock();
2440         }
2441         return false;
2442     }
2443 
2444     /**
2445      * Return true if LE Periodic Advertising feature is supported.
2446      *
2447      * @return true if chipset supports LE Periodic Advertising feature
2448      */
2449     @RequiresLegacyBluetoothPermission
2450     @RequiresNoPermission
isLePeriodicAdvertisingSupported()2451     public boolean isLePeriodicAdvertisingSupported() {
2452         if (!getLeAccess()) {
2453             return false;
2454         }
2455         mServiceLock.readLock().lock();
2456         try {
2457             if (mService != null) {
2458                 return mService.isLePeriodicAdvertisingSupported();
2459             }
2460         } catch (RemoteException e) {
2461             logRemoteException(TAG, e);
2462         } finally {
2463             mServiceLock.readLock().unlock();
2464         }
2465         return false;
2466     }
2467 
2468     /** @hide */
2469     @Retention(RetentionPolicy.SOURCE)
2470     @IntDef(
2471             value = {
2472                 BluetoothStatusCodes.FEATURE_SUPPORTED,
2473                 BluetoothStatusCodes.ERROR_UNKNOWN,
2474                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
2475                 BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
2476             })
2477     public @interface LeFeatureReturnValues {}
2478 
2479     /**
2480      * Returns {@link BluetoothStatusCodes#FEATURE_SUPPORTED} if the LE audio feature is supported,
2481      * {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} if the feature is not supported, or an
2482      * error code.
2483      *
2484      * @return whether the LE audio is supported
2485      */
2486     @RequiresNoPermission
isLeAudioSupported()2487     public @LeFeatureReturnValues int isLeAudioSupported() {
2488         if (!getLeAccess()) {
2489             return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
2490         }
2491         mServiceLock.readLock().lock();
2492         try {
2493             if (mService != null) {
2494                 return mService.isLeAudioSupported();
2495             }
2496         } catch (RemoteException e) {
2497             logRemoteException(TAG, e);
2498         } finally {
2499             mServiceLock.readLock().unlock();
2500         }
2501         return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
2502     }
2503 
2504     /**
2505      * Returns {@link BluetoothStatusCodes#FEATURE_SUPPORTED} if the LE audio broadcast source
2506      * feature is supported, {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} if the feature is
2507      * not supported, or an error code.
2508      *
2509      * @return whether the LE audio broadcast source is supported
2510      */
2511     @RequiresNoPermission
isLeAudioBroadcastSourceSupported()2512     public @LeFeatureReturnValues int isLeAudioBroadcastSourceSupported() {
2513         if (!getLeAccess()) {
2514             return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
2515         }
2516         mServiceLock.readLock().lock();
2517         try {
2518             if (mService != null) {
2519                 return mService.isLeAudioBroadcastSourceSupported();
2520             }
2521         } catch (RemoteException e) {
2522             logRemoteException(TAG, e);
2523         } finally {
2524             mServiceLock.readLock().unlock();
2525         }
2526         return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
2527     }
2528 
2529     /**
2530      * Returns {@link BluetoothStatusCodes#FEATURE_SUPPORTED} if the LE audio broadcast assistant
2531      * feature is supported, {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} if the feature is
2532      * not supported, or an error code.
2533      *
2534      * @return whether the LE audio broadcast assistant is supported
2535      */
2536     @RequiresNoPermission
isLeAudioBroadcastAssistantSupported()2537     public @LeFeatureReturnValues int isLeAudioBroadcastAssistantSupported() {
2538         if (!getLeAccess()) {
2539             return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
2540         }
2541         mServiceLock.readLock().lock();
2542         try {
2543             if (mService != null) {
2544                 return mService.isLeAudioBroadcastAssistantSupported();
2545             }
2546         } catch (RemoteException e) {
2547             logRemoteException(TAG, e);
2548         } finally {
2549             mServiceLock.readLock().unlock();
2550         }
2551         return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
2552     }
2553 
2554     /**
2555      * Returns whether the distance measurement feature is supported.
2556      *
2557      * @return whether the Bluetooth distance measurement is supported
2558      * @hide
2559      */
2560     @SystemApi
2561     @RequiresBluetoothConnectPermission
2562     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
isDistanceMeasurementSupported()2563     public @LeFeatureReturnValues int isDistanceMeasurementSupported() {
2564         if (!getLeAccess()) {
2565             return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
2566         }
2567         mServiceLock.readLock().lock();
2568         try {
2569             if (mService != null) {
2570                 return mService.isDistanceMeasurementSupported(mAttributionSource);
2571             }
2572         } catch (RemoteException e) {
2573             logRemoteException(TAG, e);
2574         } finally {
2575             mServiceLock.readLock().unlock();
2576         }
2577         return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
2578     }
2579 
2580     /**
2581      * Return the maximum LE advertising data length in bytes, if LE Extended Advertising feature is
2582      * supported, 0 otherwise.
2583      *
2584      * @return the maximum LE advertising data length.
2585      */
2586     @RequiresLegacyBluetoothPermission
2587     @RequiresNoPermission
getLeMaximumAdvertisingDataLength()2588     public int getLeMaximumAdvertisingDataLength() {
2589         if (!getLeAccess()) {
2590             return 0;
2591         }
2592         mServiceLock.readLock().lock();
2593         try {
2594             if (mService != null) {
2595                 return mService.getLeMaximumAdvertisingDataLength();
2596             }
2597         } catch (RemoteException e) {
2598             logRemoteException(TAG, e);
2599         } finally {
2600             mServiceLock.readLock().unlock();
2601         }
2602         return 0;
2603     }
2604 
2605     /**
2606      * Return true if Hearing Aid Profile is supported.
2607      *
2608      * @return true if phone supports Hearing Aid Profile
2609      */
2610     @RequiresNoPermission
isHearingAidProfileSupported()2611     private boolean isHearingAidProfileSupported() {
2612         try {
2613             return mManagerService.isHearingAidProfileSupported();
2614         } catch (RemoteException e) {
2615             throw e.rethrowFromSystemServer();
2616         }
2617     }
2618 
2619     /**
2620      * Get the maximum number of connected devices per audio profile for this device.
2621      *
2622      * @return the number of allowed simultaneous connected devices for each audio profile for this
2623      *     device, or -1 if the Bluetooth service can't be reached
2624      */
2625     @RequiresLegacyBluetoothPermission
2626     @RequiresBluetoothConnectPermission
2627     @RequiresPermission(BLUETOOTH_CONNECT)
getMaxConnectedAudioDevices()2628     public int getMaxConnectedAudioDevices() {
2629         mServiceLock.readLock().lock();
2630         try {
2631             if (mService != null) {
2632                 return mService.getMaxConnectedAudioDevices(mAttributionSource);
2633             }
2634         } catch (RemoteException e) {
2635             logRemoteException(TAG, e);
2636         } finally {
2637             mServiceLock.readLock().unlock();
2638         }
2639         return -1;
2640     }
2641 
2642     /**
2643      * Return true if hardware has entries available for matching beacons
2644      *
2645      * @return true if there are hw entries available for matching beacons
2646      * @hide
2647      */
2648     @RequiresBluetoothScanPermission
2649     @RequiresPermission(BLUETOOTH_SCAN)
isHardwareTrackingFiltersAvailable()2650     public boolean isHardwareTrackingFiltersAvailable() {
2651         if (!getLeAccess()) {
2652             return false;
2653         }
2654         try {
2655             IBluetoothScan scan = getBluetoothScan();
2656             if (scan == null) {
2657                 // BLE is not supported
2658                 return false;
2659             }
2660             return scan.numHwTrackFiltersAvailable(mAttributionSource) != 0;
2661         } catch (RemoteException e) {
2662             logRemoteException(TAG, e);
2663         }
2664         return false;
2665     }
2666 
2667     /**
2668      * Request the record of {@link BluetoothActivityEnergyInfo} object that has the activity and
2669      * energy info. This can be used to ascertain what the controller has been up to, since the last
2670      * sample.
2671      *
2672      * <p>The callback will be called only once, when the record is available.
2673      *
2674      * @param executor the executor that the callback will be invoked on
2675      * @param callback the callback that will be called with either the {@link
2676      *     BluetoothActivityEnergyInfo} object, or the error code if an error has occurred
2677      * @hide
2678      */
2679     @SystemApi
2680     @RequiresBluetoothConnectPermission
2681     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
requestControllerActivityEnergyInfo( @onNull @allbackExecutor Executor executor, @NonNull OnBluetoothActivityEnergyInfoCallback callback)2682     public void requestControllerActivityEnergyInfo(
2683             @NonNull @CallbackExecutor Executor executor,
2684             @NonNull OnBluetoothActivityEnergyInfoCallback callback) {
2685         requireNonNull(executor);
2686         requireNonNull(callback);
2687         OnBluetoothActivityEnergyInfoProxy proxy =
2688                 new OnBluetoothActivityEnergyInfoProxy(executor, callback);
2689         mServiceLock.readLock().lock();
2690         try {
2691             if (mService != null) {
2692                 mService.requestActivityInfo(proxy, mAttributionSource);
2693             } else {
2694                 proxy.onError(BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND);
2695             }
2696         } catch (RemoteException e) {
2697             logRemoteException(TAG, e);
2698             proxy.onError(BluetoothStatusCodes.ERROR_UNKNOWN);
2699         } finally {
2700             mServiceLock.readLock().unlock();
2701         }
2702     }
2703 
2704     /**
2705      * Fetches a list of the most recently connected bluetooth devices ordered by how recently they
2706      * were connected with most recently first and least recently last
2707      *
2708      * @return {@link List} of bonded {@link BluetoothDevice} ordered by how recently they were
2709      *     connected
2710      * @hide
2711      */
2712     @SystemApi
2713     @RequiresLegacyBluetoothAdminPermission
2714     @RequiresBluetoothConnectPermission
2715     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getMostRecentlyConnectedDevices()2716     public @NonNull List<BluetoothDevice> getMostRecentlyConnectedDevices() {
2717         if (getState() != STATE_ON) {
2718             return Collections.emptyList();
2719         }
2720         mServiceLock.readLock().lock();
2721         try {
2722             if (mService != null) {
2723                 return Attributable.setAttributionSource(
2724                         mService.getMostRecentlyConnectedDevices(mAttributionSource),
2725                         mAttributionSource);
2726             }
2727         } catch (RemoteException e) {
2728             logRemoteException(TAG, e);
2729         } finally {
2730             mServiceLock.readLock().unlock();
2731         }
2732         return Collections.emptyList();
2733     }
2734 
2735     /**
2736      * Return the set of {@link BluetoothDevice} objects that are bonded (paired) to the local
2737      * adapter.
2738      *
2739      * <p>If Bluetooth state is not {@link #STATE_ON}, this API will return an empty set. After
2740      * turning on Bluetooth, wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON} to get
2741      * the updated value.
2742      *
2743      * @return unmodifiable set of {@link BluetoothDevice}, or null on error
2744      */
2745     @RequiresLegacyBluetoothPermission
2746     @RequiresBluetoothConnectPermission
2747     @RequiresPermission(BLUETOOTH_CONNECT)
getBondedDevices()2748     public Set<BluetoothDevice> getBondedDevices() {
2749         if (getState() != STATE_ON) {
2750             return toDeviceSet(Arrays.asList());
2751         }
2752         mServiceLock.readLock().lock();
2753         try {
2754             if (mService != null) {
2755                 return toDeviceSet(
2756                         Attributable.setAttributionSource(
2757                                 mService.getBondedDevices(mAttributionSource), mAttributionSource));
2758             }
2759             return toDeviceSet(Arrays.asList());
2760         } catch (RemoteException e) {
2761             logRemoteException(TAG, e);
2762         } finally {
2763             mServiceLock.readLock().unlock();
2764         }
2765         return null;
2766     }
2767 
2768     /**
2769      * Gets the currently supported profiles by the adapter.
2770      *
2771      * <p>This can be used to check whether a profile is supported before attempting to connect to
2772      * its respective proxy.
2773      *
2774      * @return a list of integers indicating the ids of supported profiles as defined in {@link
2775      *     BluetoothProfile}.
2776      * @hide
2777      */
2778     @SystemApi
2779     @RequiresBluetoothConnectPermission
2780     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getSupportedProfiles()2781     public @NonNull List<Integer> getSupportedProfiles() {
2782         final ArrayList<Integer> supportedProfiles = new ArrayList<Integer>();
2783 
2784         mServiceLock.readLock().lock();
2785         try {
2786             if (mService != null) {
2787                 final long supportedProfilesBitMask =
2788                         mService.getSupportedProfiles(mAttributionSource);
2789 
2790                 for (int i = 0; i <= BluetoothProfile.MAX_PROFILE_ID; i++) {
2791                     if ((supportedProfilesBitMask & (1 << i)) != 0) {
2792                         supportedProfiles.add(i);
2793                     }
2794                 }
2795             } else {
2796                 // Bluetooth is disabled. Just fill in known supported Profiles
2797                 if (isHearingAidProfileSupported()) {
2798                     supportedProfiles.add(BluetoothProfile.HEARING_AID);
2799                 }
2800             }
2801         } catch (RemoteException e) {
2802             logRemoteException(TAG, e);
2803         } finally {
2804             mServiceLock.readLock().unlock();
2805         }
2806         return supportedProfiles;
2807     }
2808 
2809     private static final IpcDataCache.QueryHandler<IBluetooth, Integer>
2810             sBluetoothGetAdapterConnectionStateQuery =
2811                     new IpcDataCache.QueryHandler<>() {
2812                         @RequiresLegacyBluetoothPermission
2813                         @RequiresNoPermission
2814                         @Override
2815                         public Integer apply(IBluetooth serviceQuery) {
2816                             try {
2817                                 return serviceQuery.getAdapterConnectionState();
2818                             } catch (RemoteException e) {
2819                                 throw e.rethrowAsRuntimeException();
2820                             }
2821                         }
2822                         @RequiresNoPermission
2823                         @Override
2824                         public boolean shouldBypassCache(IBluetooth serviceQuery) {
2825                             return false;
2826                         }
2827                     };
2828 
2829     private static final String GET_CONNECTION_API = "BluetoothAdapter_getConnectionState";
2830 
2831     private static final IpcDataCache<IBluetooth, Integer>
2832             sBluetoothGetAdapterConnectionStateCache =
2833                     new BluetoothCache<>(
2834                             GET_CONNECTION_API, sBluetoothGetAdapterConnectionStateQuery);
2835 
2836     /** @hide */
2837     @RequiresNoPermission
disableGetAdapterConnectionStateCache()2838     public void disableGetAdapterConnectionStateCache() {
2839         sBluetoothGetAdapterConnectionStateCache.disableForCurrentProcess();
2840     }
2841 
2842     /** @hide */
invalidateGetAdapterConnectionStateCache()2843     public static void invalidateGetAdapterConnectionStateCache() {
2844         invalidateCache(GET_CONNECTION_API);
2845     }
2846 
2847     /**
2848      * Get the current connection state of the local Bluetooth adapter. This can be used to check
2849      * whether the local Bluetooth adapter is connected to any profile of any other remote Bluetooth
2850      * Device.
2851      *
2852      * <p>Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED} intent to get the
2853      * connection state of the adapter.
2854      *
2855      * @return the connection state
2856      * @hide
2857      */
2858     @SystemApi
2859     @RequiresNoPermission
getConnectionState()2860     public @ConnectionState int getConnectionState() {
2861         if (getState() != STATE_ON) {
2862             return BluetoothAdapter.STATE_DISCONNECTED;
2863         }
2864         mServiceLock.readLock().lock();
2865         try {
2866             if (mService != null) return sBluetoothGetAdapterConnectionStateCache.query(mService);
2867         } catch (RuntimeException e) {
2868             if (!(e.getCause() instanceof RemoteException)) {
2869                 throw e;
2870             }
2871             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2872         } finally {
2873             mServiceLock.readLock().unlock();
2874         }
2875         return STATE_DISCONNECTED;
2876     }
2877 
2878     private static final IpcDataCache.QueryHandler<
2879                     Pair<IBluetooth, Pair<AttributionSource, Integer>>, Integer>
2880             sBluetoothProfileQuery =
2881                     new IpcDataCache.QueryHandler<>() {
2882                         @Override
2883                         @RequiresBluetoothConnectPermission
2884                         @RequiresPermission(BLUETOOTH_CONNECT)
2885                         public Integer apply(
2886                                 Pair<IBluetooth, Pair<AttributionSource, Integer>> pairQuery) {
2887                             IBluetooth service = pairQuery.first;
2888                             AttributionSource source = pairQuery.second.first;
2889                             Integer profile = pairQuery.second.second;
2890                             try {
2891                                 return service.getProfileConnectionState(profile, source);
2892                             } catch (RemoteException e) {
2893                                 throw e.rethrowAsRuntimeException();
2894                             }
2895                         }
2896 
2897                         @RequiresNoPermission
2898                         @Override
2899                         public boolean shouldBypassCache(
2900                                 Pair<IBluetooth, Pair<AttributionSource, Integer>> pairQuery) {
2901                             return false;
2902                         }
2903                     };
2904 
2905     private static final String PROFILE_API = "BluetoothAdapter_getProfileConnectionState";
2906 
2907     private static final IpcDataCache<Pair<IBluetooth, Pair<AttributionSource, Integer>>, Integer>
2908             sGetProfileConnectionStateCache =
2909                     new BluetoothCache<>(PROFILE_API, sBluetoothProfileQuery);
2910 
2911     /** @hide */
2912     @RequiresNoPermission
disableGetProfileConnectionStateCache()2913     public void disableGetProfileConnectionStateCache() {
2914         sGetProfileConnectionStateCache.disableForCurrentProcess();
2915     }
2916 
2917     /** @hide */
invalidateGetProfileConnectionStateCache()2918     public static void invalidateGetProfileConnectionStateCache() {
2919         invalidateCache(PROFILE_API);
2920     }
2921 
2922     /**
2923      * Get the current connection state of a profile. This function can be used to check whether the
2924      * local Bluetooth adapter is connected to any remote device for a specific profile. Profile can
2925      * be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}.
2926      *
2927      * <p>Return the profile connection state
2928      */
2929     @RequiresLegacyBluetoothPermission
2930     @RequiresBluetoothConnectPermission
2931     @RequiresPermission(BLUETOOTH_CONNECT)
2932     @SuppressLint("AndroidFrameworkRequiresPermission") // IpcDataCache prevent lint enforcement
getProfileConnectionState(int profile)2933     public @ConnectionState int getProfileConnectionState(int profile) {
2934         if (getState() != STATE_ON) {
2935             return STATE_DISCONNECTED;
2936         }
2937         mServiceLock.readLock().lock();
2938         try {
2939             if (mService != null) {
2940                 return sGetProfileConnectionStateCache.query(
2941                         new Pair<>(mService, new Pair<>(mAttributionSource, profile)));
2942             }
2943         } catch (RuntimeException e) {
2944             if (!(e.getCause() instanceof RemoteException)) {
2945                 throw e;
2946             }
2947             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
2948         } finally {
2949             mServiceLock.readLock().unlock();
2950         }
2951         return STATE_DISCONNECTED;
2952     }
2953 
2954     /**
2955      * Create a listening, secure RFCOMM Bluetooth socket.
2956      *
2957      * <p>A remote device connecting to this socket will be authenticated and communication on this
2958      * socket will be encrypted.
2959      *
2960      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
2961      * {@link BluetoothServerSocket}.
2962      *
2963      * <p>Valid RFCOMM channels are in range 1 to 30.
2964      *
2965      * @param channel RFCOMM channel to listen on
2966      * @return a listening RFCOMM BluetoothServerSocket
2967      * @throws IOException on error, for example Bluetooth not available, or insufficient
2968      *     permissions, or channel in use.
2969      * @hide
2970      */
2971     @RequiresLegacyBluetoothAdminPermission
2972     @RequiresBluetoothConnectPermission
2973     @RequiresPermission(BLUETOOTH_CONNECT)
listenUsingRfcommOn(int channel)2974     public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
2975         return listenUsingRfcommOn(channel, false, false);
2976     }
2977 
2978     /**
2979      * Create a listening, secure RFCOMM Bluetooth socket.
2980      *
2981      * <p>A remote device connecting to this socket will be authenticated and communication on this
2982      * socket will be encrypted.
2983      *
2984      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
2985      * {@link BluetoothServerSocket}.
2986      *
2987      * <p>Valid RFCOMM channels are in range 1 to 30.
2988      *
2989      * <p>To auto assign a channel without creating a SDP record use {@link
2990      * #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number.
2991      *
2992      * @param channel RFCOMM channel to listen on
2993      * @param mitm enforce person-in-the-middle protection for authentication.
2994      * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 connections.
2995      * @return a listening RFCOMM BluetoothServerSocket
2996      * @throws IOException on error, for example Bluetooth not available, or insufficient
2997      *     permissions, or channel in use.
2998      * @hide
2999      */
3000     @UnsupportedAppUsage
3001     @RequiresLegacyBluetoothAdminPermission
3002     @RequiresBluetoothConnectPermission
3003     @RequiresPermission(BLUETOOTH_CONNECT)
listenUsingRfcommOn( int channel, boolean mitm, boolean min16DigitPin)3004     public BluetoothServerSocket listenUsingRfcommOn(
3005             int channel, boolean mitm, boolean min16DigitPin) throws IOException {
3006         BluetoothServerSocket socket =
3007                 new BluetoothServerSocket(
3008                         BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm, min16DigitPin);
3009         int errno = socket.mSocket.bindListen();
3010         if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
3011             socket.setChannel(socket.mSocket.getPort());
3012         }
3013         if (errno != 0) {
3014             // TODO(BT): Throw the same exception error code
3015             // that the previous code was using.
3016             // socket.mSocket.throwErrnoNative(errno);
3017             throw new IOException("Error: " + errno);
3018         }
3019         return socket;
3020     }
3021 
3022     /**
3023      * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
3024      *
3025      * <p>A remote device connecting to this socket will be authenticated and communication on this
3026      * socket will be encrypted.
3027      *
3028      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
3029      * {@link BluetoothServerSocket}.
3030      *
3031      * <p>The system will assign an unused RFCOMM channel to listen on.
3032      *
3033      * <p>The system will also register a Service Discovery Protocol (SDP) record with the local SDP
3034      * server containing the specified UUID, service name, and auto-assigned channel. Remote
3035      * Bluetooth devices can use the same UUID to query our SDP server and discover which channel to
3036      * connect to. This SDP record will be removed when this socket is closed, or if this
3037      * application closes unexpectedly.
3038      *
3039      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to connect to this socket
3040      * from another device using the same {@link UUID}.
3041      *
3042      * @param name service name for SDP record
3043      * @param uuid uuid for SDP record
3044      * @return a listening RFCOMM BluetoothServerSocket
3045      * @throws IOException on error, for example Bluetooth not available, or insufficient
3046      *     permissions, or channel in use.
3047      */
3048     @RequiresLegacyBluetoothPermission
3049     @RequiresBluetoothConnectPermission
3050     @RequiresPermission(BLUETOOTH_CONNECT)
listenUsingRfcommWithServiceRecord(String name, UUID uuid)3051     public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
3052             throws IOException {
3053         return createNewRfcommSocketAndRecord(name, uuid, true, true);
3054     }
3055 
3056     /**
3057      * Requests the framework to start an RFCOMM socket server which listens based on the provided
3058      * {@code name} and {@code uuid}.
3059      *
3060      * <p>Incoming connections will cause the system to start the component described in the {@link
3061      * PendingIntent}, {@code pendingIntent}. After the component is started, it should obtain a
3062      * {@link BluetoothAdapter} and retrieve the {@link BluetoothSocket} via {@link
3063      * #retrieveConnectedRfcommSocket(UUID)}.
3064      *
3065      * <p>An application may register multiple RFCOMM listeners. It is recommended to set the extra
3066      * field {@link #EXTRA_RFCOMM_LISTENER_ID} to help determine which service record the incoming
3067      * {@link BluetoothSocket} is using.
3068      *
3069      * <p>The provided {@link PendingIntent} must be created with the {@link
3070      * PendingIntent#FLAG_IMMUTABLE} flag.
3071      *
3072      * @param name service name for SDP record
3073      * @param uuid uuid for SDP record
3074      * @param pendingIntent component which is called when a new RFCOMM connection is available
3075      * @return a status code from {@link BluetoothStatusCodes}
3076      * @throws IllegalArgumentException if {@code pendingIntent} is not created with the {@link
3077      *     PendingIntent#FLAG_IMMUTABLE} flag.
3078      * @hide
3079      */
3080     @SystemApi
3081     @RequiresBluetoothConnectPermission
3082     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
startRfcommServer( @onNull String name, @NonNull UUID uuid, @NonNull PendingIntent pendingIntent)3083     public @RfcommListenerResult int startRfcommServer(
3084             @NonNull String name, @NonNull UUID uuid, @NonNull PendingIntent pendingIntent) {
3085         if (!pendingIntent.isImmutable()) {
3086             throw new IllegalArgumentException("The provided PendingIntent is not immutable");
3087         }
3088         mServiceLock.readLock().lock();
3089         try {
3090             if (mService != null) {
3091                 return mService.startRfcommListener(
3092                         name, new ParcelUuid(uuid), pendingIntent, mAttributionSource);
3093             }
3094         } catch (RemoteException e) {
3095             logRemoteException(TAG, e);
3096         } finally {
3097             mServiceLock.readLock().unlock();
3098         }
3099         return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
3100     }
3101 
3102     /**
3103      * Closes the RFCOMM socket server listening on the given SDP record name and UUID. This can be
3104      * called by applications after calling {@link #startRfcommServer(String, UUID, PendingIntent)}
3105      * to stop listening for incoming RFCOMM connections.
3106      *
3107      * @param uuid uuid for SDP record
3108      * @return a status code from {@link BluetoothStatusCodes}
3109      * @hide
3110      */
3111     @SystemApi
3112     @RequiresBluetoothConnectPermission
3113     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
stopRfcommServer(@onNull UUID uuid)3114     public @RfcommListenerResult int stopRfcommServer(@NonNull UUID uuid) {
3115         mServiceLock.readLock().lock();
3116         try {
3117             if (mService != null) {
3118                 return mService.stopRfcommListener(new ParcelUuid(uuid), mAttributionSource);
3119             }
3120         } catch (RemoteException e) {
3121             logRemoteException(TAG, e);
3122         } finally {
3123             mServiceLock.readLock().unlock();
3124         }
3125         return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
3126     }
3127 
3128     /**
3129      * Retrieves a connected {@link BluetoothSocket} for the given service record from a RFCOMM
3130      * listener which was registered with {@link #startRfcommServer(String, UUID, PendingIntent)}.
3131      *
3132      * <p>This method should be called by the component started by the {@link PendingIntent} which
3133      * was registered during the call to {@link #startRfcommServer(String, UUID, PendingIntent)} in
3134      * order to retrieve the socket.
3135      *
3136      * @param uuid the same UUID used to register the listener previously
3137      * @return a connected {@link BluetoothSocket} or {@code null} if no socket is available
3138      * @throws IllegalStateException if the socket could not be retrieved because the application is
3139      *     trying to obtain a socket for a listener it did not register (incorrect {@code uuid}).
3140      * @hide
3141      */
3142     @SystemApi
3143     @RequiresBluetoothConnectPermission
3144     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
retrieveConnectedRfcommSocket(@onNull UUID uuid)3145     public @NonNull BluetoothSocket retrieveConnectedRfcommSocket(@NonNull UUID uuid) {
3146         IncomingRfcommSocketInfo socketInfo = null;
3147 
3148         mServiceLock.readLock().lock();
3149         try {
3150             if (mService != null) {
3151                 socketInfo =
3152                         mService.retrievePendingSocketForServiceRecord(
3153                                 new ParcelUuid(uuid), mAttributionSource);
3154             }
3155         } catch (RemoteException e) {
3156             logRemoteException(TAG, e);
3157             return null;
3158         } finally {
3159             mServiceLock.readLock().unlock();
3160         }
3161         if (socketInfo == null) {
3162             return null;
3163         }
3164 
3165         switch (socketInfo.status) {
3166             case BluetoothStatusCodes.SUCCESS:
3167                 try {
3168                     return BluetoothSocket.createSocketFromOpenFd(
3169                             socketInfo.pfd, socketInfo.bluetoothDevice, new ParcelUuid(uuid));
3170                 } catch (IOException e) {
3171                     return null;
3172                 }
3173             case BluetoothStatusCodes.RFCOMM_LISTENER_OPERATION_FAILED_DIFFERENT_APP:
3174                 throw new IllegalStateException(
3175                         "RFCOMM listener for UUID " + uuid + " was not registered by this app");
3176             case BluetoothStatusCodes.RFCOMM_LISTENER_NO_SOCKET_AVAILABLE:
3177                 return null;
3178             default:
3179                 Log.e(
3180                         TAG,
3181                         "Unexpected result: ("
3182                                 + socketInfo.status
3183                                 + "), from the adapter service"
3184                                 + " while retrieving an rfcomm socket");
3185                 return null;
3186         }
3187     }
3188 
3189     /**
3190      * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
3191      *
3192      * <p>The link key is not required to be authenticated, i.e. the communication may be vulnerable
3193      * to Person In the Middle attacks. For Bluetooth 2.1 devices, the link will be encrypted, as
3194      * encryption is mandatory. For legacy devices (pre Bluetooth 2.1 devices) the link will not be
3195      * encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an encrypted and authenticated
3196      * communication channel is desired.
3197      *
3198      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
3199      * {@link BluetoothServerSocket}.
3200      *
3201      * <p>The system will assign an unused RFCOMM channel to listen on.
3202      *
3203      * <p>The system will also register a Service Discovery Protocol (SDP) record with the local SDP
3204      * server containing the specified UUID, service name, and auto-assigned channel. Remote
3205      * Bluetooth devices can use the same UUID to query our SDP server and discover which channel to
3206      * connect to. This SDP record will be removed when this socket is closed, or if this
3207      * application closes unexpectedly.
3208      *
3209      * <p>Use {@link BluetoothDevice#createInsecureRfcommSocketToServiceRecord} to connect to this
3210      * socket from another device using the same {@link UUID}.
3211      *
3212      * @param name service name for SDP record
3213      * @param uuid uuid for SDP record
3214      * @return a listening RFCOMM BluetoothServerSocket
3215      * @throws IOException on error, for example Bluetooth not available, or insufficient
3216      *     permissions, or channel in use.
3217      */
3218     @RequiresLegacyBluetoothPermission
3219     @RequiresBluetoothConnectPermission
3220     @RequiresPermission(BLUETOOTH_CONNECT)
listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)3221     public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
3222             throws IOException {
3223         return createNewRfcommSocketAndRecord(name, uuid, false, false);
3224     }
3225 
3226     /**
3227      * Create a listening, encrypted, RFCOMM Bluetooth socket with Service Record.
3228      *
3229      * <p>The link will be encrypted, but the link key is not required to be authenticated i.e. the
3230      * communication is vulnerable to Person In the Middle attacks. Use {@link
3231      * #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key.
3232      *
3233      * <p>Use this socket if authentication of link key is not possible. For example, for Bluetooth
3234      * 2.1 devices, if any of the devices does not have an input and output capability or just has
3235      * the ability to display a numeric key, a secure socket connection is not possible and this
3236      * socket can be used. Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is
3237      * not required. For Bluetooth 2.1 devices, the link will be encrypted, as encryption is
3238      * mandatory. For more details, refer to the Security Model section 5.2 (vol 3) of Bluetooth
3239      * Core Specification version 2.1 + EDR.
3240      *
3241      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
3242      * {@link BluetoothServerSocket}.
3243      *
3244      * <p>The system will assign an unused RFCOMM channel to listen on.
3245      *
3246      * <p>The system will also register a Service Discovery Protocol (SDP) record with the local SDP
3247      * server containing the specified UUID, service name, and auto-assigned channel. Remote
3248      * Bluetooth devices can use the same UUID to query our SDP server and discover which channel to
3249      * connect to. This SDP record will be removed when this socket is closed, or if this
3250      * application closes unexpectedly.
3251      *
3252      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to connect to this socket
3253      * from another device using the same {@link UUID}.
3254      *
3255      * @param name service name for SDP record
3256      * @param uuid uuid for SDP record
3257      * @return a listening RFCOMM BluetoothServerSocket
3258      * @throws IOException on error, for example Bluetooth not available, or insufficient
3259      *     permissions, or channel in use.
3260      * @hide
3261      */
3262     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
3263     @RequiresLegacyBluetoothPermission
3264     @RequiresBluetoothConnectPermission
3265     @RequiresPermission(BLUETOOTH_CONNECT)
listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid)3266     public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid)
3267             throws IOException {
3268         return createNewRfcommSocketAndRecord(name, uuid, false, true);
3269     }
3270 
3271     @RequiresBluetoothConnectPermission
3272     @RequiresPermission(BLUETOOTH_CONNECT)
createNewRfcommSocketAndRecord( String name, UUID uuid, boolean auth, boolean encrypt)3273     private static BluetoothServerSocket createNewRfcommSocketAndRecord(
3274             String name, UUID uuid, boolean auth, boolean encrypt) throws IOException {
3275         BluetoothServerSocket socket;
3276         socket =
3277                 new BluetoothServerSocket(
3278                         BluetoothSocket.TYPE_RFCOMM, auth, encrypt, new ParcelUuid(uuid));
3279         socket.setServiceName(name);
3280         int errno = socket.mSocket.bindListen();
3281         if (errno != 0) {
3282             // TODO(BT): Throw the same exception error code
3283             // that the previous code was using.
3284             // socket.mSocket.throwErrnoNative(errno);
3285             throw new IOException("Error: " + errno);
3286         }
3287         return socket;
3288     }
3289 
3290     /**
3291      * Construct an unencrypted, unauthenticated, RFCOMM server socket. Call #accept to retrieve
3292      * connections to this socket.
3293      *
3294      * @return An RFCOMM BluetoothServerSocket
3295      * @throws IOException On error, for example Bluetooth not available, or insufficient
3296      *     permissions.
3297      * @hide
3298      */
3299     @RequiresBluetoothConnectPermission
3300     @RequiresPermission(BLUETOOTH_CONNECT)
listenUsingInsecureRfcommOn(int port)3301     public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
3302         BluetoothServerSocket socket =
3303                 new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, false, port);
3304         int errno = socket.mSocket.bindListen();
3305         if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
3306             socket.setChannel(socket.mSocket.getPort());
3307         }
3308         if (errno != 0) {
3309             // TODO(BT): Throw the same exception error code
3310             // that the previous code was using.
3311             // socket.mSocket.throwErrnoNative(errno);
3312             throw new IOException("Error: " + errno);
3313         }
3314         return socket;
3315     }
3316 
3317     /**
3318      * Construct an encrypted, authenticated, L2CAP server socket. Call #accept to retrieve
3319      * connections to this socket.
3320      *
3321      * <p>To auto assign a port without creating a SDP record use {@link
3322      * #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
3323      *
3324      * @param port the PSM to listen on
3325      * @param mitm enforce person-in-the-middle protection for authentication.
3326      * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 connections.
3327      * @return An L2CAP BluetoothServerSocket
3328      * @throws IOException On error, for example Bluetooth not available, or insufficient
3329      *     permissions.
3330      * @hide
3331      */
3332     @RequiresBluetoothConnectPermission
3333     @RequiresPermission(BLUETOOTH_CONNECT)
listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)3334     public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)
3335             throws IOException {
3336         BluetoothServerSocket socket =
3337                 new BluetoothServerSocket(
3338                         BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, min16DigitPin);
3339         int errno = socket.mSocket.bindListen();
3340         if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
3341             int assignedChannel = socket.mSocket.getPort();
3342             if (DBG) Log.d(TAG, "listenUsingL2capOn: set assigned channel to " + assignedChannel);
3343             socket.setChannel(assignedChannel);
3344         }
3345         if (errno != 0) {
3346             // TODO(BT): Throw the same exception error code
3347             // that the previous code was using.
3348             // socket.mSocket.throwErrnoNative(errno);
3349             throw new IOException("Error: " + errno);
3350         }
3351         return socket;
3352     }
3353 
3354     /**
3355      * Construct an encrypted, authenticated, L2CAP server socket. Call #accept to retrieve
3356      * connections to this socket.
3357      *
3358      * <p>To auto assign a port without creating a SDP record use {@link
3359      * #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
3360      *
3361      * @param port the PSM to listen on
3362      * @return An L2CAP BluetoothServerSocket
3363      * @throws IOException On error, for example Bluetooth not available, or insufficient
3364      *     permissions.
3365      * @hide
3366      */
3367     @RequiresBluetoothConnectPermission
3368     @RequiresPermission(BLUETOOTH_CONNECT)
listenUsingL2capOn(int port)3369     public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException {
3370         return listenUsingL2capOn(port, false, false);
3371     }
3372 
3373     /**
3374      * Construct an insecure L2CAP server socket. Call #accept to retrieve connections to this
3375      * socket.
3376      *
3377      * <p>To auto assign a port without creating a SDP record use {@link
3378      * #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
3379      *
3380      * @param port the PSM to listen on
3381      * @return An L2CAP BluetoothServerSocket
3382      * @throws IOException On error, for example Bluetooth not available, or insufficient
3383      *     permissions.
3384      * @hide
3385      */
3386     @RequiresBluetoothConnectPermission
3387     @RequiresPermission(BLUETOOTH_CONNECT)
listenUsingInsecureL2capOn(int port)3388     public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException {
3389         Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port);
3390         BluetoothServerSocket socket =
3391                 new BluetoothServerSocket(
3392                         BluetoothSocket.TYPE_L2CAP, false, false, port, false, false);
3393         int errno = socket.mSocket.bindListen();
3394         if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
3395             int assignedChannel = socket.mSocket.getPort();
3396             if (DBG) {
3397                 Log.d(
3398                         TAG,
3399                         "listenUsingInsecureL2capOn: set assigned channel to " + assignedChannel);
3400             }
3401             socket.setChannel(assignedChannel);
3402         }
3403         if (errno != 0) {
3404             // TODO(BT): Throw the same exception error code
3405             // that the previous code was using.
3406             // socket.mSocket.throwErrnoNative(errno);
3407             throw new IOException("Error: " + errno);
3408         }
3409         return socket;
3410     }
3411 
3412     /**
3413      * Get the profile proxy object associated with the profile.
3414      *
3415      * <p>The ServiceListener's methods will be invoked on the application's main looper
3416      *
3417      * @param context Context of the application
3418      * @param listener The service listener for connection callbacks.
3419      * @param profile The Bluetooth profile to listen for status change
3420      * @return true on success, false on error
3421      */
3422     @SuppressLint("AndroidFrameworkCompatChange")
3423     @RequiresNoPermission
getProfileProxy( Context context, BluetoothProfile.ServiceListener listener, int profile)3424     public boolean getProfileProxy(
3425             Context context, BluetoothProfile.ServiceListener listener, int profile) {
3426         if (context == null || listener == null) {
3427             return false;
3428         }
3429 
3430         // Preserve legacy compatibility where apps were depending on
3431         // registerStateChangeCallback() performing a permissions check which
3432         // has been relaxed in modern platform versions
3433         if (context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.S
3434                 && context.checkSelfPermission(BLUETOOTH) != PackageManager.PERMISSION_GRANTED) {
3435             throw new SecurityException("Need BLUETOOTH permission");
3436         }
3437 
3438         return getProfileProxy(context, listener, profile, mMainHandler::post);
3439     }
3440 
getProfileProxy( @onNull Context context, @NonNull BluetoothProfile.ServiceListener listener, int profile, @NonNull @CallbackExecutor Executor executor)3441     private boolean getProfileProxy(
3442             @NonNull Context context,
3443             @NonNull BluetoothProfile.ServiceListener listener,
3444             int profile,
3445             @NonNull @CallbackExecutor Executor executor) {
3446         requireNonNull(context);
3447         requireNonNull(listener);
3448         requireNonNull(executor);
3449 
3450         if (profile == BluetoothProfile.HEALTH) {
3451             Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated");
3452             return false;
3453         }
3454 
3455         if (profile == BluetoothProfile.HEARING_AID && !isHearingAidProfileSupported()) {
3456             Log.e(TAG, "getProfileProxy(): BluetoothHearingAid is not supported");
3457             return false;
3458         }
3459 
3460         BiFunction<Context, BluetoothAdapter, BluetoothProfile> constructor =
3461                 PROFILE_CONSTRUCTORS.get(profile);
3462 
3463         if (constructor == null) {
3464             Log.e(TAG, "getProfileProxy(): Unknown profile " + profile);
3465             return false;
3466         }
3467 
3468         BluetoothProfile profileProxy = constructor.apply(context, this);
3469         ProfileConnection connection = new ProfileConnection(profile, listener, executor);
3470 
3471         synchronized (sProfileLock) {
3472             // Synchronize with the binder callback to prevent performing the
3473             // ProfileConnection.connect concurrently
3474             mProfileConnections.put(profileProxy, connection);
3475 
3476             IBinder binder = getProfile(profile);
3477             if (binder != null) {
3478                 connection.connect(profileProxy, binder);
3479             }
3480         }
3481         return true;
3482     }
3483 
3484     /**
3485      * Close the connection of the profile proxy to the Service.
3486      *
3487      * <p>Clients should call this when they are no longer using the proxy obtained from {@link
3488      * #getProfileProxy}.
3489      *
3490      * @param proxy Profile proxy object
3491      * @hide
3492      */
3493     @SuppressLint("AndroidFrameworkRequiresPermission") // Call control is not exposed to 3p app
3494     @RequiresNoPermission
closeProfileProxy(@onNull BluetoothProfile proxy)3495     public void closeProfileProxy(@NonNull BluetoothProfile proxy) {
3496         if (proxy instanceof BluetoothGatt gatt) {
3497             gatt.close();
3498             return;
3499         } else if (proxy instanceof BluetoothGattServer gatt) {
3500             gatt.close();
3501             return;
3502         }
3503 
3504         if (proxy.getAdapter() != this) {
3505             Log.e(
3506                     TAG,
3507                     "closeProfileProxy(): Called on wrong instance was "
3508                             + proxy.getAdapter()
3509                             + " but expected "
3510                             + this);
3511             Counter.logIncrementWithUid(
3512                     "bluetooth.value_close_profile_proxy_adapter_mismatch", Process.myUid());
3513             proxy.getAdapter().closeProfileProxy(proxy);
3514             return;
3515         }
3516 
3517         synchronized (sProfileLock) {
3518             ProfileConnection connection = mProfileConnections.remove(proxy);
3519             if (connection != null) {
3520                 if (proxy instanceof BluetoothLeCallControl callControl) {
3521                     callControl.unregisterBearer();
3522                 }
3523 
3524                 connection.disconnect(proxy);
3525             }
3526         }
3527     }
3528 
3529     /**
3530      * Close the connection of the profile proxy to the Service.
3531      *
3532      * <p>Clients should call this when they are no longer using the proxy obtained from {@link
3533      * #getProfileProxy}. Profile can be one of {@link BluetoothProfile#HEADSET} or {@link
3534      * BluetoothProfile#A2DP}
3535      *
3536      * @param proxy Profile proxy object
3537      */
3538     @RequiresNoPermission
closeProfileProxy(int unusedProfile, BluetoothProfile proxy)3539     public void closeProfileProxy(int unusedProfile, BluetoothProfile proxy) {
3540         if (proxy == null) {
3541             return;
3542         }
3543         closeProfileProxy(proxy);
3544     }
3545 
3546     private static final IBluetoothManagerCallback sManagerCallback =
3547             new IBluetoothManagerCallback.Stub() {
3548                 @RequiresNoPermission
3549                 public void onBluetoothServiceUp(IBinder bluetoothService) {
3550                     if (DBG) {
3551                         Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
3552                     }
3553 
3554                     sServiceLock.writeLock().lock();
3555                     try {
3556                         sService = IBluetooth.Stub.asInterface(bluetoothService);
3557                         for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
3558                             try {
3559                                 cb.onBluetoothServiceUp(bluetoothService);
3560                             } catch (RemoteException e) {
3561                                 logRemoteException(TAG, e);
3562                             }
3563                         }
3564                     } finally {
3565                         sServiceLock.writeLock().unlock();
3566                     }
3567                 }
3568 
3569                 @RequiresNoPermission
3570                 public void onBluetoothServiceDown() {
3571                     if (DBG) {
3572                         Log.d(TAG, "onBluetoothServiceDown");
3573                     }
3574 
3575                     sServiceLock.writeLock().lock();
3576                     try {
3577                         sService = null;
3578                         for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
3579                             try {
3580                                 cb.onBluetoothServiceDown();
3581                             } catch (RemoteException e) {
3582                                 logRemoteException(TAG, e);
3583                             }
3584                         }
3585                     } finally {
3586                         sServiceLock.writeLock().unlock();
3587                     }
3588                 }
3589 
3590                 @RequiresNoPermission
3591                 public void onBluetoothOn() {
3592                     if (DBG) {
3593                         Log.d(TAG, "onBluetoothOn");
3594                     }
3595 
3596                     sServiceLock.readLock().lock();
3597                     try {
3598                         for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
3599                             try {
3600                                 cb.onBluetoothOn();
3601                             } catch (RemoteException e) {
3602                                 logRemoteException(TAG, e);
3603                             }
3604                         }
3605                     } finally {
3606                         sServiceLock.readLock().unlock();
3607                     }
3608                 }
3609 
3610                 @RequiresNoPermission
3611                 public void onBluetoothOff() {
3612                     if (DBG) {
3613                         Log.d(TAG, "onBluetoothOff");
3614                     }
3615 
3616                     sServiceLock.readLock().lock();
3617                     try {
3618                         for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
3619                             try {
3620                                 cb.onBluetoothOff();
3621                             } catch (RemoteException e) {
3622                                 logRemoteException(TAG, e);
3623                             }
3624                         }
3625                     } finally {
3626                         sServiceLock.readLock().unlock();
3627                     }
3628                 }
3629             };
3630 
3631     private final IBluetoothManagerCallback mManagerCallback =
3632             new IBluetoothManagerCallback.Stub() {
3633                 @SuppressLint("AndroidFrameworkRequiresPermission") // Internal callback
3634                 @RequiresNoPermission
3635                 public void onBluetoothServiceUp(@NonNull IBinder bluetoothService) {
3636                     requireNonNull(bluetoothService);
3637                     mServiceLock.writeLock().lock();
3638                     try {
3639                         mService = IBluetooth.Stub.asInterface(bluetoothService);
3640                     } finally {
3641                         // lock downgrade is possible in ReentrantReadWriteLock
3642                         mServiceLock.readLock().lock();
3643                         mServiceLock.writeLock().unlock();
3644                     }
3645                     try {
3646                         synchronized (mMetadataListeners) {
3647                             mMetadataListeners.forEach(
3648                                     (device, pair) -> {
3649                                         try {
3650                                             mService.registerMetadataListener(
3651                                                     mBluetoothMetadataListener,
3652                                                     device,
3653                                                     mAttributionSource);
3654                                         } catch (RemoteException e) {
3655                                             Log.e(TAG, "Failed to register metadata listener", e);
3656                                             logRemoteException(TAG, e);
3657                                         }
3658                                     });
3659                         }
3660                         mAudioProfilesCallbackWrapper.registerToNewService(mService);
3661                         mQualityCallbackWrapper.registerToNewService(mService);
3662                         mBluetoothConnectionCallbackWrapper.registerToNewService(mService);
3663                         synchronized (mHciVendorSpecificCallbackRegistration) {
3664                             try {
3665                                 mHciVendorSpecificCallbackRegistration.registerToService(
3666                                         mService, mHciVendorSpecificCallbackStub);
3667                             } catch (Exception e) {
3668                                 Log.e(TAG, "Failed to register HCI vendor-specific callback", e);
3669                             }
3670                         }
3671                     } finally {
3672                         mServiceLock.readLock().unlock();
3673                     }
3674                 }
3675 
3676                 @RequiresNoPermission
3677                 public void onBluetoothServiceDown() {
3678                     mServiceLock.writeLock().lock();
3679                     try {
3680                         mService = null;
3681                         mLeScanClients.clear();
3682                         synchronized (mLock) {
3683                             if (mBluetoothLeAdvertiser != null) {
3684                                 mBluetoothLeAdvertiser.cleanup();
3685                             }
3686                             if (mBluetoothLeScanner != null) {
3687                                 mBluetoothLeScanner.cleanup();
3688                             }
3689                             if (mDistanceMeasurementManager != null) {
3690                                 mDistanceMeasurementManager.cleanup();
3691                             }
3692                         }
3693                     } finally {
3694                         mServiceLock.writeLock().unlock();
3695                     }
3696                 }
3697 
3698                 @GuardedBy("sProfileLock")
3699                 private boolean connectAllProfileProxyLocked() {
3700                     mProfileConnections.forEach(
3701                             (proxy, connection) -> {
3702                                 if (connection.mConnected) return;
3703 
3704                                 IBinder binder = getProfile(connection.mProfile);
3705                                 if (binder == null) {
3706                                     Log.e(
3707                                             TAG,
3708                                             "Failed to retrieve a binder for "
3709                                                     + getProfileName(connection.mProfile));
3710                                     return;
3711                                 }
3712                                 connection.connect(proxy, binder);
3713                             });
3714                     return true;
3715                 }
3716 
3717                 @RequiresNoPermission
3718                 public void onBluetoothOn() {
3719                     synchronized (sProfileLock) {
3720                         connectAllProfileProxyLocked();
3721                     }
3722                 }
3723 
3724                 @RequiresNoPermission
3725                 public void onBluetoothOff() {
3726                     synchronized (sProfileLock) {
3727                         mProfileConnections.forEach(
3728                                 (proxy, connection) -> {
3729                                     if (connection.mConnected) {
3730                                         connection.disconnect(proxy);
3731                                     }
3732                                 });
3733                     }
3734                 }
3735             };
3736 
3737     /**
3738      * Enable the Bluetooth Adapter, but don't auto-connect devices and don't persist state. Only
3739      * for use by system applications.
3740      *
3741      * @hide
3742      */
3743     @SystemApi
3744     @RequiresLegacyBluetoothAdminPermission
3745     @RequiresBluetoothConnectPermission
3746     @RequiresPermission(BLUETOOTH_CONNECT)
enableNoAutoConnect()3747     public boolean enableNoAutoConnect() {
3748         if (isEnabled()) {
3749             if (DBG) {
3750                 Log.d(TAG, "enableNoAutoConnect(): BT already enabled!");
3751             }
3752             return true;
3753         }
3754         try {
3755             return mManagerService.enableNoAutoConnect(mAttributionSource);
3756         } catch (RemoteException e) {
3757             throw e.rethrowFromSystemServer();
3758         }
3759     }
3760 
3761     /** @hide */
3762     @Retention(RetentionPolicy.SOURCE)
3763     @IntDef(
3764             value = {
3765                 BluetoothStatusCodes.ERROR_UNKNOWN,
3766                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
3767                 BluetoothStatusCodes.ERROR_ANOTHER_ACTIVE_OOB_REQUEST,
3768             })
3769     public @interface OobError {}
3770 
3771     /**
3772      * Provides callback methods for receiving {@link OobData} from the host stack, as well as an
3773      * error interface in order to allow the caller to determine next steps based on the {@code
3774      * ErrorCode}.
3775      *
3776      * @hide
3777      */
3778     @SystemApi
3779     public interface OobDataCallback {
3780         /**
3781          * Handles the {@link OobData} received from the host stack.
3782          *
3783          * @param transport - whether the {@link OobData} is generated for LE or Classic.
3784          * @param oobData - data generated in the host stack(LE) or controller (Classic)
3785          */
onOobData(@ransport int transport, @NonNull OobData oobData)3786         void onOobData(@Transport int transport, @NonNull OobData oobData);
3787 
3788         /**
3789          * Provides feedback when things don't go as expected.
3790          *
3791          * @param errorCode - the code describing the type of error that occurred.
3792          */
onError(@obError int errorCode)3793         void onError(@OobError int errorCode);
3794     }
3795 
3796     /**
3797      * Wraps an AIDL interface around an {@link OobDataCallback} interface.
3798      *
3799      * @see IBluetoothOobDataCallback for interface definition.
3800      * @hide
3801      */
3802     private static class WrappedOobDataCallback extends IBluetoothOobDataCallback.Stub {
3803         private final OobDataCallback mCallback;
3804         private final Executor mExecutor;
3805 
3806         /**
3807          * @param callback - object to receive {@link OobData} must be a non null argument
3808          * @throws NullPointerException if the callback is null.
3809          */
WrappedOobDataCallback( @onNull OobDataCallback callback, @NonNull @CallbackExecutor Executor executor)3810         WrappedOobDataCallback(
3811                 @NonNull OobDataCallback callback, @NonNull @CallbackExecutor Executor executor) {
3812             requireNonNull(callback);
3813             requireNonNull(executor);
3814             mCallback = callback;
3815             mExecutor = executor;
3816         }
3817 
onOobData(@ransport int transport, @NonNull OobData oobData)3818         public void onOobData(@Transport int transport, @NonNull OobData oobData) {
3819             executeFromBinder(mExecutor, () -> mCallback.onOobData(transport, oobData));
3820         }
3821 
onError(@obError int errorCode)3822         public void onError(@OobError int errorCode) {
3823             executeFromBinder(mExecutor, () -> mCallback.onError(errorCode));
3824         }
3825     }
3826 
3827     /**
3828      * Fetches a secret data value that can be used for a secure and simple pairing experience.
3829      *
3830      * <p>This is the Local Out of Band data the comes from the
3831      *
3832      * <p>This secret is the local Out of Band data. This data is used to securely and quickly pair
3833      * two devices with minimal user interaction.
3834      *
3835      * <p>For example, this secret can be transferred to a remote device out of band (meaning any
3836      * other way besides using bluetooth). Once the remote device finds this device using the
3837      * information given in the data, such as the PUBLIC ADDRESS, the remote device could then
3838      * connect to this device using this secret when the pairing sequence asks for the secret. This
3839      * device will respond by automatically accepting the pairing due to the secret being so
3840      * trustworthy.
3841      *
3842      * @param transport - provide type of transport (e.g. LE or Classic).
3843      * @param callback - target object to receive the {@link OobData} value.
3844      * @throws NullPointerException if callback is null.
3845      * @throws IllegalArgumentException if the transport is not valid.
3846      * @hide
3847      */
3848     @SystemApi
3849     @RequiresBluetoothConnectPermission
3850     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
generateLocalOobData( @ransport int transport, @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback)3851     public void generateLocalOobData(
3852             @Transport int transport,
3853             @NonNull @CallbackExecutor Executor executor,
3854             @NonNull OobDataCallback callback) {
3855         if (transport != BluetoothDevice.TRANSPORT_BREDR
3856                 && transport != BluetoothDevice.TRANSPORT_LE) {
3857             throw new IllegalArgumentException("Invalid transport '" + transport + "'!");
3858         }
3859         requireNonNull(callback);
3860         if (!isEnabled()) {
3861             Log.w(TAG, "generateLocalOobData(): Adapter isn't enabled!");
3862             callback.onError(BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
3863         } else {
3864             mServiceLock.readLock().lock();
3865             try {
3866                 if (mService != null) {
3867                     mService.generateLocalOobData(
3868                             transport,
3869                             new WrappedOobDataCallback(callback, executor),
3870                             mAttributionSource);
3871                 }
3872             } catch (RemoteException e) {
3873                 logRemoteException(TAG, e);
3874             } finally {
3875                 mServiceLock.readLock().unlock();
3876             }
3877         }
3878     }
3879 
toDeviceSet(List<BluetoothDevice> devices)3880     private static Set<BluetoothDevice> toDeviceSet(List<BluetoothDevice> devices) {
3881         Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(devices);
3882         return Collections.unmodifiableSet(deviceSet);
3883     }
3884 
3885     @Override
3886     @SuppressLint("GenericException")
3887     @SuppressWarnings("Finalize") // TODO(b/314811467)
finalize()3888     protected void finalize() throws Throwable {
3889         try {
3890             removeServiceStateCallback(mManagerCallback);
3891         } finally {
3892             super.finalize();
3893         }
3894     }
3895 
3896     /**
3897      * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
3898      *
3899      * <p>Alphabetic characters must be uppercase to be valid.
3900      *
3901      * @param address Bluetooth address as string
3902      * @return true if the address is valid, false otherwise
3903      */
checkBluetoothAddress(String address)3904     public static boolean checkBluetoothAddress(String address) {
3905         if (address == null || address.length() != ADDRESS_LENGTH) {
3906             return false;
3907         }
3908         for (int i = 0; i < ADDRESS_LENGTH; i++) {
3909             char c = address.charAt(i);
3910             switch (i % 3) {
3911                 case 0:
3912                 case 1:
3913                     if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
3914                         // hex character, OK
3915                         break;
3916                     }
3917                     return false;
3918                 case 2:
3919                     if (c == ':') {
3920                         break; // OK
3921                     }
3922                     return false;
3923             }
3924         }
3925         return true;
3926     }
3927 
3928     /**
3929      * Determines whether a String Bluetooth address, such as "F0:43:A8:23:10:00" is a RANDOM STATIC
3930      * address.
3931      *
3932      * <p>RANDOM STATIC: (addr & 0xC0) == 0xC0 RANDOM RESOLVABLE: (addr & 0xC0) == 0x40 RANDOM
3933      * non-RESOLVABLE: (addr & 0xC0) == 0x00
3934      *
3935      * @param address Bluetooth address as string
3936      * @return true if the 2 Most Significant Bits of the address equals 0xC0.
3937      * @hide
3938      */
isAddressRandomStatic(@onNull String address)3939     public static boolean isAddressRandomStatic(@NonNull String address) {
3940         requireNonNull(address);
3941         return checkBluetoothAddress(address)
3942                 && (Integer.parseInt(address.split(":")[0], 16) & 0xC0) == 0xC0;
3943     }
3944 
3945     /** @hide */
3946     @UnsupportedAppUsage
3947     @RequiresNoPermission
getBluetoothManager()3948     public IBluetoothManager getBluetoothManager() {
3949         return mManagerService;
3950     }
3951 
3952     /** @hide */
3953     @RequiresNoPermission
getAttributionSource()3954     public AttributionSource getAttributionSource() {
3955         return mAttributionSource;
3956     }
3957 
3958     @GuardedBy("sServiceLock")
3959     private static final WeakHashMap<IBluetoothManagerCallback, Void> sProxyServiceStateCallbacks =
3960             new WeakHashMap<>();
3961 
getBluetoothService()3962     /*package*/ IBluetooth getBluetoothService() {
3963         sServiceLock.readLock().lock();
3964         try {
3965             return sService;
3966         } finally {
3967             sServiceLock.readLock().unlock();
3968         }
3969     }
3970 
3971     /** Registers a IBluetoothManagerCallback and returns the cached service proxy object. */
registerBluetoothManagerCallback(IBluetoothManagerCallback cb)3972     IBluetooth registerBluetoothManagerCallback(IBluetoothManagerCallback cb) {
3973         requireNonNull(cb);
3974         sServiceLock.writeLock().lock();
3975         try {
3976             sProxyServiceStateCallbacks.put(cb, null);
3977             registerOrUnregisterAdapterLocked();
3978             return sService;
3979         } finally {
3980             sServiceLock.writeLock().unlock();
3981         }
3982     }
3983 
3984     /**
3985      * Return a binder to BluetoothGatt service
3986      *
3987      * @hide
3988      */
3989     @RequiresNoPermission
getBluetoothGatt()3990     public @Nullable IBluetoothGatt getBluetoothGatt() {
3991         mServiceLock.readLock().lock();
3992         try {
3993             if (mService != null) {
3994                 return IBluetoothGatt.Stub.asInterface(mService.getBluetoothGatt());
3995             }
3996         } catch (RemoteException e) {
3997             logRemoteException(TAG, e);
3998         } finally {
3999             mServiceLock.readLock().unlock();
4000         }
4001         return null;
4002     }
4003 
4004     /**
4005      * Return a binder to BluetoothScan
4006      *
4007      * @hide
4008      */
4009     @RequiresNoPermission
getBluetoothScan()4010     public @Nullable IBluetoothScan getBluetoothScan() {
4011         mServiceLock.readLock().lock();
4012         try {
4013             if (mService != null) {
4014                 return IBluetoothScan.Stub.asInterface(mService.getBluetoothScan());
4015             }
4016         } catch (RemoteException e) {
4017             logRemoteException(TAG, e);
4018         } finally {
4019             mServiceLock.readLock().unlock();
4020         }
4021         return null;
4022     }
4023 
4024     /**
4025      * Return a binder to BluetoothAdvertise
4026      *
4027      * @hide
4028      */
4029     @RequiresNoPermission
getBluetoothAdvertise()4030     public @Nullable IBluetoothAdvertise getBluetoothAdvertise() {
4031         mServiceLock.readLock().lock();
4032         try {
4033             if (mService != null) {
4034                 return IBluetoothAdvertise.Stub.asInterface(mService.getBluetoothAdvertise());
4035             }
4036         } catch (RemoteException e) {
4037             logRemoteException(TAG, e);
4038         } finally {
4039             mServiceLock.readLock().unlock();
4040         }
4041         return null;
4042     }
4043 
4044     /**
4045      * Return a binder to DistanceMeasurement
4046      *
4047      * @hide
4048      */
4049     @RequiresNoPermission
getDistanceMeasurement()4050     public @Nullable IDistanceMeasurement getDistanceMeasurement() {
4051         mServiceLock.readLock().lock();
4052         try {
4053             if (mService != null) {
4054                 return IDistanceMeasurement.Stub.asInterface(mService.getDistanceMeasurement());
4055             }
4056         } catch (RemoteException e) {
4057             logRemoteException(TAG, e);
4058         } finally {
4059             mServiceLock.readLock().unlock();
4060         }
4061         return null;
4062     }
4063 
4064     /** Return a binder to a Profile service */
getProfile(int profile)4065     private @Nullable IBinder getProfile(int profile) {
4066         mServiceLock.readLock().lock();
4067         try {
4068             if (mService != null) {
4069                 return mService.getProfile(profile);
4070             }
4071         } catch (RemoteException e) {
4072             logRemoteException(TAG, e);
4073         } finally {
4074             mServiceLock.readLock().unlock();
4075         }
4076         return null;
4077     }
4078 
removeServiceStateCallback(IBluetoothManagerCallback cb)4079     void removeServiceStateCallback(IBluetoothManagerCallback cb) {
4080         requireNonNull(cb);
4081         sServiceLock.writeLock().lock();
4082         try {
4083             sProxyServiceStateCallbacks.remove(cb);
4084             registerOrUnregisterAdapterLocked();
4085         } finally {
4086             sServiceLock.writeLock().unlock();
4087         }
4088     }
4089 
4090     /**
4091      * Handle registering (or unregistering) a single process-wide {@link IBluetoothManagerCallback}
4092      * based on the presence of local {@link #sProxyServiceStateCallbacks} clients.
4093      */
4094     @GuardedBy("sServiceLock") // with write lock
registerOrUnregisterAdapterLocked()4095     private void registerOrUnregisterAdapterLocked() {
4096         final boolean isRegistered = sServiceRegistered;
4097         final boolean wantRegistered = !sProxyServiceStateCallbacks.isEmpty();
4098 
4099         if (isRegistered == wantRegistered) {
4100             return;
4101         }
4102         if (wantRegistered) {
4103             try {
4104                 sService =
4105                         IBluetooth.Stub.asInterface(
4106                                 mManagerService.registerAdapter(sManagerCallback));
4107             } catch (RemoteException e) {
4108                 throw e.rethrowFromSystemServer();
4109             }
4110         } else {
4111             try {
4112                 mManagerService.unregisterAdapter(sManagerCallback);
4113                 sService = null;
4114             } catch (RemoteException e) {
4115                 throw e.rethrowFromSystemServer();
4116             }
4117         }
4118         sServiceRegistered = wantRegistered;
4119     }
4120 
4121     /**
4122      * Callback interface used to deliver LE scan results.
4123      *
4124      * @see #startLeScan(LeScanCallback)
4125      * @see #startLeScan(UUID[], LeScanCallback)
4126      */
4127     public interface LeScanCallback {
4128         /**
4129          * Callback reporting an LE device found during a device scan initiated by the {@link
4130          * BluetoothAdapter#startLeScan} function.
4131          *
4132          * @param device Identifies the remote device
4133          * @param rssi The RSSI value for the remote device as reported by the Bluetooth hardware. 0
4134          *     if no RSSI value is available.
4135          * @param scanRecord The content of the advertisement record offered by the remote device.
4136          */
onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)4137         void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
4138     }
4139 
4140     /**
4141      * Starts a scan for Bluetooth LE devices.
4142      *
4143      * <p>Results of the scan are reported using the {@link LeScanCallback#onLeScan} callback.
4144      *
4145      * @param callback the callback LE scan results are delivered
4146      * @return true, if the scan was started successfully
4147      * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)}
4148      *     instead.
4149      */
4150     @Deprecated
4151     @RequiresLegacyBluetoothAdminPermission
4152     @RequiresBluetoothScanPermission
4153     @RequiresBluetoothLocationPermission
4154     @RequiresPermission(BLUETOOTH_SCAN)
startLeScan(LeScanCallback callback)4155     public boolean startLeScan(LeScanCallback callback) {
4156         return startLeScan(null, callback);
4157     }
4158 
4159     /**
4160      * Starts a scan for Bluetooth LE devices, looking for devices that advertise given services.
4161      *
4162      * <p>Devices which advertise all specified services are reported using the {@link
4163      * LeScanCallback#onLeScan} callback.
4164      *
4165      * @param serviceUuids Array of services to look for
4166      * @param callback the callback LE scan results are delivered
4167      * @return true, if the scan was started successfully
4168      * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)}
4169      *     instead.
4170      */
4171     @Deprecated
4172     @RequiresLegacyBluetoothAdminPermission
4173     @RequiresBluetoothScanPermission
4174     @RequiresBluetoothLocationPermission
4175     @RequiresPermission(BLUETOOTH_SCAN)
startLeScan(final UUID[] serviceUuids, final LeScanCallback callback)4176     public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {
4177         if (DBG) {
4178             Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids));
4179         }
4180         if (callback == null) {
4181             if (DBG) {
4182                 Log.e(TAG, "startLeScan: null callback");
4183             }
4184             return false;
4185         }
4186         BluetoothLeScanner scanner = getBluetoothLeScanner();
4187         if (scanner == null) {
4188             if (DBG) {
4189                 Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner");
4190             }
4191             return false;
4192         }
4193 
4194         synchronized (mLeScanClients) {
4195             if (mLeScanClients.containsKey(callback)) {
4196                 if (DBG) {
4197                     Log.e(TAG, "LE Scan has already started");
4198                 }
4199                 return false;
4200             }
4201 
4202             IBluetoothGatt iGatt = getBluetoothGatt();
4203             if (iGatt == null) {
4204                 // BLE is not supported
4205                 return false;
4206             }
4207 
4208             @SuppressLint("AndroidFrameworkBluetoothPermission")
4209             ScanCallback scanCallback =
4210                     new ScanCallback() {
4211                         @Override
4212                         public void onScanResult(int callbackType, ScanResult result) {
4213                             if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
4214                                 // Should not happen.
4215                                 Log.e(TAG, "LE Scan has already started");
4216                                 return;
4217                             }
4218                             ScanRecord scanRecord = result.getScanRecord();
4219                             if (scanRecord == null) {
4220                                 return;
4221                             }
4222                             if (serviceUuids != null) {
4223                                 List<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
4224                                 for (UUID uuid : serviceUuids) {
4225                                     uuids.add(new ParcelUuid(uuid));
4226                                 }
4227                                 List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids();
4228                                 if (scanServiceUuids == null
4229                                         || !scanServiceUuids.containsAll(uuids)) {
4230                                     if (DBG) {
4231                                         Log.d(TAG, "uuids does not match");
4232                                     }
4233                                     return;
4234                                 }
4235                             }
4236                             callback.onLeScan(
4237                                     result.getDevice(), result.getRssi(), scanRecord.getBytes());
4238                         }
4239                     };
4240             ScanSettings settings =
4241                     new ScanSettings.Builder()
4242                             .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
4243                             .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
4244                             .build();
4245 
4246             List<ScanFilter> filters = new ArrayList<ScanFilter>();
4247             if (serviceUuids != null && serviceUuids.length > 0) {
4248                 // Note scan filter does not support matching an UUID array so we put one
4249                 // UUID to hardware and match the whole array in callback.
4250                 ScanFilter filter =
4251                         new ScanFilter.Builder()
4252                                 .setServiceUuid(new ParcelUuid(serviceUuids[0]))
4253                                 .build();
4254                 filters.add(filter);
4255             }
4256             scanner.startScan(filters, settings, scanCallback);
4257 
4258             mLeScanClients.put(callback, scanCallback);
4259             return true;
4260         }
4261     }
4262 
4263     /**
4264      * Stops an ongoing Bluetooth LE device scan.
4265      *
4266      * @param callback used to identify which scan to stop must be the same handle used to start the
4267      *     scan
4268      * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead.
4269      */
4270     @Deprecated
4271     @RequiresLegacyBluetoothAdminPermission
4272     @RequiresBluetoothScanPermission
4273     @RequiresPermission(BLUETOOTH_SCAN)
stopLeScan(LeScanCallback callback)4274     public void stopLeScan(LeScanCallback callback) {
4275         if (DBG) {
4276             Log.d(TAG, "stopLeScan()");
4277         }
4278         BluetoothLeScanner scanner = getBluetoothLeScanner();
4279         if (scanner == null) {
4280             return;
4281         }
4282         synchronized (mLeScanClients) {
4283             ScanCallback scanCallback = mLeScanClients.remove(callback);
4284             if (scanCallback == null) {
4285                 if (DBG) {
4286                     Log.d(TAG, "scan not started yet");
4287                 }
4288                 return;
4289             }
4290             scanner.stopScan(scanCallback);
4291         }
4292     }
4293 
4294     /**
4295      * Create a secure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
4296      * assign a dynamic protocol/service multiplexer (PSM) value. This socket can be used to listen
4297      * for incoming connections. The supported Bluetooth transport is LE only.
4298      *
4299      * <p>A remote device connecting to this socket will be authenticated and communication on this
4300      * socket will be encrypted.
4301      *
4302      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
4303      * {@link BluetoothServerSocket}.
4304      *
4305      * <p>The system will assign a dynamic PSM value. This PSM value can be read from the {@link
4306      * BluetoothServerSocket#getPsm()} and this value will be released when this server socket is
4307      * closed, Bluetooth is turned off, or the application exits unexpectedly.
4308      *
4309      * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
4310      * defined and performed by the application.
4311      *
4312      * <p>Use {@link BluetoothDevice#createL2capChannel(int)} to connect to this server socket from
4313      * another Android device that is given the PSM value.
4314      *
4315      * @return an L2CAP CoC BluetoothServerSocket
4316      * @throws IOException on error, for example Bluetooth not available or unable to start this CoC
4317      */
4318     @RequiresLegacyBluetoothPermission
4319     @RequiresBluetoothConnectPermission
4320     @RequiresPermission(BLUETOOTH_CONNECT)
listenUsingL2capChannel()4321     public @NonNull BluetoothServerSocket listenUsingL2capChannel() throws IOException {
4322         BluetoothServerSocket socket =
4323                 new BluetoothServerSocket(
4324                         BluetoothSocket.TYPE_L2CAP_LE,
4325                         true,
4326                         true,
4327                         SOCKET_CHANNEL_AUTO_STATIC_NO_SDP,
4328                         false,
4329                         false);
4330         int errno = socket.mSocket.bindListen();
4331         if (errno != 0) {
4332             throw new IOException("Error: " + errno);
4333         }
4334 
4335         int assignedPsm = socket.mSocket.getPort();
4336         if (assignedPsm == 0) {
4337             throw new IOException("Error: Unable to assign PSM value");
4338         }
4339         if (DBG) {
4340             Log.d(TAG, "listenUsingL2capChannel: set assigned PSM to " + assignedPsm);
4341         }
4342         socket.setChannel(assignedPsm);
4343 
4344         return socket;
4345     }
4346 
4347     /**
4348      * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
4349      * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The
4350      * supported Bluetooth transport is LE only.
4351      *
4352      * <p>The link key is not required to be authenticated, i.e. the communication may be vulnerable
4353      * to person-in-the-middle attacks. Use {@link #listenUsingL2capChannel}, if an encrypted and
4354      * authenticated communication channel is desired.
4355      *
4356      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
4357      * {@link BluetoothServerSocket}.
4358      *
4359      * <p>The system will assign a dynamic protocol/service multiplexer (PSM) value. This PSM value
4360      * can be read from the {@link BluetoothServerSocket#getPsm()} and this value will be released
4361      * when this server socket is closed, Bluetooth is turned off, or the application exits
4362      * unexpectedly.
4363      *
4364      * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
4365      * defined and performed by the application.
4366      *
4367      * <p>Use {@link BluetoothDevice#createInsecureL2capChannel(int)} to connect to this server
4368      * socket from another Android device that is given the PSM value.
4369      *
4370      * @return an L2CAP CoC BluetoothServerSocket
4371      * @throws IOException on error, for example Bluetooth not available or unable to start this CoC
4372      */
4373     @RequiresLegacyBluetoothPermission
4374     @RequiresBluetoothConnectPermission
4375     @RequiresPermission(BLUETOOTH_CONNECT)
listenUsingInsecureL2capChannel()4376     public @NonNull BluetoothServerSocket listenUsingInsecureL2capChannel() throws IOException {
4377         BluetoothServerSocket socket =
4378                 new BluetoothServerSocket(
4379                         BluetoothSocket.TYPE_L2CAP_LE,
4380                         false,
4381                         false,
4382                         SOCKET_CHANNEL_AUTO_STATIC_NO_SDP,
4383                         false,
4384                         false);
4385         int errno = socket.mSocket.bindListen();
4386         if (errno != 0) {
4387             throw new IOException("Error: " + errno);
4388         }
4389 
4390         int assignedPsm = socket.mSocket.getPort();
4391         if (assignedPsm == 0) {
4392             throw new IOException("Error: Unable to assign PSM value");
4393         }
4394         if (DBG) {
4395             Log.d(TAG, "listenUsingInsecureL2capChannel: set assigned PSM to " + assignedPsm);
4396         }
4397         socket.setChannel(assignedPsm);
4398 
4399         return socket;
4400     }
4401 
4402     /**
4403      * Creates a listening server channel for Bluetooth connections with the specified socket
4404      * settings {@link BluetoothSocketSettings}.
4405      *
4406      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
4407      * {@link BluetoothServerSocket}.
4408      *
4409      * <p>Use {@link BluetoothDevice#createUsingSocketSettings(BluetoothSocketSettings)} to connect
4410      * to this server socket from another Android device using the L2cap protocol/service
4411      * multiplexer(PSM) value or the RFCOMM service UUID as input.
4412      *
4413      * <p>This API requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission
4414      * only when {@code settings.getDataPath()} is different from {@link
4415      * BluetoothSocketSettings#DATA_PATH_NO_OFFLOAD}.
4416      *
4417      * <p>This API supports {@link BluetoothSocket#TYPE_RFCOMM} and {{@link BluetoothSocket#TYPE_LE}
4418      * only, which can be set using {@link BluetoothSocketSettings#setSocketType()}.
4419      * <li>For `BluetoothSocket.TYPE_RFCOMM`: The RFCOMM UUID must be provided using {@link
4420      *     BluetoothSocketSettings#setRfcommUuid()}.
4421      * <li>For `BluetoothSocket.TYPE_LE`: The system assigns a dynamic protocol/service multiplexer
4422      *     (PSM) value. This value can be read from {@link BluetoothServerSocket#getPsm()}. This
4423      *     value is released when the server socket is closed, Bluetooth is turned off, or the
4424      *     application exits unexpectedly. The mechanism for disclosing the PSM value to the client
4425      *     is application-defined.
4426      *
4427      * @param settings Bluetooth socket settings {@link BluetoothSocketSettings}.
4428      * @return a {@link BluetoothServerSocket}
4429      * @throws IllegalArgumentException if BluetoothSocket#TYPE_RFCOMM socket is requested with no
4430      *     UUID.
4431      * @throws IOException on error, for example Bluetooth not available or unable to start this LE
4432      *     Connection-oriented Channel (CoC).
4433      */
4434     @RequiresBluetoothConnectPermission
4435     @RequiresPermission(
4436             allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
4437             conditional = true)
4438     @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
listenUsingSocketSettings( @onNull BluetoothSocketSettings settings)4439     public @NonNull BluetoothServerSocket listenUsingSocketSettings(
4440             @NonNull BluetoothSocketSettings settings) throws IOException {
4441 
4442         BluetoothServerSocket socket;
4443         int type = settings.getSocketType();
4444         if (type == BluetoothSocket.TYPE_RFCOMM) {
4445             if (settings.getRfcommUuid() == null) {
4446                 throw new IllegalArgumentException("RFCOMM server missing UUID");
4447             }
4448             if (settings.getDataPath() == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
4449                 socket =
4450                         new BluetoothServerSocket(
4451                                 settings.getSocketType(),
4452                                 settings.isAuthenticationRequired(),
4453                                 settings.isEncryptionRequired(),
4454                                 new ParcelUuid(settings.getRfcommUuid()));
4455             } else {
4456                 socket =
4457                         new BluetoothServerSocket(
4458                                 settings.getSocketType(),
4459                                 settings.isAuthenticationRequired(),
4460                                 settings.isEncryptionRequired(),
4461                                 -1,
4462                                 new ParcelUuid(settings.getRfcommUuid()),
4463                                 false,
4464                                 false,
4465                                 settings.getDataPath(),
4466                                 settings.getSocketName(),
4467                                 settings.getHubId(),
4468                                 settings.getEndpointId(),
4469                                 settings.getRequestedMaximumPacketSize());
4470             }
4471             socket.setServiceName(settings.getRfcommServiceName());
4472         } else if (type == BluetoothSocket.TYPE_LE) {
4473             if (settings.getDataPath() == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD) {
4474                 socket =
4475                         new BluetoothServerSocket(
4476                                 settings.getSocketType(),
4477                                 settings.isAuthenticationRequired(),
4478                                 settings.isEncryptionRequired(),
4479                                 SOCKET_CHANNEL_AUTO_STATIC_NO_SDP,
4480                                 false,
4481                                 false);
4482             } else {
4483                 socket =
4484                         new BluetoothServerSocket(
4485                                 settings.getSocketType(),
4486                                 settings.isAuthenticationRequired(),
4487                                 settings.isEncryptionRequired(),
4488                                 SOCKET_CHANNEL_AUTO_STATIC_NO_SDP,
4489                                 null,
4490                                 false,
4491                                 false,
4492                                 settings.getDataPath(),
4493                                 settings.getSocketName(),
4494                                 settings.getHubId(),
4495                                 settings.getEndpointId(),
4496                                 settings.getRequestedMaximumPacketSize());
4497             }
4498         } else {
4499             throw new IllegalArgumentException("Error: Invalid socket type: " + type);
4500         }
4501         int errno;
4502         errno =
4503                 (settings.getDataPath() == BluetoothSocketSettings.DATA_PATH_NO_OFFLOAD)
4504                         ? socket.mSocket.bindListen()
4505                         : socket.mSocket.bindListenWithOffload();
4506         if (errno != 0) {
4507             throw new IOException("Error: " + errno);
4508         }
4509         if (type == BluetoothSocket.TYPE_LE) {
4510             int assignedPsm = socket.mSocket.getPort();
4511             if (assignedPsm == 0) {
4512                 throw new IOException("Error: Unable to assign PSM value");
4513             }
4514             if (DBG) {
4515                 Log.d(TAG, "listenUsingSocketSettings: set assigned PSM to " + assignedPsm);
4516             }
4517             socket.setChannel(assignedPsm);
4518         }
4519 
4520         return socket;
4521     }
4522 
4523     /**
4524      * Register a {@link OnMetadataChangedListener} to receive update about metadata changes for
4525      * this {@link BluetoothDevice}. Registration must be done when Bluetooth is ON and will last
4526      * until {@link #removeOnMetadataChangedListener} is called, even when Bluetooth restarted in
4527      * the middle. All input parameters should not be null or {@link NullPointerException} will be
4528      * triggered. The same {@link BluetoothDevice} and {@link OnMetadataChangedListener} pair can
4529      * only be registered once, double registration would cause {@link IllegalArgumentException}.
4530      *
4531      * @param device {@link BluetoothDevice} that will be registered
4532      * @param executor the executor for listener callback
4533      * @param listener {@link OnMetadataChangedListener} that will receive asynchronous callbacks
4534      * @return true on success, false on error
4535      * @throws NullPointerException If one of {@code listener}, {@code device} or {@code executor}
4536      *     is null.
4537      * @throws IllegalArgumentException The same {@link OnMetadataChangedListener} and {@link
4538      *     BluetoothDevice} are registered twice.
4539      * @hide
4540      */
4541     @SystemApi
4542     @RequiresBluetoothConnectPermission
4543     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
addOnMetadataChangedListener( @onNull BluetoothDevice device, @NonNull Executor executor, @NonNull OnMetadataChangedListener listener)4544     public boolean addOnMetadataChangedListener(
4545             @NonNull BluetoothDevice device,
4546             @NonNull Executor executor,
4547             @NonNull OnMetadataChangedListener listener) {
4548         if (DBG) Log.d(TAG, "addOnMetadataChangedListener(" + device + ", " + listener + ")");
4549         requireNonNull(device);
4550         requireNonNull(executor);
4551         requireNonNull(listener);
4552 
4553         mServiceLock.readLock().lock();
4554         try {
4555             if (mService == null) {
4556                 Log.e(TAG, "Bluetooth is not enabled. Cannot register metadata listener");
4557                 return false;
4558             }
4559 
4560             synchronized (mMetadataListeners) {
4561                 List<Pair<OnMetadataChangedListener, Executor>> listenerList =
4562                         mMetadataListeners.get(device);
4563                 if (listenerList == null) {
4564                     // Create new listener/executor list for registration
4565                     listenerList = new ArrayList<>();
4566                     mMetadataListeners.put(device, listenerList);
4567                 } else {
4568                     // Check whether this device is already registered by the listener
4569                     if (listenerList.stream().anyMatch((pair) -> (pair.first.equals(listener)))) {
4570                         throw new IllegalArgumentException(
4571                                 "listener already registered for " + device);
4572                     }
4573                 }
4574 
4575                 Pair<OnMetadataChangedListener, Executor> listenerPair =
4576                         new Pair(listener, executor);
4577                 listenerList.add(listenerPair);
4578 
4579                 boolean ret = false;
4580                 try {
4581                     ret =
4582                             mService.registerMetadataListener(
4583                                     mBluetoothMetadataListener, device, mAttributionSource);
4584                 } catch (RemoteException e) {
4585                     logRemoteException(TAG, e);
4586                 } finally {
4587                     if (!ret) {
4588                         // Remove listener registered earlier when fail.
4589                         listenerList.remove(listenerPair);
4590                         if (listenerList.isEmpty()) {
4591                             // Remove the device if its listener list is empty
4592                             mMetadataListeners.remove(device);
4593                         }
4594                     }
4595                 }
4596                 return ret;
4597             }
4598         } finally {
4599             mServiceLock.readLock().unlock();
4600         }
4601     }
4602 
4603     /**
4604      * Unregister a {@link OnMetadataChangedListener} from a registered {@link BluetoothDevice}.
4605      * Unregistration can be done when Bluetooth is either ON or OFF. {@link
4606      * #addOnMetadataChangedListener} must be called before unregistration.
4607      *
4608      * @param device {@link BluetoothDevice} that will be unregistered. It should not be null or
4609      *     {@link NullPointerException} will be triggered.
4610      * @param listener {@link OnMetadataChangedListener} that will be unregistered. It should not be
4611      *     null or {@link NullPointerException} will be triggered.
4612      * @return true on success, false on error
4613      * @throws NullPointerException If {@code listener} or {@code device} is null.
4614      * @throws IllegalArgumentException If {@code device} has not been registered before.
4615      * @hide
4616      */
4617     @SystemApi
4618     @RequiresBluetoothConnectPermission
4619     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
removeOnMetadataChangedListener( @onNull BluetoothDevice device, @NonNull OnMetadataChangedListener listener)4620     public boolean removeOnMetadataChangedListener(
4621             @NonNull BluetoothDevice device, @NonNull OnMetadataChangedListener listener) {
4622         if (DBG) Log.d(TAG, "removeOnMetadataChangedListener(" + device + ", " + listener + ")");
4623         requireNonNull(device);
4624         requireNonNull(listener);
4625 
4626         synchronized (mMetadataListeners) {
4627             if (!mMetadataListeners.containsKey(device)) {
4628                 throw new IllegalArgumentException("device was not registered");
4629             }
4630             // Remove issued listener from the registered device
4631             mMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener)));
4632 
4633             if (mMetadataListeners.get(device).isEmpty()) {
4634                 // Unregister to Bluetooth service if all listeners are removed from
4635                 // the registered device
4636                 mMetadataListeners.remove(device);
4637                 mServiceLock.readLock().lock();
4638                 try {
4639                     if (mService != null) {
4640                         return mService.unregisterMetadataListener(
4641                                 mBluetoothMetadataListener, device, mAttributionSource);
4642                     }
4643                 } catch (RemoteException e) {
4644                     logRemoteException(TAG, e);
4645                     return false;
4646                 } finally {
4647                     mServiceLock.readLock().unlock();
4648                 }
4649             }
4650         }
4651         return true;
4652     }
4653 
4654     /**
4655      * This interface is used to implement {@link BluetoothAdapter} metadata listener.
4656      *
4657      * @hide
4658      */
4659     @SystemApi
4660     public interface OnMetadataChangedListener {
4661         /**
4662          * Callback triggered if the metadata of {@link BluetoothDevice} registered in {@link
4663          * #addOnMetadataChangedListener}.
4664          *
4665          * @param device changed {@link BluetoothDevice}.
4666          * @param key changed metadata key, one of BluetoothDevice.METADATA_*.
4667          * @param value the new value of metadata as byte array.
4668          */
onMetadataChanged(@onNull BluetoothDevice device, int key, @Nullable byte[] value)4669         void onMetadataChanged(@NonNull BluetoothDevice device, int key, @Nullable byte[] value);
4670     }
4671 
4672     private final CallbackWrapper<BluetoothConnectionCallback, IBluetooth>
4673             mBluetoothConnectionCallbackWrapper;
4674 
4675     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
registerBluetoothConnectionCallbackFn(IBluetooth service)4676     private void registerBluetoothConnectionCallbackFn(IBluetooth service) {
4677         try {
4678             service.registerBluetoothConnectionCallback(
4679                     mBluetoothConnectionCallback, mAttributionSource);
4680         } catch (RemoteException e) {
4681             logRemoteException(TAG, e);
4682         }
4683     }
4684 
4685     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
unregisterBluetoothConnectionCallbackFn(IBluetooth service)4686     private void unregisterBluetoothConnectionCallbackFn(IBluetooth service) {
4687         try {
4688             service.unregisterBluetoothConnectionCallback(
4689                     mBluetoothConnectionCallback, mAttributionSource);
4690         } catch (RemoteException e) {
4691             logRemoteException(TAG, e);
4692         }
4693     }
4694 
4695     private final IBluetoothConnectionCallback mBluetoothConnectionCallback =
4696             new IBluetoothConnectionCallback.Stub() {
4697                 @Override
4698                 @RequiresNoPermission
4699                 public void onDeviceConnected(BluetoothDevice device) {
4700                     Attributable.setAttributionSource(device, mAttributionSource);
4701                     mBluetoothConnectionCallbackWrapper.forEach(
4702                             (cb) -> cb.onDeviceConnected(device));
4703                 }
4704 
4705                 @Override
4706                 @RequiresNoPermission
4707                 public void onDeviceDisconnected(BluetoothDevice device, int hciReason) {
4708                     Attributable.setAttributionSource(device, mAttributionSource);
4709                     mBluetoothConnectionCallbackWrapper.forEach(
4710                             (cb) -> cb.onDeviceDisconnected(device, hciReason));
4711                 }
4712             };
4713 
4714     /**
4715      * Registers the BluetoothConnectionCallback to receive callback events when a bluetooth device
4716      * (classic or low energy) is connected or disconnected.
4717      *
4718      * @param executor is the callback executor
4719      * @param callback is the connection callback you wish to register
4720      * @return true if the callback was registered successfully, false otherwise
4721      * @throws IllegalArgumentException if the callback is already registered
4722      * @hide
4723      */
4724     @SystemApi
4725     @RequiresBluetoothConnectPermission
4726     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
registerBluetoothConnectionCallback( @onNull @allbackExecutor Executor executor, @NonNull BluetoothConnectionCallback callback)4727     public boolean registerBluetoothConnectionCallback(
4728             @NonNull @CallbackExecutor Executor executor,
4729             @NonNull BluetoothConnectionCallback callback) {
4730         if (DBG) Log.d(TAG, "registerBluetoothConnectionCallback()");
4731 
4732         mServiceLock.readLock().lock();
4733         try {
4734             mBluetoothConnectionCallbackWrapper.registerCallback(mService, callback, executor);
4735         } finally {
4736             mServiceLock.readLock().unlock();
4737         }
4738 
4739         return true;
4740     }
4741 
4742     /**
4743      * Unregisters the BluetoothConnectionCallback that was previously registered by the application
4744      *
4745      * @param callback is the connection callback you wish to unregister
4746      * @return true if the callback was unregistered successfully, false otherwise
4747      * @hide
4748      */
4749     @SystemApi
4750     @RequiresBluetoothConnectPermission
4751     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
unregisterBluetoothConnectionCallback( @onNull BluetoothConnectionCallback callback)4752     public boolean unregisterBluetoothConnectionCallback(
4753             @NonNull BluetoothConnectionCallback callback) {
4754         if (DBG) Log.d(TAG, "unregisterBluetoothConnectionCallback()");
4755         mServiceLock.readLock().lock();
4756         try {
4757             mBluetoothConnectionCallbackWrapper.unregisterCallback(mService, callback);
4758         } finally {
4759             mServiceLock.readLock().unlock();
4760         }
4761         return true;
4762     }
4763 
4764     /**
4765      * This abstract class is used to implement callbacks for when a bluetooth classic or Bluetooth
4766      * Low Energy (BLE) device is either connected or disconnected.
4767      *
4768      * @hide
4769      */
4770     @SystemApi
4771     public abstract static class BluetoothConnectionCallback {
4772         /**
4773          * Callback triggered when a bluetooth device (classic or BLE) is connected
4774          *
4775          * @param device is the connected bluetooth device
4776          */
onDeviceConnected(@onNull BluetoothDevice device)4777         public void onDeviceConnected(@NonNull BluetoothDevice device) {}
4778 
4779         /**
4780          * Callback triggered when a bluetooth device (classic or BLE) is disconnected
4781          *
4782          * @param device is the disconnected bluetooth device
4783          * @param reason is the disconnect reason
4784          */
onDeviceDisconnected( @onNull BluetoothDevice device, @DisconnectReason int reason)4785         public void onDeviceDisconnected(
4786                 @NonNull BluetoothDevice device, @DisconnectReason int reason) {}
4787 
4788         /** @hide */
4789         @Retention(RetentionPolicy.SOURCE)
4790         @IntDef(
4791                 prefix = {"REASON_"},
4792                 value = {
4793                     BluetoothStatusCodes.ERROR_UNKNOWN,
4794                     BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST,
4795                     BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE_REQUEST,
4796                     BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL,
4797                     BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE,
4798                     BluetoothStatusCodes.ERROR_DISCONNECT_REASON_TIMEOUT,
4799                     BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SECURITY,
4800                     BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SYSTEM_POLICY,
4801                     BluetoothStatusCodes.ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED,
4802                     BluetoothStatusCodes.ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS,
4803                     BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS
4804                 })
4805         public @interface DisconnectReason {}
4806 
4807         /** Returns human-readable strings corresponding to {@link DisconnectReason}. */
4808         @NonNull
disconnectReasonToString(@isconnectReason int reason)4809         public static String disconnectReasonToString(@DisconnectReason int reason) {
4810             switch (reason) {
4811                 case BluetoothStatusCodes.ERROR_UNKNOWN:
4812                     return "Reason unknown";
4813                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST:
4814                     return "Local request";
4815                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE_REQUEST:
4816                     return "Remote request";
4817                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL:
4818                     return "Local error";
4819                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE:
4820                     return "Remote error";
4821                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_TIMEOUT:
4822                     return "Timeout";
4823                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SECURITY:
4824                     return "Security";
4825                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SYSTEM_POLICY:
4826                     return "System policy";
4827                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED:
4828                     return "Resource constrained";
4829                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS:
4830                     return "Connection already exists";
4831                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS:
4832                     return "Bad parameters";
4833                 default:
4834                     return "Unrecognized disconnect reason: " + reason;
4835             }
4836         }
4837     }
4838 
4839     /** @hide */
4840     @Retention(RetentionPolicy.SOURCE)
4841     @IntDef(
4842             value = {
4843                 BluetoothStatusCodes.SUCCESS,
4844                 BluetoothStatusCodes.ERROR_ANOTHER_ACTIVE_REQUEST,
4845                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
4846                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
4847                 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED,
4848                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
4849                 BluetoothStatusCodes.ERROR_NOT_DUAL_MODE_AUDIO_DEVICE,
4850                 BluetoothStatusCodes.ERROR_UNKNOWN,
4851                 BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
4852             })
4853     public @interface SetPreferredAudioProfilesReturnValues {}
4854 
4855     /**
4856      * Sets the preferred profiles for each audio mode for system routed audio. The audio framework
4857      * and Telecom will read this preference when routing system managed audio. Not supplying an
4858      * audio mode in the Bundle will reset that audio mode to the default profile preference for
4859      * that mode (e.g. an empty Bundle resets all audio modes to their default profiles).
4860      *
4861      * <p>Note: apps that invoke profile-specific audio APIs are not subject to the preference noted
4862      * here. These preferences will also be ignored if the remote device is not simultaneously
4863      * connected to a classic audio profile (A2DP and/or HFP) and LE Audio at the same time. If the
4864      * remote device does not support both BR/EDR audio and LE Audio, this API returns {@link
4865      * BluetoothStatusCodes#ERROR_NOT_DUAL_MODE_AUDIO_DEVICE}. If the system property
4866      * persist.bluetooth.enable_dual_mode_audio is set to {@code false}, this API returns {@link
4867      * BluetoothStatusCodes#FEATURE_NOT_SUPPORTED}.
4868      *
4869      * <p>The Bundle is expected to contain the following mappings: 1. For key {@link
4870      * #AUDIO_MODE_OUTPUT_ONLY}, it expects an integer value of either {@link BluetoothProfile#A2DP}
4871      * or {@link BluetoothProfile#LE_AUDIO}. 2. For key {@link #AUDIO_MODE_DUPLEX}, it expects an
4872      * integer value of either {@link BluetoothProfile#HEADSET} or {@link
4873      * BluetoothProfile#LE_AUDIO}.
4874      *
4875      * <p>Apps should register for a callback with {@link
4876      * #registerPreferredAudioProfilesChangedCallback(Executor,
4877      * PreferredAudioProfilesChangedCallback)} to know if the preferences were successfully applied
4878      * to the audio framework. If there is an active preference change for this device that has not
4879      * taken effect with the audio framework, no additional calls to this API will be allowed until
4880      * that completes.
4881      *
4882      * @param modeToProfileBundle a mapping to indicate the preferred profile for each audio mode
4883      * @return whether the preferred audio profiles were requested to be set
4884      * @throws NullPointerException if modeToProfileBundle or device is null
4885      * @throws IllegalArgumentException if this BluetoothDevice object has an invalid address or the
4886      *     Bundle doesn't conform to its requirements
4887      * @hide
4888      */
4889     @SystemApi
4890     @RequiresBluetoothConnectPermission
4891     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
4892     @SetPreferredAudioProfilesReturnValues
setPreferredAudioProfiles( @onNull BluetoothDevice device, @NonNull Bundle modeToProfileBundle)4893     public int setPreferredAudioProfiles(
4894             @NonNull BluetoothDevice device, @NonNull Bundle modeToProfileBundle) {
4895         if (DBG) {
4896             Log.d(TAG, "setPreferredAudioProfiles( " + modeToProfileBundle + ", " + device + ")");
4897         }
4898         requireNonNull(modeToProfileBundle);
4899         requireNonNull(device);
4900         if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
4901             throw new IllegalArgumentException("device cannot have an invalid address");
4902         }
4903         if (!modeToProfileBundle.containsKey(AUDIO_MODE_OUTPUT_ONLY)
4904                 && !modeToProfileBundle.containsKey(AUDIO_MODE_DUPLEX)) {
4905             throw new IllegalArgumentException(
4906                     "Bundle does not contain a key AUDIO_MODE_OUTPUT_ONLY or AUDIO_MODE_DUPLEX");
4907         }
4908         if (modeToProfileBundle.containsKey(AUDIO_MODE_OUTPUT_ONLY)
4909                 && modeToProfileBundle.getInt(AUDIO_MODE_OUTPUT_ONLY) != BluetoothProfile.A2DP
4910                 && modeToProfileBundle.getInt(AUDIO_MODE_OUTPUT_ONLY)
4911                         != BluetoothProfile.LE_AUDIO) {
4912             throw new IllegalArgumentException(
4913                     "Key AUDIO_MODE_OUTPUT_ONLY has an invalid value: "
4914                             + modeToProfileBundle.getInt(AUDIO_MODE_OUTPUT_ONLY));
4915         }
4916         if (modeToProfileBundle.containsKey(AUDIO_MODE_DUPLEX)
4917                 && modeToProfileBundle.getInt(AUDIO_MODE_DUPLEX) != BluetoothProfile.HEADSET
4918                 && modeToProfileBundle.getInt(AUDIO_MODE_DUPLEX) != BluetoothProfile.LE_AUDIO) {
4919             throw new IllegalArgumentException(
4920                     "Key AUDIO_MODE_DUPLEX has an invalid value: "
4921                             + modeToProfileBundle.getInt(AUDIO_MODE_DUPLEX));
4922         }
4923 
4924         mServiceLock.readLock().lock();
4925         try {
4926             if (mService != null) {
4927                 return mService.setPreferredAudioProfiles(
4928                         device, modeToProfileBundle, mAttributionSource);
4929             }
4930         } catch (RemoteException e) {
4931             logRemoteException(TAG, e);
4932         } finally {
4933             mServiceLock.readLock().unlock();
4934         }
4935         return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
4936     }
4937 
4938     /**
4939      * Gets the preferred profile for each audio mode for system routed audio. This API returns a
4940      * Bundle with mappings between each audio mode and its preferred audio profile. If no values
4941      * are set via {@link #setPreferredAudioProfiles(BluetoothDevice, Bundle)}, this API returns the
4942      * default system preferences set via the sysprops {@link
4943      * BluetoothProperties#getDefaultOutputOnlyAudioProfile()} and {@link
4944      * BluetoothProperties#getDefaultDuplexAudioProfile()}.
4945      *
4946      * <p>An audio capable device must support at least one audio mode with a preferred audio
4947      * profile. If a device does not support an audio mode, the audio mode will be omitted from the
4948      * keys of the Bundle. If the device is not recognized as a dual mode audio capable device (e.g.
4949      * because it is not bonded, does not support any audio profiles, or does not support both
4950      * BR/EDR audio and LE Audio), this API returns an empty Bundle. If the system property
4951      * persist.bluetooth.enable_dual_mode_audio is set to {@code false}, this API returns an empty
4952      * Bundle.
4953      *
4954      * <p>The Bundle can contain the following mappings:
4955      *
4956      * <ul>
4957      *   <li>For key {@link #AUDIO_MODE_OUTPUT_ONLY}, if an audio profile preference was set, this
4958      *       will have an int value of either {@link BluetoothProfile#A2DP} or {@link
4959      *       BluetoothProfile#LE_AUDIO}.
4960      *   <li>For key {@link #AUDIO_MODE_DUPLEX}, if an audio profile preference was set, this will
4961      *       have an int value of either {@link BluetoothProfile#HEADSET} or {@link
4962      *       BluetoothProfile#LE_AUDIO}.
4963      * </ul>
4964      *
4965      * @return a Bundle mapping each set audio mode and preferred audio profile pair
4966      * @throws NullPointerException if modeToProfileBundle or device is null
4967      * @throws IllegalArgumentException if this BluetoothDevice object has an invalid address or the
4968      *     Bundle doesn't conform to its requirements
4969      * @hide
4970      */
4971     @SystemApi
4972     @RequiresBluetoothConnectPermission
4973     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
getPreferredAudioProfiles(@onNull BluetoothDevice device)4974     public @NonNull Bundle getPreferredAudioProfiles(@NonNull BluetoothDevice device) {
4975         if (DBG) Log.d(TAG, "getPreferredAudioProfiles(" + device + ")");
4976         requireNonNull(device);
4977         if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
4978             throw new IllegalArgumentException("device cannot have an invalid address");
4979         }
4980 
4981         mServiceLock.readLock().lock();
4982         try {
4983             if (mService != null) {
4984                 return mService.getPreferredAudioProfiles(device, mAttributionSource);
4985             }
4986         } catch (RemoteException e) {
4987             logRemoteException(TAG, e);
4988         } finally {
4989             mServiceLock.readLock().unlock();
4990         }
4991 
4992         return Bundle.EMPTY;
4993     }
4994 
4995     /** @hide */
4996     @Retention(RetentionPolicy.SOURCE)
4997     @IntDef(
4998             value = {
4999                 BluetoothStatusCodes.SUCCESS,
5000                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
5001                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
5002                 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED,
5003                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
5004                 BluetoothStatusCodes.ERROR_UNKNOWN
5005             })
5006     public @interface NotifyActiveDeviceChangeAppliedReturnValues {}
5007 
5008     /**
5009      * Called by audio framework to inform the Bluetooth stack that an active device change has
5010      * taken effect. If this active device change is triggered by an app calling {@link
5011      * #setPreferredAudioProfiles(BluetoothDevice, Bundle)}, the Bluetooth stack will invoke {@link
5012      * PreferredAudioProfilesChangedCallback#onPreferredAudioProfilesChanged( BluetoothDevice,
5013      * Bundle, int)} if all requested changes for the device have been applied.
5014      *
5015      * <p>This method will return {@link BluetoothStatusCodes#ERROR_BLUETOOTH_NOT_ALLOWED} if called
5016      * outside system server.
5017      *
5018      * @param device is the BluetoothDevice that had its preferred audio profile changed
5019      * @return whether the Bluetooth stack acknowledged the change successfully
5020      * @throws NullPointerException if device is null
5021      * @throws IllegalArgumentException if the device's address is invalid
5022      * @hide
5023      */
5024     @SystemApi
5025     @RequiresBluetoothConnectPermission
5026     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
5027     @NotifyActiveDeviceChangeAppliedReturnValues
notifyActiveDeviceChangeApplied(@onNull BluetoothDevice device)5028     public int notifyActiveDeviceChangeApplied(@NonNull BluetoothDevice device) {
5029         if (DBG) Log.d(TAG, "notifyActiveDeviceChangeApplied(" + device + ")");
5030         requireNonNull(device);
5031         if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
5032             throw new IllegalArgumentException("device cannot have an invalid address");
5033         }
5034 
5035         mServiceLock.readLock().lock();
5036         try {
5037             if (mService != null) {
5038                 return mService.notifyActiveDeviceChangeApplied(device, mAttributionSource);
5039             }
5040         } catch (RemoteException e) {
5041             logRemoteException(TAG, e);
5042         } finally {
5043             mServiceLock.readLock().unlock();
5044         }
5045 
5046         return BluetoothStatusCodes.ERROR_UNKNOWN;
5047     }
5048 
5049     private final CallbackWrapper<PreferredAudioProfilesChangedCallback, IBluetooth>
5050             mAudioProfilesCallbackWrapper;
5051 
5052     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
registerAudioProfilesCallbackFn(IBluetooth service)5053     private void registerAudioProfilesCallbackFn(IBluetooth service) {
5054         try {
5055             service.registerPreferredAudioProfilesChangedCallback(
5056                     mPreferredAudioProfilesChangedCallback, mAttributionSource);
5057         } catch (RemoteException e) {
5058             logRemoteException(TAG, e);
5059         }
5060     }
5061 
5062     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
unregisterAudioProfilesCallbackFn(IBluetooth service)5063     private void unregisterAudioProfilesCallbackFn(IBluetooth service) {
5064         try {
5065             service.unregisterPreferredAudioProfilesChangedCallback(
5066                     mPreferredAudioProfilesChangedCallback, mAttributionSource);
5067         } catch (RemoteException e) {
5068             logRemoteException(TAG, e);
5069         }
5070     }
5071 
5072     private final IBluetoothPreferredAudioProfilesCallback mPreferredAudioProfilesChangedCallback =
5073             new IBluetoothPreferredAudioProfilesCallback.Stub() {
5074                 @Override
5075                 @RequiresNoPermission
5076                 public void onPreferredAudioProfilesChanged(
5077                         BluetoothDevice device, Bundle preferredAudioProfiles, int status) {
5078                     mAudioProfilesCallbackWrapper.forEach(
5079                             (cb) ->
5080                                     cb.onPreferredAudioProfilesChanged(
5081                                             device, preferredAudioProfiles, status));
5082                 }
5083             };
5084 
5085     /** @hide */
5086     @Retention(RetentionPolicy.SOURCE)
5087     @IntDef(
5088             value = {
5089                 BluetoothStatusCodes.SUCCESS,
5090                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
5091                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
5092                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
5093                 BluetoothStatusCodes.ERROR_UNKNOWN,
5094                 BluetoothStatusCodes.FEATURE_NOT_SUPPORTED
5095             })
5096     public @interface RegisterPreferredAudioProfilesCallbackReturnValues {}
5097 
5098     /**
5099      * Registers a callback to be notified when the preferred audio profile changes have taken
5100      * effect. To unregister this callback, call {@link
5101      * #unregisterPreferredAudioProfilesChangedCallback( PreferredAudioProfilesChangedCallback)}. If
5102      * the system property persist.bluetooth.enable_dual_mode_audio is set to {@code false}, this
5103      * API returns {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED}.
5104      *
5105      * @param executor an {@link Executor} to execute the callbacks
5106      * @param callback user implementation of the {@link PreferredAudioProfilesChangedCallback}
5107      * @return whether the callback was registered successfully
5108      * @throws NullPointerException if executor or callback is null
5109      * @throws IllegalArgumentException if the callback is already registered
5110      * @hide
5111      */
5112     @SystemApi
5113     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
5114     @RegisterPreferredAudioProfilesCallbackReturnValues
registerPreferredAudioProfilesChangedCallback( @onNull @allbackExecutor Executor executor, @NonNull PreferredAudioProfilesChangedCallback callback)5115     public int registerPreferredAudioProfilesChangedCallback(
5116             @NonNull @CallbackExecutor Executor executor,
5117             @NonNull PreferredAudioProfilesChangedCallback callback) {
5118         if (DBG) Log.d(TAG, "registerPreferredAudioProfilesChangedCallback()");
5119         requireNonNull(callback);
5120         requireNonNull(executor);
5121 
5122         mServiceLock.readLock().lock();
5123         try {
5124             int status = mService.isDualModeAudioEnabled(mAttributionSource);
5125             if (status != BluetoothStatusCodes.SUCCESS) {
5126                 return status;
5127             }
5128             mAudioProfilesCallbackWrapper.registerCallback(mService, callback, executor);
5129         } catch (RemoteException e) {
5130             logRemoteException(TAG, e);
5131         } finally {
5132             mServiceLock.readLock().unlock();
5133         }
5134 
5135         return BluetoothStatusCodes.SUCCESS;
5136     }
5137 
5138     /** @hide */
5139     @Retention(RetentionPolicy.SOURCE)
5140     @IntDef(
5141             value = {
5142                 BluetoothStatusCodes.SUCCESS,
5143                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
5144                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
5145                 BluetoothStatusCodes.ERROR_CALLBACK_NOT_REGISTERED,
5146                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
5147                 BluetoothStatusCodes.ERROR_UNKNOWN,
5148                 BluetoothStatusCodes.FEATURE_NOT_SUPPORTED
5149             })
5150     public @interface UnRegisterPreferredAudioProfilesCallbackReturnValues {}
5151 
5152     /**
5153      * Unregisters a callback that was previously registered with {@link
5154      * #registerPreferredAudioProfilesChangedCallback(Executor,
5155      * PreferredAudioProfilesChangedCallback)}.
5156      *
5157      * @param callback user implementation of the {@link PreferredAudioProfilesChangedCallback}
5158      * @return whether the callback was successfully unregistered
5159      * @throws NullPointerException if the callback is null
5160      * @throws IllegalArgumentException if the callback has not been registered
5161      * @hide
5162      */
5163     @SystemApi
5164     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
5165     @UnRegisterPreferredAudioProfilesCallbackReturnValues
unregisterPreferredAudioProfilesChangedCallback( @onNull PreferredAudioProfilesChangedCallback callback)5166     public int unregisterPreferredAudioProfilesChangedCallback(
5167             @NonNull PreferredAudioProfilesChangedCallback callback) {
5168         if (DBG) Log.d(TAG, "unregisterPreferredAudioProfilesChangedCallback()");
5169 
5170         mServiceLock.readLock().lock();
5171         try {
5172             mAudioProfilesCallbackWrapper.unregisterCallback(mService, callback);
5173         } finally {
5174             mServiceLock.readLock().unlock();
5175         }
5176 
5177         return BluetoothStatusCodes.SUCCESS;
5178     }
5179 
5180     /**
5181      * A callback for preferred audio profile changes that arise from calls to {@link
5182      * #setPreferredAudioProfiles(BluetoothDevice, Bundle)}.
5183      *
5184      * @hide
5185      */
5186     @SystemApi
5187     public interface PreferredAudioProfilesChangedCallback {
5188         /**
5189          * Called when the preferred audio profile change from a call to {@link
5190          * #setPreferredAudioProfiles(BluetoothDevice, Bundle)} has taken effect in the audio
5191          * framework or timed out. This callback includes a Bundle that indicates the current
5192          * preferred audio profile for each audio mode, if one was set. If an audio mode does not
5193          * have a profile preference, its key will be omitted from the Bundle. If both audio modes
5194          * do not have a preferred profile set, the Bundle will be empty.
5195          *
5196          * <p>The Bundle can contain the following mappings:
5197          *
5198          * <ul>
5199          *   <li>For key {@link #AUDIO_MODE_OUTPUT_ONLY}, if an audio profile preference was set,
5200          *       this will have an int value of either {@link BluetoothProfile#A2DP} or {@link
5201          *       BluetoothProfile#LE_AUDIO}.
5202          *   <li>For key {@link #AUDIO_MODE_DUPLEX}, if an audio profile preference was set, this
5203          *       will have an int value of either {@link BluetoothProfile#HEADSET} or {@link
5204          *       BluetoothProfile#LE_AUDIO}.
5205          * </ul>
5206          *
5207          * @param device is the device which had its preferred audio profiles changed
5208          * @param preferredAudioProfiles a Bundle mapping audio mode to its preferred audio profile
5209          * @param status whether the operation succeeded or timed out
5210          * @hide
5211          */
5212         @SystemApi
onPreferredAudioProfilesChanged( @onNull BluetoothDevice device, @NonNull Bundle preferredAudioProfiles, int status)5213         void onPreferredAudioProfilesChanged(
5214                 @NonNull BluetoothDevice device,
5215                 @NonNull Bundle preferredAudioProfiles,
5216                 int status);
5217     }
5218 
5219     private final CallbackWrapper<BluetoothQualityReportReadyCallback, IBluetooth>
5220             mQualityCallbackWrapper;
5221 
5222     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
registerBluetoothQualityReportCallbackFn(IBluetooth service)5223     private void registerBluetoothQualityReportCallbackFn(IBluetooth service) {
5224         try {
5225             service.registerBluetoothQualityReportReadyCallback(
5226                     mBluetoothQualityReportReadyCallback, mAttributionSource);
5227         } catch (RemoteException e) {
5228             logRemoteException(TAG, e);
5229         }
5230     }
5231 
5232     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
unregisterBluetoothQualityReportCallbackFn(IBluetooth service)5233     private void unregisterBluetoothQualityReportCallbackFn(IBluetooth service) {
5234         try {
5235             service.unregisterBluetoothQualityReportReadyCallback(
5236                     mBluetoothQualityReportReadyCallback, mAttributionSource);
5237         } catch (RemoteException e) {
5238             logRemoteException(TAG, e);
5239         }
5240     }
5241 
5242     private final IBluetoothQualityReportReadyCallback mBluetoothQualityReportReadyCallback =
5243             new IBluetoothQualityReportReadyCallback.Stub() {
5244                 @Override
5245                 @RequiresNoPermission
5246                 public void onBluetoothQualityReportReady(
5247                         BluetoothDevice device, BluetoothQualityReport report, int status) {
5248                     mQualityCallbackWrapper.forEach(
5249                             (cb) -> cb.onBluetoothQualityReportReady(device, report, status));
5250                 }
5251             };
5252 
5253     /** @hide */
5254     @Retention(RetentionPolicy.SOURCE)
5255     @IntDef(
5256             value = {
5257                 BluetoothStatusCodes.SUCCESS,
5258                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
5259                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
5260                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
5261                 BluetoothStatusCodes.ERROR_UNKNOWN
5262             })
5263     public @interface RegisterBluetoothQualityReportReadyCallbackReturnValues {}
5264 
5265     /**
5266      * Registers a callback to be notified when Bluetooth Quality Report is ready. To unregister
5267      * this callback, call {@link #unregisterBluetoothQualityReportReadyCallback(
5268      * BluetoothQualityReportReadyCallback)}.
5269      *
5270      * @param executor an {@link Executor} to execute the callbacks
5271      * @param callback user implementation of the {@link BluetoothQualityReportReadyCallback}
5272      * @return whether the callback was registered successfully
5273      * @throws NullPointerException if executor or callback is null
5274      * @throws IllegalArgumentException if the callback is already registered
5275      * @hide
5276      */
5277     @SystemApi
5278     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
5279     @RegisterBluetoothQualityReportReadyCallbackReturnValues
registerBluetoothQualityReportReadyCallback( @onNull @allbackExecutor Executor executor, @NonNull BluetoothQualityReportReadyCallback callback)5280     public int registerBluetoothQualityReportReadyCallback(
5281             @NonNull @CallbackExecutor Executor executor,
5282             @NonNull BluetoothQualityReportReadyCallback callback) {
5283         if (DBG) Log.d(TAG, "registerBluetoothQualityReportReadyCallback()");
5284 
5285         mServiceLock.readLock().lock();
5286         try {
5287             mQualityCallbackWrapper.registerCallback(mService, callback, executor);
5288         } finally {
5289             mServiceLock.readLock().unlock();
5290         }
5291         return BluetoothStatusCodes.SUCCESS;
5292     }
5293 
5294     /** @hide */
5295     @Retention(RetentionPolicy.SOURCE)
5296     @IntDef(
5297             value = {
5298                 BluetoothStatusCodes.SUCCESS,
5299                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
5300                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
5301                 BluetoothStatusCodes.ERROR_CALLBACK_NOT_REGISTERED,
5302                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
5303                 BluetoothStatusCodes.ERROR_UNKNOWN
5304             })
5305     public @interface UnRegisterBluetoothQualityReportReadyCallbackReturnValues {}
5306 
5307     /**
5308      * Unregisters a callback that was previously registered with {@link
5309      * #registerBluetoothQualityReportReadyCallback(Executor, BluetoothQualityReportReadyCallback)}.
5310      *
5311      * @param callback user implementation of the {@link BluetoothQualityReportReadyCallback}
5312      * @return whether the callback was successfully unregistered
5313      * @throws NullPointerException if the callback is null
5314      * @throws IllegalArgumentException if the callback has not been registered
5315      * @hide
5316      */
5317     @SystemApi
5318     @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
5319     @UnRegisterBluetoothQualityReportReadyCallbackReturnValues
unregisterBluetoothQualityReportReadyCallback( @onNull BluetoothQualityReportReadyCallback callback)5320     public int unregisterBluetoothQualityReportReadyCallback(
5321             @NonNull BluetoothQualityReportReadyCallback callback) {
5322         if (DBG) Log.d(TAG, "unregisterBluetoothQualityReportReadyCallback()");
5323 
5324         mServiceLock.readLock().lock();
5325         try {
5326             mQualityCallbackWrapper.unregisterCallback(mService, callback);
5327         } finally {
5328             mServiceLock.readLock().unlock();
5329         }
5330 
5331         return BluetoothStatusCodes.SUCCESS;
5332     }
5333 
5334     /**
5335      * A callback for Bluetooth Quality Report that arise from the controller.
5336      *
5337      * @hide
5338      */
5339     @SystemApi
5340     public interface BluetoothQualityReportReadyCallback {
5341         /**
5342          * Called when the Bluetooth Quality Report coming from the controller is ready. This
5343          * callback includes a Parcel that contains information about Bluetooth Quality. Currently
5344          * the report supports five event types: Quality monitor event, Approaching LSTO event, A2DP
5345          * choppy event, SCO choppy event and Connect fail event. To know which kind of event is
5346          * wrapped in this {@link BluetoothQualityReport} object, you need to call {@link
5347          * BluetoothQualityReport#getQualityReportId}.
5348          *
5349          * @param device is the BluetoothDevice which connection quality is being reported
5350          * @param bluetoothQualityReport a Parcel that contains info about Bluetooth Quality
5351          * @param status whether the operation succeeded or timed out
5352          * @hide
5353          */
5354         @SystemApi
onBluetoothQualityReportReady( @onNull BluetoothDevice device, @NonNull BluetoothQualityReport bluetoothQualityReport, int status)5355         void onBluetoothQualityReportReady(
5356                 @NonNull BluetoothDevice device,
5357                 @NonNull BluetoothQualityReport bluetoothQualityReport,
5358                 int status);
5359     }
5360 
5361     /**
5362      * Converts old constant of priority to the new for connection policy
5363      *
5364      * @param priority is the priority to convert to connection policy
5365      * @return the equivalent connection policy constant to the priority
5366      * @hide
5367      */
priorityToConnectionPolicy(int priority)5368     public static @ConnectionPolicy int priorityToConnectionPolicy(int priority) {
5369         switch (priority) {
5370             case BluetoothProfile.PRIORITY_AUTO_CONNECT:
5371                 return CONNECTION_POLICY_ALLOWED;
5372             case BluetoothProfile.PRIORITY_ON:
5373                 return CONNECTION_POLICY_ALLOWED;
5374             case BluetoothProfile.PRIORITY_OFF:
5375                 return CONNECTION_POLICY_FORBIDDEN;
5376             case BluetoothProfile.PRIORITY_UNDEFINED:
5377                 return CONNECTION_POLICY_UNKNOWN;
5378             default:
5379                 Log.e(TAG, "setPriority: Invalid priority: " + priority);
5380                 return CONNECTION_POLICY_UNKNOWN;
5381         }
5382     }
5383 
5384     /**
5385      * Converts new constant of connection policy to the old for priority
5386      *
5387      * @param connectionPolicy is the connection policy to convert to priority
5388      * @return the equivalent priority constant to the connectionPolicy
5389      * @hide
5390      */
connectionPolicyToPriority(@onnectionPolicy int connectionPolicy)5391     public static int connectionPolicyToPriority(@ConnectionPolicy int connectionPolicy) {
5392         switch (connectionPolicy) {
5393             case CONNECTION_POLICY_ALLOWED:
5394                 return BluetoothProfile.PRIORITY_ON;
5395             case CONNECTION_POLICY_FORBIDDEN:
5396                 return BluetoothProfile.PRIORITY_OFF;
5397             case CONNECTION_POLICY_UNKNOWN:
5398                 return BluetoothProfile.PRIORITY_UNDEFINED;
5399         }
5400         return BluetoothProfile.PRIORITY_UNDEFINED;
5401     }
5402 
5403     /**
5404      * Sets the desired mode of the HCI snoop logging applied at Bluetooth startup.
5405      *
5406      * <p>Please note that Bluetooth needs to be restarted in order for the change to take effect.
5407      *
5408      * @return status code indicating whether the logging mode was successfully set
5409      * @throws IllegalArgumentException if the mode is not a valid logging mode
5410      * @hide
5411      */
5412     @SystemApi
5413     @RequiresPermission(BLUETOOTH_PRIVILEGED)
5414     @SetSnoopLogModeStatusCode
setBluetoothHciSnoopLoggingMode(@luetoothSnoopLogMode int mode)5415     public int setBluetoothHciSnoopLoggingMode(@BluetoothSnoopLogMode int mode) {
5416         if (mode != BT_SNOOP_LOG_MODE_DISABLED
5417                 && mode != BT_SNOOP_LOG_MODE_FILTERED
5418                 && mode != BT_SNOOP_LOG_MODE_FULL) {
5419             throw new IllegalArgumentException("Invalid Bluetooth HCI snoop log mode param value");
5420         }
5421         try {
5422             return mManagerService.setBtHciSnoopLogMode(mode);
5423         } catch (RemoteException e) {
5424             throw e.rethrowFromSystemServer();
5425         }
5426     }
5427 
5428     /**
5429      * Gets the current desired mode of HCI snoop logging applied at Bluetooth startup.
5430      *
5431      * @return the current HCI snoop logging mode applied at Bluetooth startup
5432      * @hide
5433      */
5434     @SystemApi
5435     @RequiresPermission(BLUETOOTH_PRIVILEGED)
5436     @BluetoothSnoopLogMode
getBluetoothHciSnoopLoggingMode()5437     public int getBluetoothHciSnoopLoggingMode() {
5438         try {
5439             return mManagerService.getBtHciSnoopLogMode();
5440         } catch (RemoteException e) {
5441             throw e.rethrowFromSystemServer();
5442         }
5443     }
5444 
5445     /**
5446      * Returns true if the auto on feature is supported on the device
5447      *
5448      * @hide
5449      */
5450     @SystemApi
5451     @RequiresPermission(BLUETOOTH_PRIVILEGED)
isAutoOnSupported()5452     public boolean isAutoOnSupported() {
5453         try {
5454             return mManagerService.isAutoOnSupported();
5455         } catch (RemoteException e) {
5456             throw e.rethrowFromSystemServer();
5457         }
5458     }
5459 
5460     /**
5461      * Get the value of the automatic restart of the Bluetooth stack for the current user
5462      *
5463      * @return true if the auto on feature is enabled for the current user
5464      * @throws IllegalStateException if feature is not supported
5465      * @hide
5466      */
5467     @SystemApi
5468     @RequiresPermission(BLUETOOTH_PRIVILEGED)
isAutoOnEnabled()5469     public boolean isAutoOnEnabled() {
5470         try {
5471             return mManagerService.isAutoOnEnabled();
5472         } catch (RemoteException e) {
5473             throw e.rethrowFromSystemServer();
5474         }
5475     }
5476 
5477     /**
5478      * Set the value of the automatic restart of the Bluetooth stack for the current user. Client
5479      * can subscribe to update by listening to {@link ACTION_AUTO_ON_STATE_CHANGED} intent
5480      *
5481      * @param status true if the feature is enabled
5482      * @throws IllegalStateException if feature is not supported
5483      * @hide
5484      */
5485     @SystemApi
5486     @RequiresPermission(BLUETOOTH_PRIVILEGED)
setAutoOnEnabled(boolean status)5487     public void setAutoOnEnabled(boolean status) {
5488         try {
5489             mManagerService.setAutoOnEnabled(status);
5490         } catch (RemoteException e) {
5491             throw e.rethrowFromSystemServer();
5492         }
5493     }
5494 
5495     /** @hide */
5496     @Retention(RetentionPolicy.SOURCE)
5497     @IntDef(
5498             value = {
5499                 BluetoothStatusCodes.FEATURE_SUPPORTED,
5500                 BluetoothStatusCodes.ERROR_UNKNOWN,
5501                 BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
5502                 BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION,
5503                 BluetoothStatusCodes.FEATURE_NOT_SUPPORTED
5504             })
5505     public @interface GetOffloadedTransportDiscoveryDataScanSupportedReturnValues {}
5506 
5507     /**
5508      * Check if offloaded transport discovery data scan is supported or not.
5509      *
5510      * @return {@code BluetoothStatusCodes.FEATURE_SUPPORTED} if chipset supports on-chip tds filter
5511      *     scan
5512      * @hide
5513      */
5514     @SystemApi
5515     @RequiresBluetoothScanPermission
5516     @RequiresPermission(allOf = {BLUETOOTH_SCAN, BLUETOOTH_PRIVILEGED})
5517     @GetOffloadedTransportDiscoveryDataScanSupportedReturnValues
getOffloadedTransportDiscoveryDataScanSupported()5518     public int getOffloadedTransportDiscoveryDataScanSupported() {
5519         if (!getLeAccess()) {
5520             return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
5521         }
5522         mServiceLock.readLock().lock();
5523         try {
5524             if (mService != null) {
5525                 return mService.getOffloadedTransportDiscoveryDataScanSupported(mAttributionSource);
5526             }
5527         } catch (RemoteException e) {
5528             logRemoteException(TAG, e);
5529         } finally {
5530             mServiceLock.readLock().unlock();
5531         }
5532         return BluetoothStatusCodes.ERROR_UNKNOWN;
5533     }
5534 
5535     /**
5536      * Callbacks for receiving response of HCI Vendor-Specific Commands and Vendor-Specific Events
5537      * that arise from the controller.
5538      *
5539      * @hide
5540      */
5541     @SystemApi
5542     @FlaggedApi(Flags.FLAG_HCI_VENDOR_SPECIFIC_EXTENSION)
5543     public interface BluetoothHciVendorSpecificCallback {
5544         /**
5545          * Invoked when an `HCI_Command_Status`, in response to a Vendor Command is received.
5546          *
5547          * @param ocf "Opcode command field" of the HCI Opcode, as defined in the Bluetooth Core
5548          *     Specification Vol 4, Part E, Section 5.4.1.
5549          * @param status as defined by the Bluetooth Core Specification.
5550          */
onCommandStatus( @ntRangefrom = 0x000, to = 0x3ff) int ocf, @IntRange(from = 0x00, to = 0xff) int status)5551         void onCommandStatus(
5552                 @IntRange(from = 0x000, to = 0x3ff) int ocf,
5553                 @IntRange(from = 0x00, to = 0xff) int status);
5554 
5555         /**
5556          * Invoked when an `HCI_Command_Complete`, in response to a Vendor Command is received.
5557          *
5558          * @param ocf "Opcode command field" of the HCI Opcode, as defined in the Bluetooth Core
5559          *     Specification Vol 4, Part E, Section 5.4.1.
5560          * @param returnParameters Data returned by the command (from 0 to 252 Bytes).
5561          */
onCommandComplete( @ntRangefrom = 0x000, to = 0x3ff) int ocf, @NonNull byte[] returnParameters)5562         void onCommandComplete(
5563                 @IntRange(from = 0x000, to = 0x3ff) int ocf, @NonNull byte[] returnParameters);
5564 
5565         /**
5566          * Invoked when an event is received.
5567          *
5568          * @param code The vendor-specific event Code. The first octet of the event parameters
5569          *     of a vendor-specific event (Bluetooth Core Specification Vol 4, Part E, 5.4.3).
5570          * @param data from 0 to 254 Bytes.
5571          */
onEvent(@ntRangefrom = 0x00, to = 0xfe) int code, @NonNull byte[] data)5572         void onEvent(@IntRange(from = 0x00, to = 0xfe) int code, @NonNull byte[] data);
5573     }
5574 
5575     private static final class HciVendorSpecificCallbackRegistration {
5576         private BluetoothHciVendorSpecificCallback mCallback;
5577         private Executor mExecutor;
5578         private Set<Integer> mEventCodeSet;
5579 
set( BluetoothHciVendorSpecificCallback callback, Set<Integer> eventCodeSet, Executor executor)5580         void set(
5581                 BluetoothHciVendorSpecificCallback callback,
5582                 Set<Integer> eventCodeSet,
5583                 Executor executor) {
5584             mCallback = callback;
5585             mEventCodeSet = eventCodeSet;
5586             mExecutor = executor;
5587         }
5588 
reset()5589         void reset() {
5590             mCallback = null;
5591             mEventCodeSet = null;
5592             mExecutor = null;
5593         }
5594 
isSet()5595         boolean isSet() {
5596             return mCallback != null;
5597         }
5598 
isSet(BluetoothHciVendorSpecificCallback callback)5599         boolean isSet(BluetoothHciVendorSpecificCallback callback) {
5600             return isSet() && (callback == mCallback);
5601         }
5602 
5603         @RequiresPermission(BLUETOOTH_PRIVILEGED)
registerToService(IBluetooth service, IBluetoothHciVendorSpecificCallback stub)5604         void registerToService(IBluetooth service, IBluetoothHciVendorSpecificCallback stub) {
5605             if (service == null || !isSet()) {
5606                 return;
5607             }
5608 
5609             int[] eventCodes = mEventCodeSet.stream().mapToInt(i -> i).toArray();
5610             try {
5611                 service.registerHciVendorSpecificCallback(stub, eventCodes);
5612             } catch (RemoteException e) {
5613                 logRemoteException(TAG, e);
5614             }
5615         }
5616 
5617         @RequiresPermission(BLUETOOTH_PRIVILEGED)
unregisterFromService( IBluetooth service, IBluetoothHciVendorSpecificCallback stub)5618         static void unregisterFromService(
5619                 IBluetooth service, IBluetoothHciVendorSpecificCallback stub) {
5620             if (service == null) {
5621                 return;
5622             }
5623             try {
5624                 service.unregisterHciVendorSpecificCallback(stub);
5625             } catch (RemoteException e) {
5626                 logRemoteException(TAG, e);
5627             }
5628         }
5629 
execute(Consumer<BluetoothHciVendorSpecificCallback> consumer)5630         void execute(Consumer<BluetoothHciVendorSpecificCallback> consumer) {
5631             BluetoothHciVendorSpecificCallback callback = mCallback;
5632             if (callback == null) {
5633                 return;
5634             }
5635             executeFromBinder(mExecutor, () -> consumer.accept(callback));
5636         }
5637     }
5638 
5639     private final HciVendorSpecificCallbackRegistration mHciVendorSpecificCallbackRegistration =
5640             new HciVendorSpecificCallbackRegistration();
5641 
5642     private final IBluetoothHciVendorSpecificCallback mHciVendorSpecificCallbackStub =
5643             new IBluetoothHciVendorSpecificCallback.Stub() {
5644 
5645                 @Override
5646                 @RequiresNoPermission
5647                 public void onCommandStatus(int ocf, int status) {
5648                     synchronized (mHciVendorSpecificCallbackRegistration) {
5649                         if (Flags.hciVendorSpecificExtension()) {
5650                             mHciVendorSpecificCallbackRegistration.execute(
5651                                     (cb) -> cb.onCommandStatus(ocf, status));
5652                         }
5653                     }
5654                 }
5655 
5656                 @Override
5657                 @RequiresNoPermission
5658                 public void onCommandComplete(int ocf, byte[] returnParameters) {
5659                     synchronized (mHciVendorSpecificCallbackRegistration) {
5660                         if (Flags.hciVendorSpecificExtension()) {
5661                             mHciVendorSpecificCallbackRegistration.execute(
5662                                     (cb) -> cb.onCommandComplete(ocf, returnParameters));
5663                         }
5664                     }
5665                 }
5666 
5667                 @Override
5668                 @RequiresNoPermission
5669                 public void onEvent(int code, byte[] data) {
5670                     synchronized (mHciVendorSpecificCallbackRegistration) {
5671                         if (Flags.hciVendorSpecificExtension()) {
5672                             mHciVendorSpecificCallbackRegistration.execute(
5673                                     (cb) -> cb.onEvent(code, data));
5674                         }
5675                     }
5676                 }
5677             };
5678 
5679     /**
5680      * Register an {@link BluetoothHciVendorCallback} to listen for HCI vendor responses and events
5681      *
5682      * @param eventCodeSet Set of vendor-specific event codes to listen for updates. Each
5683      *     vendor-specific event code must be in the range 0x00 to 0x4f or 0x60 to 0xff. The
5684      *     inclusive range 0x52-0x5f is reserved by the system.
5685      * @param executor an {@link Executor} to execute given callback
5686      * @param callback user implementation of the {@link BluetoothHciVendorCallback}
5687      * @throws IllegalArgumentException if the callback is already registered, or event codes not in
5688      *     a valid range
5689      * @hide
5690      */
5691     @SystemApi
5692     @FlaggedApi(Flags.FLAG_HCI_VENDOR_SPECIFIC_EXTENSION)
5693     @RequiresPermission(BLUETOOTH_PRIVILEGED)
registerBluetoothHciVendorSpecificCallback( @onNull Set<Integer> eventCodeSet, @NonNull @CallbackExecutor Executor executor, @NonNull BluetoothHciVendorSpecificCallback callback)5694     public void registerBluetoothHciVendorSpecificCallback(
5695             @NonNull Set<Integer> eventCodeSet,
5696             @NonNull @CallbackExecutor Executor executor,
5697             @NonNull BluetoothHciVendorSpecificCallback callback) {
5698         if (DBG) Log.d(TAG, "registerBluetoothHciVendorSpecificCallback()");
5699 
5700         requireNonNull(eventCodeSet);
5701         requireNonNull(executor);
5702         requireNonNull(callback);
5703         if (eventCodeSet.stream()
5704                 .anyMatch((n) -> (n < 0) || (n >= 0x52 && n < 0x60) || (n > 0xff))) {
5705             throw new IllegalArgumentException("Event code not in valid range");
5706         }
5707 
5708         mServiceLock.readLock().lock();
5709         try {
5710             synchronized (mHciVendorSpecificCallbackRegistration) {
5711                 if (mHciVendorSpecificCallbackRegistration.isSet()) {
5712                     throw new IllegalArgumentException("Only one registration allowed");
5713                 }
5714                 mHciVendorSpecificCallbackRegistration.set(callback, eventCodeSet, executor);
5715                 try {
5716                     mHciVendorSpecificCallbackRegistration.registerToService(
5717                             mService, mHciVendorSpecificCallbackStub);
5718                 } catch (Exception e) {
5719                     mHciVendorSpecificCallbackRegistration.reset();
5720                     throw e;
5721                 }
5722             }
5723         } finally {
5724             mServiceLock.readLock().unlock();
5725         }
5726     }
5727 
5728     /**
5729      * Unregister the specified {@link BluetoothHciVendorCallback}
5730      *
5731      * @param callback user implementation of the {@link BluetoothHciVendorCallback}
5732      * @throws IllegalArgumentException if the callback has not been registered
5733      * @hide
5734      */
5735     @SystemApi
5736     @FlaggedApi(Flags.FLAG_HCI_VENDOR_SPECIFIC_EXTENSION)
5737     @RequiresPermission(BLUETOOTH_PRIVILEGED)
unregisterBluetoothHciVendorSpecificCallback( @onNull BluetoothHciVendorSpecificCallback callback)5738     public void unregisterBluetoothHciVendorSpecificCallback(
5739             @NonNull BluetoothHciVendorSpecificCallback callback) {
5740         if (DBG) Log.d(TAG, "unregisterBluetoothHciVendorSpecificCallback()");
5741 
5742         requireNonNull(callback);
5743 
5744         mServiceLock.readLock().lock();
5745         try {
5746             synchronized (mHciVendorSpecificCallbackRegistration) {
5747                 if (!mHciVendorSpecificCallbackRegistration.isSet(callback)) {
5748                     throw new IllegalArgumentException("Callback not registered");
5749                 }
5750                 mHciVendorSpecificCallbackRegistration.unregisterFromService(
5751                         mService, mHciVendorSpecificCallbackStub);
5752                 mHciVendorSpecificCallbackRegistration.reset();
5753             }
5754         } finally {
5755             mServiceLock.readLock().unlock();
5756         }
5757     }
5758 
5759     /**
5760      * Send an HCI Vendor-Specific Command
5761      *
5762      * @param ocf "Opcode command field" of the HCI Opcode, as defined in the Bluetooth Core
5763      *     Specification Vol 4, Part E, Section 5.4.1. Each vendor-specific ocf must be in the range
5764      *     0x000-0x14f or 0x160-0x3ff. The inclusive range 0x150-0x15f is reserved by the system.
5765      * @param parameters shall be less or equal to 255 bytes.
5766      * @throws IllegalArgumentException if the ocf is not in a valid range
5767      * @throws IllegalStateException when a callback has not been registered
5768      * @hide
5769      */
5770     @SystemApi
5771     @FlaggedApi(Flags.FLAG_HCI_VENDOR_SPECIFIC_EXTENSION)
5772     @RequiresPermission(BLUETOOTH_PRIVILEGED)
sendBluetoothHciVendorSpecificCommand( @ntRangefrom = 0x000, to = 0x3ff) int ocf, @NonNull byte[] parameters)5773     public void sendBluetoothHciVendorSpecificCommand(
5774             @IntRange(from = 0x000, to = 0x3ff) int ocf, @NonNull byte[] parameters) {
5775         if (DBG) Log.d(TAG, "sendBluetoothHciVendorSpecificCommand()");
5776 
5777         // Open this no-op android command for test purpose
5778         int getVendorCapabilitiesOcf = 0x153;
5779         if (ocf < 0
5780                 || (ocf >= 0x150 && ocf < 0x160 && ocf != getVendorCapabilitiesOcf)
5781                 || ocf > 0x3ff) {
5782             throw new IllegalArgumentException("Opcode command value not in valid range");
5783         }
5784 
5785         requireNonNull(parameters);
5786         if (parameters.length > 255) {
5787             throw new IllegalArgumentException("Parameters size is too big");
5788         }
5789 
5790         mServiceLock.readLock().lock();
5791         try {
5792             if (!mHciVendorSpecificCallbackRegistration.isSet()) {
5793                 throw new IllegalStateException("No Callback registered");
5794             }
5795 
5796             if (mService != null) {
5797                 mService.sendHciVendorSpecificCommand(
5798                         ocf, parameters, mHciVendorSpecificCallbackStub);
5799             }
5800         } catch (RemoteException e) {
5801             logRemoteException(TAG, e);
5802         } finally {
5803             mServiceLock.readLock().unlock();
5804         }
5805     }
5806 
5807     /**
5808      * Returns whether LE CoC socket hardware offload is supported.
5809      *
5810      * <p>Bluetooth socket hardware offload allows the system to handle Bluetooth communication on a
5811      * low-power processor, improving efficiency and reducing power consumption. This is achieved by
5812      * providing channel information of an already connected {@link BluetoothSocket} to offload
5813      * endpoints (e.g., offload stacks and applications). The offload stack can then decode received
5814      * packets and pass them to the appropriate offload application without waking up the main
5815      * application processor. This API allows offload endpoints to utilize Bluetooth sockets while
5816      * the host stack retains control over the connection.
5817      *
5818      * <p>To configure a socket for hardware offload, use the following {@link
5819      * BluetoothSocketSettings} methods:
5820      *
5821      * <ul>
5822      *   <li>{@link BluetoothSocketSettings#setDataPath(int)} with {@link
5823      *       BluetoothSocketSettings#DATA_PATH_HARDWARE_OFFLOAD}
5824      *   <li>{@link BluetoothSocketSettings#setHubId(long)}
5825      *   <li>{@link BluetoothSocketSettings#setEndpointId(long)}
5826      * </ul>
5827      *
5828      * <p>This functionality is provided as a System API because only OEM specific system
5829      * applications can be offloaded as endpoints in the low-power processor.
5830      *
5831      * @return {@code true} if LE CoC socket hardware offload is supported, {@code false} otherwise.
5832      * @hide
5833      */
5834     @SystemApi
5835     @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
5836     @RequiresPermission(BLUETOOTH_PRIVILEGED)
isLeCocSocketOffloadSupported()5837     public boolean isLeCocSocketOffloadSupported() {
5838         if (!isEnabled()) {
5839             return false;
5840         }
5841         mServiceLock.readLock().lock();
5842         try {
5843             if (mService != null) {
5844                 return mService.isLeCocSocketOffloadSupported(mAttributionSource);
5845             }
5846         } catch (RemoteException e) {
5847             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
5848         } finally {
5849             mServiceLock.readLock().unlock();
5850         }
5851         return false;
5852     }
5853 
5854     /**
5855      * Returns whether RFCOMM socket hardware offload is supported.
5856      *
5857      * <p>Bluetooth socket hardware offload allows the system to handle Bluetooth communication on a
5858      * low-power processor, improving efficiency and reducing power consumption. This is achieved by
5859      * providing channel information of an already connected {@link BluetoothSocket} to offload
5860      * endpoints (e.g., offload stacks and applications). The offload stack can then decode received
5861      * packets and pass them to the appropriate offload application without waking up the main
5862      * application processor. This API allows offload endpoints to utilize Bluetooth sockets while
5863      * the host stack retains control over the connection.
5864      *
5865      * <p>To configure a socket for hardware offload, use the following {@link
5866      * BluetoothSocketSettings} methods:
5867      *
5868      * <ul>
5869      *   <li>{@link BluetoothSocketSettings#setDataPath(int)} with {@link
5870      *       BluetoothSocketSettings#DATA_PATH_HARDWARE_OFFLOAD}
5871      *   <li>{@link BluetoothSocketSettings#setHubId(long)}
5872      *   <li>{@link BluetoothSocketSettings#setEndpointId(long)}
5873      * </ul>
5874      *
5875      * <p>This functionality is provided as a System API because only OEM specific system
5876      * applications can be offloaded as endpoints in the low-power processor.
5877      *
5878      * @return {@code true} if RFCOMM socket hardware offload is supported, {@code false} otherwise.
5879      * @hide
5880      */
5881     @SystemApi
5882     @FlaggedApi(Flags.FLAG_SOCKET_SETTINGS_API)
5883     @RequiresPermission(BLUETOOTH_PRIVILEGED)
isRfcommSocketOffloadSupported()5884     public boolean isRfcommSocketOffloadSupported() {
5885         if (!isEnabled()) {
5886             return false;
5887         }
5888         mServiceLock.readLock().lock();
5889         try {
5890             if (mService != null) {
5891                 return mService.isRfcommSocketOffloadSupported(mAttributionSource);
5892             }
5893         } catch (RemoteException e) {
5894             Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
5895         } finally {
5896             mServiceLock.readLock().unlock();
5897         }
5898         return false;
5899     }
5900 }
5901