• 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 java.util.Objects.requireNonNull;
21 
22 import android.annotation.CallbackExecutor;
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.RequiresNoPermission;
27 import android.annotation.RequiresPermission;
28 import android.annotation.SdkConstant;
29 import android.annotation.SdkConstant.SdkConstantType;
30 import android.annotation.SuppressLint;
31 import android.annotation.SystemApi;
32 import android.app.ActivityThread;
33 import android.app.PropertyInvalidatedCache;
34 import android.bluetooth.BluetoothDevice.Transport;
35 import android.bluetooth.BluetoothProfile.ConnectionPolicy;
36 import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
37 import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
38 import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
39 import android.bluetooth.annotations.RequiresBluetoothScanPermission;
40 import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
41 import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
42 import android.bluetooth.le.BluetoothLeAdvertiser;
43 import android.bluetooth.le.BluetoothLeScanner;
44 import android.bluetooth.le.PeriodicAdvertisingManager;
45 import android.bluetooth.le.ScanCallback;
46 import android.bluetooth.le.ScanFilter;
47 import android.bluetooth.le.ScanRecord;
48 import android.bluetooth.le.ScanResult;
49 import android.bluetooth.le.ScanSettings;
50 import android.compat.annotation.UnsupportedAppUsage;
51 import android.content.Attributable;
52 import android.content.AttributionSource;
53 import android.content.Context;
54 import android.os.BatteryStats;
55 import android.os.Binder;
56 import android.os.Build;
57 import android.os.IBinder;
58 import android.os.ParcelUuid;
59 import android.os.RemoteException;
60 import android.os.ResultReceiver;
61 import android.os.ServiceManager;
62 import android.os.SynchronousResultReceiver;
63 import android.os.SystemProperties;
64 import android.util.Log;
65 import android.util.Pair;
66 
67 import com.android.internal.annotations.GuardedBy;
68 
69 import java.io.IOException;
70 import java.lang.annotation.Retention;
71 import java.lang.annotation.RetentionPolicy;
72 import java.util.ArrayList;
73 import java.util.Arrays;
74 import java.util.Collections;
75 import java.util.HashMap;
76 import java.util.HashSet;
77 import java.util.List;
78 import java.util.Locale;
79 import java.util.Map;
80 import java.util.Objects;
81 import java.util.Set;
82 import java.util.UUID;
83 import java.util.WeakHashMap;
84 import java.util.concurrent.Executor;
85 import java.util.concurrent.TimeoutException;
86 import java.util.concurrent.locks.ReentrantReadWriteLock;
87 
88 /**
89  * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter}
90  * lets you perform fundamental Bluetooth tasks, such as initiate
91  * device discovery, query a list of bonded (paired) devices,
92  * instantiate a {@link BluetoothDevice} using a known MAC address, and create
93  * a {@link BluetoothServerSocket} to listen for connection requests from other
94  * devices, and start a scan for Bluetooth LE devices.
95  *
96  * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
97  * adapter, call the {@link BluetoothManager#getAdapter} function on {@link BluetoothManager}.
98  * On JELLY_BEAN_MR1 and below you will need to use the static {@link #getDefaultAdapter}
99  * method instead.
100  * </p><p>
101  * Fundamentally, this is your starting point for all
102  * Bluetooth actions. Once you have the local adapter, you can get a set of
103  * {@link BluetoothDevice} objects representing all paired devices with
104  * {@link #getBondedDevices()}; start device discovery with
105  * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
106  * listen for incoming RFComm connection requests with {@link
107  * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented
108  * Channels (CoC) connection requests with {@link #listenUsingL2capChannel()}; or start a scan for
109  * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
110  * </p>
111  * <p>This class is thread safe.</p>
112  * <div class="special reference">
113  * <h3>Developer Guides</h3>
114  * <p>
115  * For more information about using Bluetooth, read the <a href=
116  * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
117  * guide.
118  * </p>
119  * </div>
120  *
121  * {@see BluetoothDevice}
122  * {@see BluetoothServerSocket}
123  */
124 public final class BluetoothAdapter {
125     private static final String TAG = "BluetoothAdapter";
126     private static final String DESCRIPTOR = "android.bluetooth.BluetoothAdapter";
127     private static final boolean DBG = true;
128     private static final boolean VDBG = false;
129 
130     /**
131      * Default MAC address reported to a client that does not have the
132      * android.permission.LOCAL_MAC_ADDRESS permission.
133      *
134      * @hide
135      */
136     public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
137 
138     /**
139      * Sentinel error value for this class. Guaranteed to not equal any other
140      * integer constant in this class. Provided as a convenience for functions
141      * that require a sentinel error value, for example:
142      * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
143      * BluetoothAdapter.ERROR)</code>
144      */
145     public static final int ERROR = Integer.MIN_VALUE;
146 
147     /**
148      * Broadcast Action: The state of the local Bluetooth adapter has been
149      * changed.
150      * <p>For example, Bluetooth has been turned on or off.
151      * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link
152      * #EXTRA_PREVIOUS_STATE} containing the new and old states
153      * respectively.
154      */
155     @RequiresLegacyBluetoothPermission
156     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
157             ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED";
158 
159     /**
160      * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
161      * intents to request the current power state. Possible values are:
162      * {@link #STATE_OFF},
163      * {@link #STATE_TURNING_ON},
164      * {@link #STATE_ON},
165      * {@link #STATE_TURNING_OFF},
166      */
167     public static final String EXTRA_STATE = "android.bluetooth.adapter.extra.STATE";
168     /**
169      * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
170      * intents to request the previous power state. Possible values are:
171      * {@link #STATE_OFF},
172      * {@link #STATE_TURNING_ON},
173      * {@link #STATE_ON},
174      * {@link #STATE_TURNING_OFF}
175      */
176     public static final String EXTRA_PREVIOUS_STATE =
177             "android.bluetooth.adapter.extra.PREVIOUS_STATE";
178 
179     /** @hide */
180     @IntDef(prefix = { "STATE_" }, value = {
181             STATE_OFF,
182             STATE_TURNING_ON,
183             STATE_ON,
184             STATE_TURNING_OFF,
185             STATE_BLE_TURNING_ON,
186             STATE_BLE_ON,
187             STATE_BLE_TURNING_OFF
188     })
189     @Retention(RetentionPolicy.SOURCE)
190     public @interface AdapterState {}
191 
192     /**
193      * Indicates the local Bluetooth adapter is off.
194      */
195     public static final int STATE_OFF = 10;
196     /**
197      * Indicates the local Bluetooth adapter is turning on. However local
198      * clients should wait for {@link #STATE_ON} before attempting to
199      * use the adapter.
200      */
201     public static final int STATE_TURNING_ON = 11;
202     /**
203      * Indicates the local Bluetooth adapter is on, and ready for use.
204      */
205     public static final int STATE_ON = 12;
206     /**
207      * Indicates the local Bluetooth adapter is turning off. Local clients
208      * should immediately attempt graceful disconnection of any remote links.
209      */
210     public static final int STATE_TURNING_OFF = 13;
211 
212     /**
213      * Indicates the local Bluetooth adapter is turning Bluetooth LE mode on.
214      *
215      * @hide
216      */
217     public static final int STATE_BLE_TURNING_ON = 14;
218 
219     /**
220      * Indicates the local Bluetooth adapter is in LE only mode.
221      *
222      * @hide
223      */
224     public static final int STATE_BLE_ON = 15;
225 
226     /**
227      * Indicates the local Bluetooth adapter is turning off LE only mode.
228      *
229      * @hide
230      */
231     public static final int STATE_BLE_TURNING_OFF = 16;
232 
233     /**
234      * UUID of the GATT Read Characteristics for LE_PSM value.
235      *
236      * @hide
237      */
238     public static final UUID LE_PSM_CHARACTERISTIC_UUID =
239             UUID.fromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a");
240 
241     /**
242      * Human-readable string helper for AdapterState
243      *
244      * @hide
245      */
nameForState(@dapterState int state)246     public static String nameForState(@AdapterState int state) {
247         switch (state) {
248             case STATE_OFF:
249                 return "OFF";
250             case STATE_TURNING_ON:
251                 return "TURNING_ON";
252             case STATE_ON:
253                 return "ON";
254             case STATE_TURNING_OFF:
255                 return "TURNING_OFF";
256             case STATE_BLE_TURNING_ON:
257                 return "BLE_TURNING_ON";
258             case STATE_BLE_ON:
259                 return "BLE_ON";
260             case STATE_BLE_TURNING_OFF:
261                 return "BLE_TURNING_OFF";
262             default:
263                 return "?!?!? (" + state + ")";
264         }
265     }
266 
267     /**
268      * Activity Action: Show a system activity that requests discoverable mode.
269      * This activity will also request the user to turn on Bluetooth if it
270      * is not currently enabled.
271      * <p>Discoverable mode is equivalent to {@link
272      * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see
273      * this Bluetooth adapter when they perform a discovery.
274      * <p>For privacy, Android is not discoverable by default.
275      * <p>The sender of this Intent can optionally use extra field {@link
276      * #EXTRA_DISCOVERABLE_DURATION} to request the duration of
277      * discoverability. Currently the default duration is 120 seconds, and
278      * maximum duration is capped at 300 seconds for each request.
279      * <p>Notification of the result of this activity is posted using the
280      * {@link android.app.Activity#onActivityResult} callback. The
281      * <code>resultCode</code>
282      * will be the duration (in seconds) of discoverability or
283      * {@link android.app.Activity#RESULT_CANCELED} if the user rejected
284      * discoverability or an error has occurred.
285      * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED}
286      * for global notification whenever the scan mode changes. For example, an
287      * application can be notified when the device has ended discoverability.
288      */
289     @RequiresLegacyBluetoothPermission
290     @RequiresBluetoothAdvertisePermission
291     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
292     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
293             ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
294 
295     /**
296      * Used as an optional int extra field in {@link
297      * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration
298      * for discoverability in seconds. The current default is 120 seconds, and
299      * requests over 300 seconds will be capped. These values could change.
300      */
301     public static final String EXTRA_DISCOVERABLE_DURATION =
302             "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION";
303 
304     /**
305      * Activity Action: Show a system activity that allows the user to turn on
306      * Bluetooth.
307      * <p>This system activity will return once Bluetooth has completed turning
308      * on, or the user has decided not to turn Bluetooth on.
309      * <p>Notification of the result of this activity is posted using the
310      * {@link android.app.Activity#onActivityResult} callback. The
311      * <code>resultCode</code>
312      * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been
313      * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
314      * has rejected the request or an error has occurred.
315      * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
316      * for global notification whenever Bluetooth is turned on or off.
317      */
318     @RequiresLegacyBluetoothPermission
319     @RequiresBluetoothConnectPermission
320     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
321     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
322             ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
323 
324     /**
325      * Activity Action: Show a system activity that allows the user to turn off
326      * Bluetooth. This is used only if permission review is enabled which is for
327      * apps targeting API less than 23 require a permission review before any of
328      * the app's components can run.
329      * <p>This system activity will return once Bluetooth has completed turning
330      * off, or the user has decided not to turn Bluetooth off.
331      * <p>Notification of the result of this activity is posted using the
332      * {@link android.app.Activity#onActivityResult} callback. The
333      * <code>resultCode</code>
334      * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been
335      * turned off or {@link android.app.Activity#RESULT_CANCELED} if the user
336      * has rejected the request or an error has occurred.
337      * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
338      * for global notification whenever Bluetooth is turned on or off.
339      *
340      * @hide
341      */
342     @RequiresLegacyBluetoothPermission
343     @RequiresBluetoothConnectPermission
344     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
345     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
346             ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE";
347 
348     /**
349      * Activity Action: Show a system activity that allows user to enable BLE scans even when
350      * Bluetooth is turned off.<p>
351      *
352      * Notification of result of this activity is posted using
353      * {@link android.app.Activity#onActivityResult}. The <code>resultCode</code> will be
354      * {@link android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or
355      * {@link android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an
356      * error occurred.
357      *
358      * @hide
359      */
360     @SystemApi
361     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
362     public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE =
363             "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
364 
365     /**
366      * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
367      * has changed.
368      * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
369      * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
370      * respectively.
371      */
372     @RequiresLegacyBluetoothPermission
373     @RequiresBluetoothScanPermission
374     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
375     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
376             ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
377 
378     /**
379      * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
380      * intents to request the current scan mode. Possible values are:
381      * {@link #SCAN_MODE_NONE},
382      * {@link #SCAN_MODE_CONNECTABLE},
383      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
384      */
385     public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
386     /**
387      * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
388      * intents to request the previous scan mode. Possible values are:
389      * {@link #SCAN_MODE_NONE},
390      * {@link #SCAN_MODE_CONNECTABLE},
391      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
392      */
393     public static final String EXTRA_PREVIOUS_SCAN_MODE =
394             "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
395 
396     /** @hide */
397     @IntDef(prefix = { "SCAN_" }, value = {
398             SCAN_MODE_NONE,
399             SCAN_MODE_CONNECTABLE,
400             SCAN_MODE_CONNECTABLE_DISCOVERABLE
401     })
402     @Retention(RetentionPolicy.SOURCE)
403     public @interface ScanMode {}
404 
405     /**
406      * Indicates that both inquiry scan and page scan are disabled on the local
407      * Bluetooth adapter. Therefore this device is neither discoverable
408      * nor connectable from remote Bluetooth devices.
409      */
410     public static final int SCAN_MODE_NONE = 20;
411     /**
412      * Indicates that inquiry scan is disabled, but page scan is enabled on the
413      * local Bluetooth adapter. Therefore this device is not discoverable from
414      * remote Bluetooth devices, but is connectable from remote devices that
415      * have previously discovered this device.
416      */
417     public static final int SCAN_MODE_CONNECTABLE = 21;
418     /**
419      * Indicates that both inquiry scan and page scan are enabled on the local
420      * Bluetooth adapter. Therefore this device is both discoverable and
421      * connectable from remote Bluetooth devices.
422      */
423     public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
424 
425     /**
426      * Device only has a display.
427      *
428      * @hide
429      */
430     public static final int IO_CAPABILITY_OUT = 0;
431 
432     /**
433      * Device has a display and the ability to input Yes/No.
434      *
435      * @hide
436      */
437     public static final int IO_CAPABILITY_IO = 1;
438 
439     /**
440      * Device only has a keyboard for entry but no display.
441      *
442      * @hide
443      */
444     public static final int IO_CAPABILITY_IN = 2;
445 
446     /**
447      * Device has no Input or Output capability.
448      *
449      * @hide
450      */
451     public static final int IO_CAPABILITY_NONE = 3;
452 
453     /**
454      * Device has a display and a full keyboard.
455      *
456      * @hide
457      */
458     public static final int IO_CAPABILITY_KBDISP = 4;
459 
460     /**
461      * Maximum range value for Input/Output capabilities.
462      *
463      * <p>This should be updated when adding a new Input/Output capability. Other code
464      * like validation depends on this being accurate.
465      *
466      * @hide
467      */
468     public static final int IO_CAPABILITY_MAX = 5;
469 
470     /**
471      * The Input/Output capability of the device is unknown.
472      *
473      * @hide
474      */
475     public static final int IO_CAPABILITY_UNKNOWN = 255;
476 
477     /** @hide */
478     @IntDef({IO_CAPABILITY_OUT, IO_CAPABILITY_IO, IO_CAPABILITY_IN, IO_CAPABILITY_NONE,
479             IO_CAPABILITY_KBDISP})
480     @Retention(RetentionPolicy.SOURCE)
481     public @interface IoCapability {}
482 
483     /** @hide */
484     @IntDef(prefix = "ACTIVE_DEVICE_", value = {ACTIVE_DEVICE_AUDIO,
485             ACTIVE_DEVICE_PHONE_CALL, ACTIVE_DEVICE_ALL})
486     @Retention(RetentionPolicy.SOURCE)
487     public @interface ActiveDeviceUse {}
488 
489     /**
490      * Use the specified device for audio (a2dp and hearing aid profile)
491      *
492      * @hide
493      */
494     @SystemApi
495     public static final int ACTIVE_DEVICE_AUDIO = 0;
496 
497     /**
498      * Use the specified device for phone calls (headset profile and hearing
499      * aid profile)
500      *
501      * @hide
502      */
503     @SystemApi
504     public static final int ACTIVE_DEVICE_PHONE_CALL = 1;
505 
506     /**
507      * Use the specified device for a2dp, hearing aid profile, and headset profile
508      *
509      * @hide
510      */
511     @SystemApi
512     public static final int ACTIVE_DEVICE_ALL = 2;
513 
514     /**
515      * Broadcast Action: The local Bluetooth adapter has started the remote
516      * device discovery process.
517      * <p>This usually involves an inquiry scan of about 12 seconds, followed
518      * by a page scan of each new device to retrieve its Bluetooth name.
519      * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as
520      * remote Bluetooth devices are found.
521      * <p>Device discovery is a heavyweight procedure. New connections to
522      * remote Bluetooth devices should not be attempted while discovery is in
523      * progress, and existing connections will experience limited bandwidth
524      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
525      * discovery.
526      */
527     @RequiresLegacyBluetoothPermission
528     @RequiresBluetoothScanPermission
529     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
530     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
531             ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
532     /**
533      * Broadcast Action: The local Bluetooth adapter has finished the device
534      * discovery process.
535      */
536     @RequiresLegacyBluetoothPermission
537     @RequiresBluetoothScanPermission
538     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
539     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
540             ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
541 
542     /**
543      * Broadcast Action: The local Bluetooth adapter has changed its friendly
544      * Bluetooth name.
545      * <p>This name is visible to remote Bluetooth devices.
546      * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing
547      * the name.
548      */
549     @RequiresLegacyBluetoothPermission
550     @RequiresBluetoothConnectPermission
551     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
552     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
553             ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
554     /**
555      * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED}
556      * intents to request the local Bluetooth name.
557      */
558     public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
559 
560     /**
561      * Intent used to broadcast the change in connection state of the local
562      * Bluetooth adapter to a profile of the remote device. When the adapter is
563      * not connected to any profiles of any remote devices and it attempts a
564      * connection to a profile this intent will be sent. Once connected, this intent
565      * will not be sent for any more connection attempts to any profiles of any
566      * remote device. When the adapter disconnects from the last profile its
567      * connected to of any remote device, this intent will be sent.
568      *
569      * <p> This intent is useful for applications that are only concerned about
570      * whether the local adapter is connected to any profile of any device and
571      * are not really concerned about which profile. For example, an application
572      * which displays an icon to display whether Bluetooth is connected or not
573      * can use this intent.
574      *
575      * <p>This intent will have 3 extras:
576      * {@link #EXTRA_CONNECTION_STATE} - The current connection state.
577      * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state.
578      * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
579      *
580      * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE}
581      * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
582      * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
583      */
584     @RequiresLegacyBluetoothPermission
585     @RequiresBluetoothConnectPermission
586     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
587     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
588             ACTION_CONNECTION_STATE_CHANGED =
589             "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
590 
591     /**
592      * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
593      *
594      * This extra represents the current connection state.
595      */
596     public static final String EXTRA_CONNECTION_STATE =
597             "android.bluetooth.adapter.extra.CONNECTION_STATE";
598 
599     /**
600      * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
601      *
602      * This extra represents the previous connection state.
603      */
604     public static final String EXTRA_PREVIOUS_CONNECTION_STATE =
605             "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
606 
607     /**
608      * Broadcast Action: The Bluetooth adapter state has changed in LE only mode.
609      *
610      * @hide
611      */
612     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
613     @SystemApi public static final String ACTION_BLE_STATE_CHANGED =
614             "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
615 
616     /**
617      * Intent used to broadcast the change in the Bluetooth address
618      * of the local Bluetooth adapter.
619      * <p>Always contains the extra field {@link
620      * #EXTRA_BLUETOOTH_ADDRESS} containing the Bluetooth address.
621      *
622      * Note: only system level processes are allowed to send this
623      * defined broadcast.
624      *
625      * @hide
626      */
627     @RequiresBluetoothConnectPermission
628     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
629     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
630     public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED =
631             "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED";
632 
633     /**
634      * Used as a String extra field in {@link
635      * #ACTION_BLUETOOTH_ADDRESS_CHANGED} intent to store the local
636      * Bluetooth address.
637      *
638      * @hide
639      */
640     public static final String EXTRA_BLUETOOTH_ADDRESS =
641             "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS";
642 
643     /**
644      * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
645      * by BLE Always on enabled application to know the ACL_CONNECTED event
646      * when Bluetooth state in STATE_BLE_ON. This denotes GATT connection
647      * as Bluetooth LE is the only feature available in STATE_BLE_ON
648      *
649      * This is counterpart of {@link BluetoothDevice#ACTION_ACL_CONNECTED} which
650      * works in Bluetooth state STATE_ON
651      *
652      * @hide
653      */
654     @RequiresBluetoothConnectPermission
655     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
656     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
657     public static final String ACTION_BLE_ACL_CONNECTED =
658             "android.bluetooth.adapter.action.BLE_ACL_CONNECTED";
659 
660     /**
661      * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
662      * by BLE Always on enabled application to know the ACL_DISCONNECTED event
663      * when Bluetooth state in STATE_BLE_ON. This denotes GATT disconnection as Bluetooth
664      * LE is the only feature available in STATE_BLE_ON
665      *
666      * This is counterpart of {@link BluetoothDevice#ACTION_ACL_DISCONNECTED} which
667      * works in Bluetooth state STATE_ON
668      *
669      * @hide
670      */
671     @RequiresBluetoothConnectPermission
672     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
673     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
674     public static final String ACTION_BLE_ACL_DISCONNECTED =
675             "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED";
676 
677     /** The profile is in disconnected state */
678     public static final int STATE_DISCONNECTED = BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED;
679     /** The profile is in connecting state */
680     public static final int STATE_CONNECTING = BluetoothProtoEnums.CONNECTION_STATE_CONNECTING;
681     /** The profile is in connected state */
682     public static final int STATE_CONNECTED = BluetoothProtoEnums.CONNECTION_STATE_CONNECTED;
683     /** The profile is in disconnecting state */
684     public static final int STATE_DISCONNECTING =
685             BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING;
686 
687     /** @hide */
688     public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
689     private final IBinder mToken;
690 
691 
692     /**
693      * When creating a ServerSocket using listenUsingRfcommOn() or
694      * listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create
695      * a ServerSocket that auto assigns a channel number to the first
696      * bluetooth socket.
697      * The channel number assigned to this first Bluetooth Socket will
698      * be stored in the ServerSocket, and reused for subsequent Bluetooth
699      * sockets.
700      *
701      * @hide
702      */
703     public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2;
704 
705 
706     private static final int ADDRESS_LENGTH = 17;
707 
708     /**
709      * Lazily initialized singleton. Guaranteed final after first object
710      * constructed.
711      */
712     private static BluetoothAdapter sAdapter;
713 
714     private BluetoothLeScanner mBluetoothLeScanner;
715     private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
716     private PeriodicAdvertisingManager mPeriodicAdvertisingManager;
717 
718     private final IBluetoothManager mManagerService;
719     private final AttributionSource mAttributionSource;
720 
721     // Yeah, keeping both mService and sService isn't pretty, but it's too late
722     // in the current release for a major refactoring, so we leave them both
723     // intact until this can be cleaned up in a future release
724 
725     @UnsupportedAppUsage
726     @GuardedBy("mServiceLock")
727     private IBluetooth mService;
728     private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
729 
730     @GuardedBy("sServiceLock")
731     private static boolean sServiceRegistered;
732     @GuardedBy("sServiceLock")
733     private static IBluetooth sService;
734     private static final Object sServiceLock = new Object();
735 
736     private final Object mLock = new Object();
737     private final Map<LeScanCallback, ScanCallback> mLeScanClients;
738     private final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
739                 mMetadataListeners = new HashMap<>();
740     private final Map<BluetoothConnectionCallback, Executor>
741             mBluetoothConnectionCallbackExecutorMap = new HashMap<>();
742 
743     /**
744      * Bluetooth metadata listener. Overrides the default BluetoothMetadataListener
745      * implementation.
746      */
747     @SuppressLint("AndroidFrameworkBluetoothPermission")
748     private final IBluetoothMetadataListener mBluetoothMetadataListener =
749             new IBluetoothMetadataListener.Stub() {
750         @Override
751         public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) {
752             Attributable.setAttributionSource(device, mAttributionSource);
753             synchronized (mMetadataListeners) {
754                 if (mMetadataListeners.containsKey(device)) {
755                     List<Pair<OnMetadataChangedListener, Executor>> list =
756                             mMetadataListeners.get(device);
757                     for (Pair<OnMetadataChangedListener, Executor> pair : list) {
758                         OnMetadataChangedListener listener = pair.first;
759                         Executor executor = pair.second;
760                         executor.execute(() -> {
761                             listener.onMetadataChanged(device, key, value);
762                         });
763                     }
764                 }
765             }
766             return;
767         }
768     };
769 
770     /**
771      * Get a handle to the default local Bluetooth adapter.
772      * <p>
773      * Currently Android only supports one Bluetooth adapter, but the API could
774      * be extended to support more. This will always return the default adapter.
775      * </p>
776      *
777      * @return the default local adapter, or null if Bluetooth is not supported
778      *         on this hardware platform
779      * @deprecated this method will continue to work, but developers are
780      *             strongly encouraged to migrate to using
781      *             {@link BluetoothManager#getAdapter()}, since that approach
782      *             enables support for {@link Context#createAttributionContext}.
783      */
784     @Deprecated
785     @RequiresNoPermission
getDefaultAdapter()786     public static synchronized BluetoothAdapter getDefaultAdapter() {
787         if (sAdapter == null) {
788             sAdapter = createAdapter(BluetoothManager.resolveAttributionSource(null));
789         }
790         return sAdapter;
791     }
792 
793     /** {@hide} */
createAdapter(AttributionSource attributionSource)794     public static BluetoothAdapter createAdapter(AttributionSource attributionSource) {
795         IBinder binder = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
796         if (binder != null) {
797             return new BluetoothAdapter(IBluetoothManager.Stub.asInterface(binder),
798                     attributionSource);
799         } else {
800             Log.e(TAG, "Bluetooth binder is null");
801             return null;
802         }
803     }
804 
805     /**
806      * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
807      */
BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource)808     BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) {
809         mManagerService = Objects.requireNonNull(managerService);
810         mAttributionSource = Objects.requireNonNull(attributionSource);
811         synchronized (mServiceLock.writeLock()) {
812             mService = getBluetoothService(mManagerCallback);
813         }
814         mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
815         mToken = new Binder(DESCRIPTOR);
816     }
817 
818     /**
819      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
820      * address.
821      * <p>Valid Bluetooth hardware addresses must be upper case, in a format
822      * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is
823      * available to validate a Bluetooth address.
824      * <p>A {@link BluetoothDevice} will always be returned for a valid
825      * hardware address, even if this adapter has never seen that device.
826      *
827      * @param address valid Bluetooth MAC address
828      * @throws IllegalArgumentException if address is invalid
829      */
830     @RequiresNoPermission
getRemoteDevice(String address)831     public BluetoothDevice getRemoteDevice(String address) {
832         final BluetoothDevice res = new BluetoothDevice(address);
833         res.setAttributionSource(mAttributionSource);
834         return res;
835     }
836 
837     /**
838      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
839      * address.
840      * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method
841      * expects the address in network byte order (MSB first).
842      * <p>A {@link BluetoothDevice} will always be returned for a valid
843      * hardware address, even if this adapter has never seen that device.
844      *
845      * @param address Bluetooth MAC address (6 bytes)
846      * @throws IllegalArgumentException if address is invalid
847      */
848     @RequiresNoPermission
getRemoteDevice(byte[] address)849     public BluetoothDevice getRemoteDevice(byte[] address) {
850         if (address == null || address.length != 6) {
851             throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
852         }
853         final BluetoothDevice res = new BluetoothDevice(
854                 String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1],
855                         address[2], address[3], address[4], address[5]));
856         res.setAttributionSource(mAttributionSource);
857         return res;
858     }
859 
860     /**
861      * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations.
862      * Will return null if Bluetooth is turned off or if Bluetooth LE Advertising is not
863      * supported on this device.
864      * <p>
865      * Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported
866      * on this device before calling this method.
867      */
868     @RequiresNoPermission
getBluetoothLeAdvertiser()869     public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
870         if (!getLeAccess()) {
871             return null;
872         }
873         synchronized (mLock) {
874             if (mBluetoothLeAdvertiser == null) {
875                 mBluetoothLeAdvertiser = new BluetoothLeAdvertiser(this);
876             }
877             return mBluetoothLeAdvertiser;
878         }
879     }
880 
881     /**
882      * Returns a {@link PeriodicAdvertisingManager} object for Bluetooth LE Periodic Advertising
883      * operations. Will return null if Bluetooth is turned off or if Bluetooth LE Periodic
884      * Advertising is not supported on this device.
885      * <p>
886      * Use {@link #isLePeriodicAdvertisingSupported()} to check whether LE Periodic Advertising is
887      * supported on this device before calling this method.
888      *
889      * @hide
890      */
891     @RequiresNoPermission
getPeriodicAdvertisingManager()892     public PeriodicAdvertisingManager getPeriodicAdvertisingManager() {
893         if (!getLeAccess()) {
894             return null;
895         }
896 
897         if (!isLePeriodicAdvertisingSupported()) {
898             return null;
899         }
900 
901         synchronized (mLock) {
902             if (mPeriodicAdvertisingManager == null) {
903                 mPeriodicAdvertisingManager = new PeriodicAdvertisingManager(this);
904             }
905             return mPeriodicAdvertisingManager;
906         }
907     }
908 
909     /**
910      * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
911      */
912     @RequiresNoPermission
getBluetoothLeScanner()913     public BluetoothLeScanner getBluetoothLeScanner() {
914         if (!getLeAccess()) {
915             return null;
916         }
917         synchronized (mLock) {
918             if (mBluetoothLeScanner == null) {
919                 mBluetoothLeScanner = new BluetoothLeScanner(this);
920             }
921             return mBluetoothLeScanner;
922         }
923     }
924 
925     /**
926      * Return true if Bluetooth is currently enabled and ready for use.
927      * <p>Equivalent to:
928      * <code>getBluetoothState() == STATE_ON</code>
929      *
930      * @return true if the local adapter is turned on
931      */
932     @RequiresLegacyBluetoothPermission
933     @RequiresNoPermission
isEnabled()934     public boolean isEnabled() {
935         return getState() == BluetoothAdapter.STATE_ON;
936     }
937 
938     /**
939      * Return true if Bluetooth LE(Always BLE On feature) is currently
940      * enabled and ready for use
941      * <p>This returns true if current state is either STATE_ON or STATE_BLE_ON
942      *
943      * @return true if the local Bluetooth LE adapter is turned on
944      * @hide
945      */
946     @SystemApi
947     @RequiresNoPermission
isLeEnabled()948     public boolean isLeEnabled() {
949         final int state = getLeState();
950         if (DBG) {
951             Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state));
952         }
953         return (state == BluetoothAdapter.STATE_ON
954                 || state == BluetoothAdapter.STATE_BLE_ON
955                 || state == BluetoothAdapter.STATE_TURNING_ON
956                 || state == BluetoothAdapter.STATE_TURNING_OFF);
957     }
958 
959     /**
960      * Turns off Bluetooth LE which was earlier turned on by calling enableBLE().
961      *
962      * <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition
963      * to STATE_OFF and completely shut-down Bluetooth
964      *
965      * <p> If the Adapter state is STATE_ON, This would unregister the existance of
966      * special Bluetooth LE application and hence the further turning off of Bluetooth
967      * from UI would ensure the complete turn-off of Bluetooth rather than staying back
968      * BLE only state
969      *
970      * <p>This is an asynchronous call: it will return immediately, and
971      * clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
972      * to be notified of subsequent adapter state changes If this call returns
973      * true, then the adapter state will immediately transition from {@link
974      * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
975      * later transition to either {@link #STATE_BLE_ON} or {@link
976      * #STATE_OFF} based on the existance of the further Always BLE ON enabled applications
977      * If this call returns false then there was an
978      * immediate problem that will prevent the QAdapter from being turned off -
979      * such as the QAadapter already being turned off.
980      *
981      * @return true to indicate success, or false on immediate error
982      * @hide
983      */
984     @SystemApi
985     @RequiresBluetoothConnectPermission
986     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
disableBLE()987     public boolean disableBLE() {
988         if (!isBleScanAlwaysAvailable()) {
989             return false;
990         }
991         String packageName = ActivityThread.currentPackageName();
992         try {
993             return mManagerService.disableBle(mAttributionSource, mToken);
994         } catch (RemoteException e) {
995             Log.e(TAG, "", e);
996         }
997         return false;
998     }
999 
1000     /**
1001      * Applications who want to only use Bluetooth Low Energy (BLE) can call enableBLE.
1002      *
1003      * enableBLE registers the existence of an app using only LE functions.
1004      *
1005      * enableBLE may enable Bluetooth to an LE only mode so that an app can use
1006      * LE related features (BluetoothGatt or BluetoothGattServer classes)
1007      *
1008      * If the user disables Bluetooth while an app is registered to use LE only features,
1009      * Bluetooth will remain on in LE only mode for the app.
1010      *
1011      * When Bluetooth is in LE only mode, it is not shown as ON to the UI.
1012      *
1013      * <p>This is an asynchronous call: it returns immediately, and
1014      * clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
1015      * to be notified of adapter state changes.
1016      *
1017      * If this call returns * true, then the adapter state is either in a mode where
1018      * LE is available, or will transition from {@link #STATE_OFF} to {@link #STATE_BLE_TURNING_ON},
1019      * and some time later transition to either {@link #STATE_OFF} or {@link #STATE_BLE_ON}.
1020      *
1021      * If this call returns false then there was an immediate problem that prevents the
1022      * adapter from being turned on - such as Airplane mode.
1023      *
1024      * {@link #ACTION_BLE_STATE_CHANGED} returns the Bluetooth Adapter's various
1025      * states, It includes all the classic Bluetooth Adapter states along with
1026      * internal BLE only states
1027      *
1028      * @return true to indicate Bluetooth LE will be available, or false on immediate error
1029      * @hide
1030      */
1031     @SystemApi
1032     @RequiresBluetoothConnectPermission
1033     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
enableBLE()1034     public boolean enableBLE() {
1035         if (!isBleScanAlwaysAvailable()) {
1036             return false;
1037         }
1038         String packageName = ActivityThread.currentPackageName();
1039         try {
1040             return mManagerService.enableBle(mAttributionSource, mToken);
1041         } catch (RemoteException e) {
1042             Log.e(TAG, "", e);
1043         }
1044 
1045         return false;
1046     }
1047 
1048     private static final String BLUETOOTH_GET_STATE_CACHE_PROPERTY = "cache_key.bluetooth.get_state";
1049 
1050     private final PropertyInvalidatedCache<Void, Integer> mBluetoothGetStateCache =
1051             new PropertyInvalidatedCache<Void, Integer>(
1052                 8, BLUETOOTH_GET_STATE_CACHE_PROPERTY) {
1053                 @Override
1054                 @SuppressLint("AndroidFrameworkRequiresPermission")
1055                 protected Integer recompute(Void query) {
1056                     try {
1057                         return mService.getState();
1058                     } catch (RemoteException e) {
1059                         throw e.rethrowFromSystemServer();
1060                     }
1061                 }
1062             };
1063 
1064     /** @hide */
1065     @RequiresNoPermission
disableBluetoothGetStateCache()1066     public void disableBluetoothGetStateCache() {
1067         mBluetoothGetStateCache.disableLocal();
1068     }
1069 
1070     /** @hide */
invalidateBluetoothGetStateCache()1071     public static void invalidateBluetoothGetStateCache() {
1072         PropertyInvalidatedCache.invalidateCache(BLUETOOTH_GET_STATE_CACHE_PROPERTY);
1073     }
1074 
1075     /**
1076      * Fetch the current bluetooth state.  If the service is down, return
1077      * OFF.
1078      */
1079     @AdapterState
getStateInternal()1080     private int getStateInternal() {
1081         int state = BluetoothAdapter.STATE_OFF;
1082         try {
1083             mServiceLock.readLock().lock();
1084             if (mService != null) {
1085                 state = mBluetoothGetStateCache.query(null);
1086             }
1087         } catch (RuntimeException e) {
1088             if (e.getCause() instanceof RemoteException) {
1089                 Log.e(TAG, "", e.getCause());
1090             } else {
1091                 throw e;
1092             }
1093         } finally {
1094             mServiceLock.readLock().unlock();
1095         }
1096         return state;
1097     }
1098 
1099     /**
1100      * Get the current state of the local Bluetooth adapter.
1101      * <p>Possible return values are
1102      * {@link #STATE_OFF},
1103      * {@link #STATE_TURNING_ON},
1104      * {@link #STATE_ON},
1105      * {@link #STATE_TURNING_OFF}.
1106      *
1107      * @return current state of Bluetooth adapter
1108      */
1109     @RequiresLegacyBluetoothPermission
1110     @RequiresNoPermission
1111     @AdapterState
getState()1112     public int getState() {
1113         int state = getStateInternal();
1114 
1115         // Consider all internal states as OFF
1116         if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON
1117                 || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
1118             if (VDBG) {
1119                 Log.d(TAG, "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF");
1120             }
1121             state = BluetoothAdapter.STATE_OFF;
1122         }
1123         if (VDBG) {
1124             Log.d(TAG, "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState(
1125                     state));
1126         }
1127         return state;
1128     }
1129 
1130     /**
1131      * Get the current state of the local Bluetooth adapter
1132      * <p>This returns current internal state of Adapter including LE ON/OFF
1133      *
1134      * <p>Possible return values are
1135      * {@link #STATE_OFF},
1136      * {@link #STATE_BLE_TURNING_ON},
1137      * {@link #STATE_BLE_ON},
1138      * {@link #STATE_TURNING_ON},
1139      * {@link #STATE_ON},
1140      * {@link #STATE_TURNING_OFF},
1141      * {@link #STATE_BLE_TURNING_OFF}.
1142      *
1143      * @return current state of Bluetooth adapter
1144      * @hide
1145      */
1146     @RequiresLegacyBluetoothPermission
1147     @RequiresNoPermission
1148     @AdapterState
1149     @UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine "
1150             + "whether you can use BLE & BT classic.")
getLeState()1151     public int getLeState() {
1152         int state = getStateInternal();
1153 
1154         if (VDBG) {
1155             Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state));
1156         }
1157         return state;
1158     }
1159 
getLeAccess()1160     boolean getLeAccess() {
1161         if (getLeState() == STATE_ON) {
1162             return true;
1163         } else if (getLeState() == STATE_BLE_ON) {
1164             return true; // TODO: FILTER SYSTEM APPS HERE <--
1165         }
1166 
1167         return false;
1168     }
1169 
1170     /**
1171      * Turn on the local Bluetooth adapter&mdash;do not use without explicit
1172      * user action to turn on Bluetooth.
1173      * <p>This powers on the underlying Bluetooth hardware, and starts all
1174      * Bluetooth system services.
1175      * <p class="caution"><strong>Bluetooth should never be enabled without
1176      * direct user consent</strong>. If you want to turn on Bluetooth in order
1177      * to create a wireless connection, you should use the {@link
1178      * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests
1179      * user permission to turn on Bluetooth. The {@link #enable()} method is
1180      * provided only for applications that include a user interface for changing
1181      * system settings, such as a "power manager" app.</p>
1182      * <p>This is an asynchronous call: it will return immediately, and
1183      * clients should listen for {@link #ACTION_STATE_CHANGED}
1184      * to be notified of subsequent adapter state changes. If this call returns
1185      * true, then the adapter state will immediately transition from {@link
1186      * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
1187      * later transition to either {@link #STATE_OFF} or {@link
1188      * #STATE_ON}. If this call returns false then there was an
1189      * immediate problem that will prevent the adapter from being turned on -
1190      * such as Airplane mode, or the adapter is already turned on.
1191      *
1192      * @return true to indicate adapter startup has begun, or false on immediate error
1193      */
1194     @RequiresLegacyBluetoothAdminPermission
1195     @RequiresBluetoothConnectPermission
1196     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
enable()1197     public boolean enable() {
1198         if (isEnabled()) {
1199             if (DBG) {
1200                 Log.d(TAG, "enable(): BT already enabled!");
1201             }
1202             return true;
1203         }
1204         try {
1205             return mManagerService.enable(mAttributionSource);
1206         } catch (RemoteException e) {
1207             Log.e(TAG, "", e);
1208         }
1209         return false;
1210     }
1211 
1212     /**
1213      * Turn off the local Bluetooth adapter&mdash;do not use without explicit
1214      * user action to turn off Bluetooth.
1215      * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
1216      * system services, and powers down the underlying Bluetooth hardware.
1217      * <p class="caution"><strong>Bluetooth should never be disabled without
1218      * direct user consent</strong>. The {@link #disable()} method is
1219      * provided only for applications that include a user interface for changing
1220      * system settings, such as a "power manager" app.</p>
1221      * <p>This is an asynchronous call: it will return immediately, and
1222      * clients should listen for {@link #ACTION_STATE_CHANGED}
1223      * to be notified of subsequent adapter state changes. If this call returns
1224      * true, then the adapter state will immediately transition from {@link
1225      * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
1226      * later transition to either {@link #STATE_OFF} or {@link
1227      * #STATE_ON}. If this call returns false then there was an
1228      * immediate problem that will prevent the adapter from being turned off -
1229      * such as the adapter already being turned off.
1230      *
1231      * @return true to indicate adapter shutdown has begun, or false on immediate error
1232      */
1233     @RequiresLegacyBluetoothAdminPermission
1234     @RequiresBluetoothConnectPermission
1235     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
disable()1236     public boolean disable() {
1237         try {
1238             return mManagerService.disable(mAttributionSource, true);
1239         } catch (RemoteException e) {
1240             Log.e(TAG, "", e);
1241         }
1242         return false;
1243     }
1244 
1245     /**
1246      * Turn off the local Bluetooth adapter and don't persist the setting.
1247      *
1248      * @return true to indicate adapter shutdown has begun, or false on immediate error
1249      * @hide
1250      */
1251     @UnsupportedAppUsage(trackingBug = 171933273)
1252     @RequiresLegacyBluetoothAdminPermission
1253     @RequiresBluetoothConnectPermission
1254     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
disable(boolean persist)1255     public boolean disable(boolean persist) {
1256 
1257         try {
1258             return mManagerService.disable(mAttributionSource, persist);
1259         } catch (RemoteException e) {
1260             Log.e(TAG, "", e);
1261         }
1262         return false;
1263     }
1264 
1265     /**
1266      * Returns the hardware address of the local Bluetooth adapter.
1267      * <p>For example, "00:11:22:AA:BB:CC".
1268      *
1269      * @return Bluetooth hardware address as string
1270      */
1271     @RequiresLegacyBluetoothPermission
1272     @RequiresBluetoothConnectPermission
1273     @RequiresPermission(allOf = {
1274             android.Manifest.permission.BLUETOOTH_CONNECT,
1275             android.Manifest.permission.LOCAL_MAC_ADDRESS,
1276     })
getAddress()1277     public String getAddress() {
1278         try {
1279             return mManagerService.getAddress(mAttributionSource);
1280         } catch (RemoteException e) {
1281             Log.e(TAG, "", e);
1282         }
1283         return null;
1284     }
1285 
1286     /**
1287      * Get the friendly Bluetooth name of the local Bluetooth adapter.
1288      * <p>This name is visible to remote Bluetooth devices.
1289      *
1290      * @return the Bluetooth name, or null on error
1291      */
1292     @RequiresLegacyBluetoothPermission
1293     @RequiresBluetoothConnectPermission
1294     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getName()1295     public String getName() {
1296         try {
1297             return mManagerService.getName(mAttributionSource);
1298         } catch (RemoteException e) {
1299             Log.e(TAG, "", e);
1300         }
1301         return null;
1302     }
1303 
1304     /** {@hide} */
1305     @RequiresBluetoothAdvertisePermission
1306     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
getNameLengthForAdvertise()1307     public int getNameLengthForAdvertise() {
1308         try {
1309             return mService.getNameLengthForAdvertise(mAttributionSource);
1310         } catch (RemoteException e) {
1311             Log.e(TAG, "", e);
1312         }
1313         return -1;
1314     }
1315 
1316     /**
1317      * Factory reset bluetooth settings.
1318      *
1319      * @return true to indicate that the config file was successfully cleared
1320      * @hide
1321      */
1322     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1323     @RequiresBluetoothConnectPermission
1324     @RequiresPermission(allOf = {
1325             android.Manifest.permission.BLUETOOTH_CONNECT,
1326             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
1327     })
factoryReset()1328     public boolean factoryReset() {
1329         try {
1330             mServiceLock.readLock().lock();
1331             if (mService != null && mService.factoryReset(mAttributionSource)
1332                     && mManagerService != null
1333                     && mManagerService.onFactoryReset(mAttributionSource)) {
1334                 return true;
1335             }
1336             Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later");
1337             SystemProperties.set("persist.bluetooth.factoryreset", "true");
1338         } catch (RemoteException e) {
1339             Log.e(TAG, "", e);
1340         } finally {
1341             mServiceLock.readLock().unlock();
1342         }
1343         return false;
1344     }
1345 
1346     /**
1347      * Get the UUIDs supported by the local Bluetooth adapter.
1348      *
1349      * @return the UUIDs supported by the local Bluetooth Adapter.
1350      * @hide
1351      */
1352     @UnsupportedAppUsage
1353     @RequiresLegacyBluetoothPermission
1354     @RequiresBluetoothConnectPermission
1355     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getUuids()1356     public @Nullable ParcelUuid[] getUuids() {
1357         if (getState() != STATE_ON) {
1358             return null;
1359         }
1360         try {
1361             mServiceLock.readLock().lock();
1362             if (mService != null) {
1363                 return mService.getUuids(mAttributionSource);
1364             }
1365         } catch (RemoteException e) {
1366             Log.e(TAG, "", e);
1367         } finally {
1368             mServiceLock.readLock().unlock();
1369         }
1370         return null;
1371     }
1372 
1373     /**
1374      * Set the friendly Bluetooth name of the local Bluetooth adapter.
1375      * <p>This name is visible to remote Bluetooth devices.
1376      * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8
1377      * encoding, although many remote devices can only display the first
1378      * 40 characters, and some may be limited to just 20.
1379      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1380      * will return false. After turning on Bluetooth,
1381      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1382      * to get the updated value.
1383      *
1384      * @param name a valid Bluetooth name
1385      * @return true if the name was set, false otherwise
1386      */
1387     @RequiresLegacyBluetoothAdminPermission
1388     @RequiresBluetoothConnectPermission
1389     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
setName(String name)1390     public boolean setName(String name) {
1391         if (getState() != STATE_ON) {
1392             return false;
1393         }
1394         try {
1395             mServiceLock.readLock().lock();
1396             if (mService != null) {
1397                 return mService.setName(name, mAttributionSource);
1398             }
1399         } catch (RemoteException e) {
1400             Log.e(TAG, "", e);
1401         } finally {
1402             mServiceLock.readLock().unlock();
1403         }
1404         return false;
1405     }
1406 
1407     /**
1408      * Returns the {@link BluetoothClass} Bluetooth Class of Device (CoD) of the local Bluetooth
1409      * adapter.
1410      *
1411      * @return {@link BluetoothClass} Bluetooth CoD of local Bluetooth device.
1412      *
1413      * @hide
1414      */
1415     @RequiresLegacyBluetoothAdminPermission
1416     @RequiresBluetoothConnectPermission
1417     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getBluetoothClass()1418     public BluetoothClass getBluetoothClass() {
1419         if (getState() != STATE_ON) {
1420             return null;
1421         }
1422         try {
1423             mServiceLock.readLock().lock();
1424             if (mService != null) {
1425                 return mService.getBluetoothClass(mAttributionSource);
1426             }
1427         } catch (RemoteException e) {
1428             Log.e(TAG, "", e);
1429         } finally {
1430             mServiceLock.readLock().unlock();
1431         }
1432         return null;
1433     }
1434 
1435     /**
1436      * Sets the {@link BluetoothClass} Bluetooth Class of Device (CoD) of the local Bluetooth
1437      * adapter.
1438      *
1439      * <p>Note: This value persists across system reboot.
1440      *
1441      * @param bluetoothClass {@link BluetoothClass} to set the local Bluetooth adapter to.
1442      * @return true if successful, false if unsuccessful.
1443      *
1444      * @hide
1445      */
1446     @RequiresBluetoothConnectPermission
1447     @RequiresPermission(allOf = {
1448             android.Manifest.permission.BLUETOOTH_CONNECT,
1449             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
1450     })
setBluetoothClass(BluetoothClass bluetoothClass)1451     public boolean setBluetoothClass(BluetoothClass bluetoothClass) {
1452         if (getState() != STATE_ON) {
1453             return false;
1454         }
1455         try {
1456             mServiceLock.readLock().lock();
1457             if (mService != null) {
1458                 return mService.setBluetoothClass(bluetoothClass, mAttributionSource);
1459             }
1460         } catch (RemoteException e) {
1461             Log.e(TAG, "", e);
1462         } finally {
1463             mServiceLock.readLock().unlock();
1464         }
1465         return false;
1466     }
1467 
1468     /**
1469      * Returns the Input/Output capability of the device for classic Bluetooth.
1470      *
1471      * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
1472      *         {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE},
1473      *         {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}.
1474      *
1475      * @hide
1476      */
1477     @RequiresLegacyBluetoothAdminPermission
1478     @RequiresBluetoothConnectPermission
1479     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
1480     @IoCapability
getIoCapability()1481     public int getIoCapability() {
1482         if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
1483         try {
1484             mServiceLock.readLock().lock();
1485             if (mService != null) return mService.getIoCapability(mAttributionSource);
1486         } catch (RemoteException e) {
1487             Log.e(TAG, e.getMessage(), e);
1488         } finally {
1489             mServiceLock.readLock().unlock();
1490         }
1491         return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
1492     }
1493 
1494     /**
1495      * Sets the Input/Output capability of the device for classic Bluetooth.
1496      *
1497      * <p>Changing the Input/Output capability of a device only takes effect on restarting the
1498      * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()}
1499      * and {@link BluetoothAdapter#enable()} to see the changes.
1500      *
1501      * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
1502      *                   {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN},
1503      *                   {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}.
1504      *
1505      * @hide
1506      */
1507     @RequiresBluetoothConnectPermission
1508     @RequiresPermission(allOf = {
1509             android.Manifest.permission.BLUETOOTH_CONNECT,
1510             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
1511     })
setIoCapability(@oCapability int capability)1512     public boolean setIoCapability(@IoCapability int capability) {
1513         if (getState() != STATE_ON) return false;
1514         try {
1515             mServiceLock.readLock().lock();
1516             if (mService != null) return mService.setIoCapability(capability, mAttributionSource);
1517         } catch (RemoteException e) {
1518             Log.e(TAG, e.getMessage(), e);
1519         } finally {
1520             mServiceLock.readLock().unlock();
1521         }
1522         return false;
1523     }
1524 
1525     /**
1526      * Returns the Input/Output capability of the device for BLE operations.
1527      *
1528      * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
1529      *         {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE},
1530      *         {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}.
1531      *
1532      * @hide
1533      */
1534     @RequiresLegacyBluetoothAdminPermission
1535     @RequiresBluetoothConnectPermission
1536     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
1537     @IoCapability
getLeIoCapability()1538     public int getLeIoCapability() {
1539         if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
1540         try {
1541             mServiceLock.readLock().lock();
1542             if (mService != null) return mService.getLeIoCapability(mAttributionSource);
1543         } catch (RemoteException e) {
1544             Log.e(TAG, e.getMessage(), e);
1545         } finally {
1546             mServiceLock.readLock().unlock();
1547         }
1548         return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
1549     }
1550 
1551     /**
1552      * Sets the Input/Output capability of the device for BLE operations.
1553      *
1554      * <p>Changing the Input/Output capability of a device only takes effect on restarting the
1555      * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()}
1556      * and {@link BluetoothAdapter#enable()} to see the changes.
1557      *
1558      * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
1559      *                   {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN},
1560      *                   {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}.
1561      *
1562      * @hide
1563      */
1564     @RequiresBluetoothConnectPermission
1565     @RequiresPermission(allOf = {
1566             android.Manifest.permission.BLUETOOTH_CONNECT,
1567             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
1568     })
setLeIoCapability(@oCapability int capability)1569     public boolean setLeIoCapability(@IoCapability int capability) {
1570         if (getState() != STATE_ON) return false;
1571         try {
1572             mServiceLock.readLock().lock();
1573             if (mService != null) return mService.setLeIoCapability(capability, mAttributionSource);
1574         } catch (RemoteException e) {
1575             Log.e(TAG, e.getMessage(), e);
1576         } finally {
1577             mServiceLock.readLock().unlock();
1578         }
1579         return false;
1580     }
1581 
1582     /**
1583      * Get the current Bluetooth scan mode of the local Bluetooth adapter.
1584      * <p>The Bluetooth scan mode determines if the local adapter is
1585      * connectable and/or discoverable from remote Bluetooth devices.
1586      * <p>Possible values are:
1587      * {@link #SCAN_MODE_NONE},
1588      * {@link #SCAN_MODE_CONNECTABLE},
1589      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
1590      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1591      * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth,
1592      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1593      * to get the updated value.
1594      *
1595      * @return scan mode
1596      */
1597     @RequiresLegacyBluetoothPermission
1598     @RequiresBluetoothScanPermission
1599     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
1600     @ScanMode
getScanMode()1601     public int getScanMode() {
1602         if (getState() != STATE_ON) {
1603             return SCAN_MODE_NONE;
1604         }
1605         try {
1606             mServiceLock.readLock().lock();
1607             if (mService != null) {
1608                 return mService.getScanMode(mAttributionSource);
1609             }
1610         } catch (RemoteException e) {
1611             Log.e(TAG, "", e);
1612         } finally {
1613             mServiceLock.readLock().unlock();
1614         }
1615         return SCAN_MODE_NONE;
1616     }
1617 
1618     /**
1619      * Set the Bluetooth scan mode of the local Bluetooth adapter.
1620      * <p>The Bluetooth scan mode determines if the local adapter is
1621      * connectable and/or discoverable from remote Bluetooth devices.
1622      * <p>For privacy reasons, discoverable mode is automatically turned off
1623      * after <code>durationMillis</code> milliseconds. For example, 120000 milliseconds should be
1624      * enough for a remote device to initiate and complete its discovery process.
1625      * <p>Valid scan mode values are:
1626      * {@link #SCAN_MODE_NONE},
1627      * {@link #SCAN_MODE_CONNECTABLE},
1628      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
1629      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1630      * will return false. After turning on Bluetooth,
1631      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1632      * to get the updated value.
1633      * <p>Applications cannot set the scan mode. They should use
1634      * <code>startActivityForResult(
1635      * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
1636      * </code>instead.
1637      *
1638      * @param mode valid scan mode
1639      * @param durationMillis time in milliseconds to apply scan mode, only used for {@link
1640      * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}
1641      * @return true if the scan mode was set, false otherwise
1642      * @hide
1643      */
1644     @UnsupportedAppUsage(publicAlternatives = "Use {@link #ACTION_REQUEST_DISCOVERABLE}, which "
1645             + "shows UI that confirms the user wants to go into discoverable mode.")
1646     @RequiresLegacyBluetoothPermission
1647     @RequiresBluetoothScanPermission
1648     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
setScanMode(@canMode int mode, long durationMillis)1649     public boolean setScanMode(@ScanMode int mode, long durationMillis) {
1650         if (getState() != STATE_ON) {
1651             return false;
1652         }
1653         try {
1654             mServiceLock.readLock().lock();
1655             if (mService != null) {
1656                 int durationSeconds = Math.toIntExact(durationMillis / 1000);
1657                 return mService.setScanMode(mode, durationSeconds, mAttributionSource);
1658             }
1659         } catch (RemoteException e) {
1660             Log.e(TAG, "", e);
1661         } catch (ArithmeticException ex) {
1662             Log.e(TAG, "setScanMode: Duration in seconds outside of the bounds of an int");
1663             throw new IllegalArgumentException("Duration not in bounds. In seconds, the "
1664                     + "durationMillis must be in the range of an int");
1665         } finally {
1666             mServiceLock.readLock().unlock();
1667         }
1668         return false;
1669     }
1670 
1671     /**
1672      * Set the Bluetooth scan mode of the local Bluetooth adapter.
1673      * <p>The Bluetooth scan mode determines if the local adapter is
1674      * connectable and/or discoverable from remote Bluetooth devices.
1675      * <p>For privacy reasons, discoverable mode is automatically turned off
1676      * after <code>duration</code> seconds. For example, 120 seconds should be
1677      * enough for a remote device to initiate and complete its discovery
1678      * process.
1679      * <p>Valid scan mode values are:
1680      * {@link #SCAN_MODE_NONE},
1681      * {@link #SCAN_MODE_CONNECTABLE},
1682      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
1683      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1684      * will return false. After turning on Bluetooth,
1685      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1686      * to get the updated value.
1687      * <p>Applications cannot set the scan mode. They should use
1688      * <code>startActivityForResult(
1689      * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
1690      * </code>instead.
1691      *
1692      * @param mode valid scan mode
1693      * @return true if the scan mode was set, false otherwise
1694      * @hide
1695      */
1696     @UnsupportedAppUsage
1697     @RequiresLegacyBluetoothPermission
1698     @RequiresBluetoothScanPermission
1699     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
setScanMode(@canMode int mode)1700     public boolean setScanMode(@ScanMode int mode) {
1701         if (getState() != STATE_ON) {
1702             return false;
1703         }
1704         try {
1705             mServiceLock.readLock().lock();
1706             if (mService != null) {
1707                 return mService.setScanMode(mode, getDiscoverableTimeout(), mAttributionSource);
1708             }
1709         } catch (RemoteException e) {
1710             Log.e(TAG, "", e);
1711         } finally {
1712             mServiceLock.readLock().unlock();
1713         }
1714         return false;
1715     }
1716 
1717     /** @hide */
1718     @UnsupportedAppUsage
1719     @RequiresBluetoothScanPermission
1720     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
getDiscoverableTimeout()1721     public int getDiscoverableTimeout() {
1722         if (getState() != STATE_ON) {
1723             return -1;
1724         }
1725         try {
1726             mServiceLock.readLock().lock();
1727             if (mService != null) {
1728                 return mService.getDiscoverableTimeout(mAttributionSource);
1729             }
1730         } catch (RemoteException e) {
1731             Log.e(TAG, "", e);
1732         } finally {
1733             mServiceLock.readLock().unlock();
1734         }
1735         return -1;
1736     }
1737 
1738     /** @hide */
1739     @UnsupportedAppUsage
1740     @RequiresBluetoothScanPermission
1741     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
setDiscoverableTimeout(int timeout)1742     public void setDiscoverableTimeout(int timeout) {
1743         if (getState() != STATE_ON) {
1744             return;
1745         }
1746         try {
1747             mServiceLock.readLock().lock();
1748             if (mService != null) {
1749                 mService.setDiscoverableTimeout(timeout, mAttributionSource);
1750             }
1751         } catch (RemoteException e) {
1752             Log.e(TAG, "", e);
1753         } finally {
1754             mServiceLock.readLock().unlock();
1755         }
1756     }
1757 
1758     /**
1759      * Get the end time of the latest remote device discovery process.
1760      *
1761      * @return the latest time that the bluetooth adapter was/will be in discovery mode, in
1762      * milliseconds since the epoch. This time can be in the future if {@link #startDiscovery()} has
1763      * been called recently.
1764      * @hide
1765      */
1766     @SystemApi
1767     @RequiresBluetoothConnectPermission
1768     @RequiresPermission(allOf = {
1769             android.Manifest.permission.BLUETOOTH_CONNECT,
1770             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
1771     })
getDiscoveryEndMillis()1772     public long getDiscoveryEndMillis() {
1773         try {
1774             mServiceLock.readLock().lock();
1775             if (mService != null) {
1776                 return mService.getDiscoveryEndMillis(mAttributionSource);
1777             }
1778         } catch (RemoteException e) {
1779             Log.e(TAG, "", e);
1780         } finally {
1781             mServiceLock.readLock().unlock();
1782         }
1783         return -1;
1784     }
1785 
1786     /**
1787      * Start the remote device discovery process.
1788      * <p>The discovery process usually involves an inquiry scan of about 12
1789      * seconds, followed by a page scan of each new device to retrieve its
1790      * Bluetooth name.
1791      * <p>This is an asynchronous call, it will return immediately. Register
1792      * for {@link #ACTION_DISCOVERY_STARTED} and {@link
1793      * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the
1794      * discovery starts and completes. Register for {@link
1795      * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices
1796      * are found.
1797      * <p>Device discovery is a heavyweight procedure. New connections to
1798      * remote Bluetooth devices should not be attempted while discovery is in
1799      * progress, and existing connections will experience limited bandwidth
1800      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
1801      * discovery. Discovery is not managed by the Activity,
1802      * but is run as a system service, so an application should always call
1803      * {@link BluetoothAdapter#cancelDiscovery()} even if it
1804      * did not directly request a discovery, just to be sure.
1805      * <p>Device discovery will only find remote devices that are currently
1806      * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are
1807      * not discoverable by default, and need to be entered into a special mode.
1808      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1809      * will return false. After turning on Bluetooth, wait for {@link #ACTION_STATE_CHANGED}
1810      * with {@link #STATE_ON} to get the updated value.
1811      * <p>If a device is currently bonding, this request will be queued and executed once that
1812      * device has finished bonding. If a request is already queued, this request will be ignored.
1813      *
1814      * @return true on success, false on error
1815      */
1816     @RequiresLegacyBluetoothAdminPermission
1817     @RequiresBluetoothScanPermission
1818     @RequiresBluetoothLocationPermission
1819     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
startDiscovery()1820     public boolean startDiscovery() {
1821         if (getState() != STATE_ON) {
1822             return false;
1823         }
1824         try {
1825             mServiceLock.readLock().lock();
1826             if (mService != null) {
1827                 return mService.startDiscovery(mAttributionSource);
1828             }
1829         } catch (RemoteException e) {
1830             Log.e(TAG, "", e);
1831         } finally {
1832             mServiceLock.readLock().unlock();
1833         }
1834         return false;
1835     }
1836 
1837     /**
1838      * Cancel the current device discovery process.
1839      * <p>Because discovery is a heavyweight procedure for the Bluetooth
1840      * adapter, this method should always be called before attempting to connect
1841      * to a remote device with {@link
1842      * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by
1843      * the  Activity, but is run as a system service, so an application should
1844      * always call cancel discovery even if it did not directly request a
1845      * discovery, just to be sure.
1846      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1847      * will return false. After turning on Bluetooth,
1848      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1849      * to get the updated value.
1850      *
1851      * @return true on success, false on error
1852      */
1853     @RequiresLegacyBluetoothAdminPermission
1854     @RequiresBluetoothScanPermission
1855     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
cancelDiscovery()1856     public boolean cancelDiscovery() {
1857         if (getState() != STATE_ON) {
1858             return false;
1859         }
1860         try {
1861             mServiceLock.readLock().lock();
1862             if (mService != null) {
1863                 return mService.cancelDiscovery(mAttributionSource);
1864             }
1865         } catch (RemoteException e) {
1866             Log.e(TAG, "", e);
1867         } finally {
1868             mServiceLock.readLock().unlock();
1869         }
1870         return false;
1871     }
1872 
1873     /**
1874      * Return true if the local Bluetooth adapter is currently in the device
1875      * discovery process.
1876      * <p>Device discovery is a heavyweight procedure. New connections to
1877      * remote Bluetooth devices should not be attempted while discovery is in
1878      * progress, and existing connections will experience limited bandwidth
1879      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
1880      * discovery.
1881      * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED}
1882      * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery
1883      * starts or completes.
1884      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1885      * will return false. After turning on Bluetooth,
1886      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1887      * to get the updated value.
1888      *
1889      * @return true if discovering
1890      */
1891     @RequiresLegacyBluetoothPermission
1892     @RequiresBluetoothScanPermission
1893     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
isDiscovering()1894     public boolean isDiscovering() {
1895         if (getState() != STATE_ON) {
1896             return false;
1897         }
1898         try {
1899             mServiceLock.readLock().lock();
1900             if (mService != null) {
1901                 return mService.isDiscovering(mAttributionSource);
1902             }
1903         } catch (RemoteException e) {
1904             Log.e(TAG, "", e);
1905         } finally {
1906             mServiceLock.readLock().unlock();
1907         }
1908         return false;
1909     }
1910 
1911     /**
1912      * Removes the active device for the grouping of @ActiveDeviceUse specified
1913      *
1914      * @param profiles represents the purpose for which we are setting this as the active device.
1915      *                 Possible values are:
1916      *                 {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO},
1917      *                 {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL},
1918      *                 {@link BluetoothAdapter#ACTIVE_DEVICE_ALL}
1919      * @return false on immediate error, true otherwise
1920      * @throws IllegalArgumentException if device is null or profiles is not one of
1921      * {@link ActiveDeviceUse}
1922      * @hide
1923      */
1924     @SystemApi
1925     @RequiresBluetoothConnectPermission
1926     @RequiresPermission(allOf = {
1927             android.Manifest.permission.BLUETOOTH_CONNECT,
1928             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
1929             android.Manifest.permission.MODIFY_PHONE_STATE,
1930     })
removeActiveDevice(@ctiveDeviceUse int profiles)1931     public boolean removeActiveDevice(@ActiveDeviceUse int profiles) {
1932         if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL
1933                 && profiles != ACTIVE_DEVICE_ALL) {
1934             Log.e(TAG, "Invalid profiles param value in removeActiveDevice");
1935             throw new IllegalArgumentException("Profiles must be one of "
1936                     + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, "
1937                     + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or "
1938                     + "BluetoothAdapter.ACTIVE_DEVICE_ALL");
1939         }
1940         try {
1941             mServiceLock.readLock().lock();
1942             if (mService != null) {
1943                 if (DBG) Log.d(TAG, "removeActiveDevice, profiles: " + profiles);
1944                 return mService.removeActiveDevice(profiles, mAttributionSource);
1945             }
1946         } catch (RemoteException e) {
1947             Log.e(TAG, "", e);
1948         } finally {
1949             mServiceLock.readLock().unlock();
1950         }
1951 
1952         return false;
1953     }
1954 
1955     /**
1956      * Sets device as the active devices for the profiles passed into the function
1957      *
1958      * @param device is the remote bluetooth device
1959      * @param profiles represents the purpose for which we are setting this as the active device.
1960      *                 Possible values are:
1961      *                 {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO},
1962      *                 {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL},
1963      *                 {@link BluetoothAdapter#ACTIVE_DEVICE_ALL}
1964      * @return false on immediate error, true otherwise
1965      * @throws IllegalArgumentException if device is null or profiles is not one of
1966      * {@link ActiveDeviceUse}
1967      * @hide
1968      */
1969     @SystemApi
1970     @RequiresBluetoothConnectPermission
1971     @RequiresPermission(allOf = {
1972             android.Manifest.permission.BLUETOOTH_CONNECT,
1973             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
1974             android.Manifest.permission.MODIFY_PHONE_STATE,
1975     })
setActiveDevice(@onNull BluetoothDevice device, @ActiveDeviceUse int profiles)1976     public boolean setActiveDevice(@NonNull BluetoothDevice device,
1977             @ActiveDeviceUse int profiles) {
1978         if (device == null) {
1979             Log.e(TAG, "setActiveDevice: Null device passed as parameter");
1980             throw new IllegalArgumentException("device cannot be null");
1981         }
1982         if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL
1983                 && profiles != ACTIVE_DEVICE_ALL) {
1984             Log.e(TAG, "Invalid profiles param value in setActiveDevice");
1985             throw new IllegalArgumentException("Profiles must be one of "
1986                     + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, "
1987                     + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or "
1988                     + "BluetoothAdapter.ACTIVE_DEVICE_ALL");
1989         }
1990         try {
1991             mServiceLock.readLock().lock();
1992             if (mService != null) {
1993                 if (DBG) {
1994                     Log.d(TAG, "setActiveDevice, device: " + device + ", profiles: " + profiles);
1995                 }
1996                 return mService.setActiveDevice(device, profiles, mAttributionSource);
1997             }
1998         } catch (RemoteException e) {
1999             Log.e(TAG, "", e);
2000         } finally {
2001             mServiceLock.readLock().unlock();
2002         }
2003 
2004         return false;
2005     }
2006 
2007     /**
2008      * Connects all enabled and supported bluetooth profiles between the local and remote device.
2009      * Connection is asynchronous and you should listen to each profile's broadcast intent
2010      * ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful. For example,
2011      * to verify a2dp is connected, you would listen for
2012      * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED}
2013      *
2014      * @param device is the remote device with which to connect these profiles
2015      * @return true if message sent to try to connect all profiles, false if an error occurred
2016      *
2017      * @hide
2018      */
2019     @RequiresBluetoothConnectPermission
2020     @RequiresPermission(allOf = {
2021             android.Manifest.permission.BLUETOOTH_CONNECT,
2022             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
2023             android.Manifest.permission.MODIFY_PHONE_STATE,
2024     })
connectAllEnabledProfiles(@onNull BluetoothDevice device)2025     public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) {
2026         try {
2027             mServiceLock.readLock().lock();
2028             if (mService != null) {
2029                 return mService.connectAllEnabledProfiles(device, mAttributionSource);
2030             }
2031         } catch (RemoteException e) {
2032             Log.e(TAG, "", e);
2033         } finally {
2034             mServiceLock.readLock().unlock();
2035         }
2036 
2037         return false;
2038     }
2039 
2040     /**
2041      * Disconnects all enabled and supported bluetooth profiles between the local and remote device.
2042      * Disconnection is asynchronous and you should listen to each profile's broadcast intent
2043      * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example,
2044      * to verify a2dp is disconnected, you would listen for
2045      * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED}
2046      *
2047      * @param device is the remote device with which to disconnect these profiles
2048      * @return true if message sent to try to disconnect all profiles, false if an error occurred
2049      *
2050      * @hide
2051      */
2052     @RequiresBluetoothConnectPermission
2053     @RequiresPermission(allOf = {
2054             android.Manifest.permission.BLUETOOTH_CONNECT,
2055             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
2056     })
disconnectAllEnabledProfiles(@onNull BluetoothDevice device)2057     public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) {
2058         try {
2059             mServiceLock.readLock().lock();
2060             if (mService != null) {
2061                 return mService.disconnectAllEnabledProfiles(device, mAttributionSource);
2062             }
2063         } catch (RemoteException e) {
2064             Log.e(TAG, "", e);
2065         } finally {
2066             mServiceLock.readLock().unlock();
2067         }
2068 
2069         return false;
2070     }
2071 
2072     /**
2073      * Return true if the multi advertisement is supported by the chipset
2074      *
2075      * @return true if Multiple Advertisement feature is supported
2076      */
2077     @RequiresLegacyBluetoothPermission
2078     @RequiresNoPermission
isMultipleAdvertisementSupported()2079     public boolean isMultipleAdvertisementSupported() {
2080         if (getState() != STATE_ON) {
2081             return false;
2082         }
2083         try {
2084             mServiceLock.readLock().lock();
2085             if (mService != null) {
2086                 return mService.isMultiAdvertisementSupported();
2087             }
2088         } catch (RemoteException e) {
2089             Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e);
2090         } finally {
2091             mServiceLock.readLock().unlock();
2092         }
2093         return false;
2094     }
2095 
2096     /**
2097      * Returns {@code true} if BLE scan is always available, {@code false} otherwise. <p>
2098      *
2099      * If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan} and
2100      * fetch scan results even when Bluetooth is turned off.<p>
2101      *
2102      * To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}.
2103      *
2104      * @hide
2105      */
2106     @SystemApi
2107     @RequiresNoPermission
isBleScanAlwaysAvailable()2108     public boolean isBleScanAlwaysAvailable() {
2109         try {
2110             return mManagerService.isBleScanAlwaysAvailable();
2111         } catch (RemoteException e) {
2112             Log.e(TAG, "remote expection when calling isBleScanAlwaysAvailable", e);
2113             return false;
2114         }
2115     }
2116 
2117     private static final String BLUETOOTH_FILTERING_CACHE_PROPERTY =
2118             "cache_key.bluetooth.is_offloaded_filtering_supported";
2119     private final PropertyInvalidatedCache<Void, Boolean> mBluetoothFilteringCache =
2120             new PropertyInvalidatedCache<Void, Boolean>(
2121                 8, BLUETOOTH_FILTERING_CACHE_PROPERTY) {
2122                 @Override
2123                 @SuppressLint("AndroidFrameworkRequiresPermission")
2124                 protected Boolean recompute(Void query) {
2125                     try {
2126                         mServiceLock.readLock().lock();
2127                         if (mService != null) {
2128                             return mService.isOffloadedFilteringSupported();
2129                         }
2130                     } catch (RemoteException e) {
2131                         Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e);
2132                     } finally {
2133                         mServiceLock.readLock().unlock();
2134                     }
2135                     return false;
2136 
2137                 }
2138             };
2139 
2140     /** @hide */
2141     @RequiresNoPermission
disableIsOffloadedFilteringSupportedCache()2142     public void disableIsOffloadedFilteringSupportedCache() {
2143         mBluetoothFilteringCache.disableLocal();
2144     }
2145 
2146     /** @hide */
invalidateIsOffloadedFilteringSupportedCache()2147     public static void invalidateIsOffloadedFilteringSupportedCache() {
2148         PropertyInvalidatedCache.invalidateCache(BLUETOOTH_FILTERING_CACHE_PROPERTY);
2149     }
2150 
2151     /**
2152      * Return true if offloaded filters are supported
2153      *
2154      * @return true if chipset supports on-chip filtering
2155      */
2156     @RequiresLegacyBluetoothPermission
2157     @RequiresNoPermission
isOffloadedFilteringSupported()2158     public boolean isOffloadedFilteringSupported() {
2159         if (!getLeAccess()) {
2160             return false;
2161         }
2162         return mBluetoothFilteringCache.query(null);
2163     }
2164 
2165     /**
2166      * Return true if offloaded scan batching is supported
2167      *
2168      * @return true if chipset supports on-chip scan batching
2169      */
2170     @RequiresLegacyBluetoothPermission
2171     @RequiresNoPermission
isOffloadedScanBatchingSupported()2172     public boolean isOffloadedScanBatchingSupported() {
2173         if (!getLeAccess()) {
2174             return false;
2175         }
2176         try {
2177             mServiceLock.readLock().lock();
2178             if (mService != null) {
2179                 return mService.isOffloadedScanBatchingSupported();
2180             }
2181         } catch (RemoteException e) {
2182             Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e);
2183         } finally {
2184             mServiceLock.readLock().unlock();
2185         }
2186         return false;
2187     }
2188 
2189     /**
2190      * Return true if LE 2M PHY feature is supported.
2191      *
2192      * @return true if chipset supports LE 2M PHY feature
2193      */
2194     @RequiresLegacyBluetoothPermission
2195     @RequiresNoPermission
isLe2MPhySupported()2196     public boolean isLe2MPhySupported() {
2197         if (!getLeAccess()) {
2198             return false;
2199         }
2200         try {
2201             mServiceLock.readLock().lock();
2202             if (mService != null) {
2203                 return mService.isLe2MPhySupported();
2204             }
2205         } catch (RemoteException e) {
2206             Log.e(TAG, "failed to get isExtendedAdvertisingSupported, error: ", e);
2207         } finally {
2208             mServiceLock.readLock().unlock();
2209         }
2210         return false;
2211     }
2212 
2213     /**
2214      * Return true if LE Coded PHY feature is supported.
2215      *
2216      * @return true if chipset supports LE Coded PHY feature
2217      */
2218     @RequiresLegacyBluetoothPermission
2219     @RequiresNoPermission
isLeCodedPhySupported()2220     public boolean isLeCodedPhySupported() {
2221         if (!getLeAccess()) {
2222             return false;
2223         }
2224         try {
2225             mServiceLock.readLock().lock();
2226             if (mService != null) {
2227                 return mService.isLeCodedPhySupported();
2228             }
2229         } catch (RemoteException e) {
2230             Log.e(TAG, "failed to get isLeCodedPhySupported, error: ", e);
2231         } finally {
2232             mServiceLock.readLock().unlock();
2233         }
2234         return false;
2235     }
2236 
2237     /**
2238      * Return true if LE Extended Advertising feature is supported.
2239      *
2240      * @return true if chipset supports LE Extended Advertising feature
2241      */
2242     @RequiresLegacyBluetoothPermission
2243     @RequiresNoPermission
isLeExtendedAdvertisingSupported()2244     public boolean isLeExtendedAdvertisingSupported() {
2245         if (!getLeAccess()) {
2246             return false;
2247         }
2248         try {
2249             mServiceLock.readLock().lock();
2250             if (mService != null) {
2251                 return mService.isLeExtendedAdvertisingSupported();
2252             }
2253         } catch (RemoteException e) {
2254             Log.e(TAG, "failed to get isLeExtendedAdvertisingSupported, error: ", e);
2255         } finally {
2256             mServiceLock.readLock().unlock();
2257         }
2258         return false;
2259     }
2260 
2261     /**
2262      * Return true if LE Periodic Advertising feature is supported.
2263      *
2264      * @return true if chipset supports LE Periodic Advertising feature
2265      */
2266     @RequiresLegacyBluetoothPermission
2267     @RequiresNoPermission
isLePeriodicAdvertisingSupported()2268     public boolean isLePeriodicAdvertisingSupported() {
2269         if (!getLeAccess()) {
2270             return false;
2271         }
2272         try {
2273             mServiceLock.readLock().lock();
2274             if (mService != null) {
2275                 return mService.isLePeriodicAdvertisingSupported();
2276             }
2277         } catch (RemoteException e) {
2278             Log.e(TAG, "failed to get isLePeriodicAdvertisingSupported, error: ", e);
2279         } finally {
2280             mServiceLock.readLock().unlock();
2281         }
2282         return false;
2283     }
2284 
2285     /**
2286      * Return the maximum LE advertising data length in bytes,
2287      * if LE Extended Advertising feature is supported, 0 otherwise.
2288      *
2289      * @return the maximum LE advertising data length.
2290      */
2291     @RequiresLegacyBluetoothPermission
2292     @RequiresNoPermission
getLeMaximumAdvertisingDataLength()2293     public int getLeMaximumAdvertisingDataLength() {
2294         if (!getLeAccess()) {
2295             return 0;
2296         }
2297         try {
2298             mServiceLock.readLock().lock();
2299             if (mService != null) {
2300                 return mService.getLeMaximumAdvertisingDataLength();
2301             }
2302         } catch (RemoteException e) {
2303             Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e);
2304         } finally {
2305             mServiceLock.readLock().unlock();
2306         }
2307         return 0;
2308     }
2309 
2310     /**
2311      * Return true if Hearing Aid Profile is supported.
2312      *
2313      * @return true if phone supports Hearing Aid Profile
2314      */
2315     @RequiresNoPermission
isHearingAidProfileSupported()2316     private boolean isHearingAidProfileSupported() {
2317         try {
2318             return mManagerService.isHearingAidProfileSupported();
2319         } catch (RemoteException e) {
2320             Log.e(TAG, "remote expection when calling isHearingAidProfileSupported", e);
2321             return false;
2322         }
2323     }
2324 
2325     /**
2326      * Get the maximum number of connected audio devices.
2327      *
2328      * @return the maximum number of connected audio devices
2329      * @hide
2330      */
2331     @RequiresLegacyBluetoothPermission
2332     @RequiresBluetoothConnectPermission
2333     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getMaxConnectedAudioDevices()2334     public int getMaxConnectedAudioDevices() {
2335         try {
2336             mServiceLock.readLock().lock();
2337             if (mService != null) {
2338                 return mService.getMaxConnectedAudioDevices(mAttributionSource);
2339             }
2340         } catch (RemoteException e) {
2341             Log.e(TAG, "failed to get getMaxConnectedAudioDevices, error: ", e);
2342         } finally {
2343             mServiceLock.readLock().unlock();
2344         }
2345         return 1;
2346     }
2347 
2348     /**
2349      * Return true if hardware has entries available for matching beacons
2350      *
2351      * @return true if there are hw entries available for matching beacons
2352      * @hide
2353      */
2354     @RequiresBluetoothConnectPermission
2355     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
isHardwareTrackingFiltersAvailable()2356     public boolean isHardwareTrackingFiltersAvailable() {
2357         if (!getLeAccess()) {
2358             return false;
2359         }
2360         try {
2361             IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
2362             if (iGatt == null) {
2363                 // BLE is not supported
2364                 return false;
2365             }
2366             return (iGatt.numHwTrackFiltersAvailable(mAttributionSource) != 0);
2367         } catch (RemoteException e) {
2368             Log.e(TAG, "", e);
2369         }
2370         return false;
2371     }
2372 
2373     /**
2374      * Return the record of {@link BluetoothActivityEnergyInfo} object that
2375      * has the activity and energy info. This can be used to ascertain what
2376      * the controller has been up to, since the last sample.
2377      *
2378      * @param updateType Type of info, cached vs refreshed.
2379      * @return a record with {@link BluetoothActivityEnergyInfo} or null if report is unavailable or
2380      * unsupported
2381      * @hide
2382      * @deprecated use the asynchronous {@link #requestControllerActivityEnergyInfo(ResultReceiver)}
2383      * instead.
2384      */
2385     @Deprecated
2386     @RequiresBluetoothConnectPermission
2387     @RequiresPermission(allOf = {
2388             android.Manifest.permission.BLUETOOTH_CONNECT,
2389             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
2390     })
getControllerActivityEnergyInfo(int updateType)2391     public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
2392         SynchronousResultReceiver receiver = new SynchronousResultReceiver();
2393         requestControllerActivityEnergyInfo(receiver);
2394         try {
2395             SynchronousResultReceiver.Result result = receiver.awaitResult(1000);
2396             if (result.bundle != null) {
2397                 return result.bundle.getParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY);
2398             }
2399         } catch (TimeoutException e) {
2400             Log.e(TAG, "getControllerActivityEnergyInfo timed out");
2401         }
2402         return null;
2403     }
2404 
2405     /**
2406      * Request the record of {@link BluetoothActivityEnergyInfo} object that
2407      * has the activity and energy info. This can be used to ascertain what
2408      * the controller has been up to, since the last sample.
2409      *
2410      * A null value for the activity info object may be sent if the bluetooth service is
2411      * unreachable or the device does not support reporting such information.
2412      *
2413      * @param result The callback to which to send the activity info.
2414      * @hide
2415      */
2416     @RequiresBluetoothConnectPermission
2417     @RequiresPermission(allOf = {
2418             android.Manifest.permission.BLUETOOTH_CONNECT,
2419             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
2420     })
requestControllerActivityEnergyInfo(ResultReceiver result)2421     public void requestControllerActivityEnergyInfo(ResultReceiver result) {
2422         try {
2423             mServiceLock.readLock().lock();
2424             if (mService != null) {
2425                 mService.requestActivityInfo(result, mAttributionSource);
2426                 result = null;
2427             }
2428         } catch (RemoteException e) {
2429             Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e);
2430         } finally {
2431             mServiceLock.readLock().unlock();
2432             if (result != null) {
2433                 // Only send an immediate result if we failed.
2434                 result.send(0, null);
2435             }
2436         }
2437     }
2438 
2439     /**
2440      * Fetches a list of the most recently connected bluetooth devices ordered by how recently they
2441      * were connected with most recently first and least recently last
2442      *
2443      * @return {@link List} of bonded {@link BluetoothDevice} ordered by how recently they were
2444      * connected
2445      *
2446      * @hide
2447      */
2448     @RequiresLegacyBluetoothAdminPermission
2449     @RequiresBluetoothConnectPermission
2450     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getMostRecentlyConnectedDevices()2451     public @NonNull List<BluetoothDevice> getMostRecentlyConnectedDevices() {
2452         if (getState() != STATE_ON) {
2453             return new ArrayList<>();
2454         }
2455         try {
2456             mServiceLock.readLock().lock();
2457             if (mService != null) {
2458                 return Attributable.setAttributionSource(
2459                         mService.getMostRecentlyConnectedDevices(mAttributionSource),
2460                         mAttributionSource);
2461             }
2462         } catch (RemoteException e) {
2463             Log.e(TAG, "", e);
2464         } finally {
2465             mServiceLock.readLock().unlock();
2466         }
2467         return new ArrayList<>();
2468     }
2469 
2470     /**
2471      * Return the set of {@link BluetoothDevice} objects that are bonded
2472      * (paired) to the local adapter.
2473      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
2474      * will return an empty set. After turning on Bluetooth,
2475      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
2476      * to get the updated value.
2477      *
2478      * @return unmodifiable set of {@link BluetoothDevice}, or null on error
2479      */
2480     @RequiresLegacyBluetoothPermission
2481     @RequiresBluetoothConnectPermission
2482     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getBondedDevices()2483     public Set<BluetoothDevice> getBondedDevices() {
2484         if (getState() != STATE_ON) {
2485             return toDeviceSet(Arrays.asList());
2486         }
2487         try {
2488             mServiceLock.readLock().lock();
2489             if (mService != null) {
2490                 return toDeviceSet(Attributable.setAttributionSource(
2491                         Arrays.asList(mService.getBondedDevices(mAttributionSource)),
2492                         mAttributionSource));
2493             }
2494             return toDeviceSet(Arrays.asList());
2495         } catch (RemoteException e) {
2496             Log.e(TAG, "", e);
2497         } finally {
2498             mServiceLock.readLock().unlock();
2499         }
2500         return null;
2501     }
2502 
2503     /**
2504      * Gets the currently supported profiles by the adapter.
2505      *
2506      * <p> This can be used to check whether a profile is supported before attempting
2507      * to connect to its respective proxy.
2508      *
2509      * @return a list of integers indicating the ids of supported profiles as defined in {@link
2510      * BluetoothProfile}.
2511      * @hide
2512      */
2513     @RequiresNoPermission
getSupportedProfiles()2514     public @NonNull List<Integer> getSupportedProfiles() {
2515         final ArrayList<Integer> supportedProfiles = new ArrayList<Integer>();
2516 
2517         try {
2518             synchronized (mManagerCallback) {
2519                 if (mService != null) {
2520                     final long supportedProfilesBitMask = mService.getSupportedProfiles();
2521 
2522                     for (int i = 0; i <= BluetoothProfile.MAX_PROFILE_ID; i++) {
2523                         if ((supportedProfilesBitMask & (1 << i)) != 0) {
2524                             supportedProfiles.add(i);
2525                         }
2526                     }
2527                 } else {
2528                     // Bluetooth is disabled. Just fill in known supported Profiles
2529                     if (isHearingAidProfileSupported()) {
2530                         supportedProfiles.add(BluetoothProfile.HEARING_AID);
2531                     }
2532                 }
2533             }
2534         } catch (RemoteException e) {
2535             Log.e(TAG, "getSupportedProfiles:", e);
2536         }
2537         return supportedProfiles;
2538     }
2539 
2540     private static final String BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY =
2541             "cache_key.bluetooth.get_adapter_connection_state";
2542     private final PropertyInvalidatedCache<Void, Integer>
2543             mBluetoothGetAdapterConnectionStateCache =
2544             new PropertyInvalidatedCache<Void, Integer> (
2545                 8, BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY) {
2546                 /**
2547                  * This method must not be called when mService is null.
2548                  */
2549                 @Override
2550                 @SuppressLint("AndroidFrameworkRequiresPermission")
2551                 protected Integer recompute(Void query) {
2552                     try {
2553                         return mService.getAdapterConnectionState();
2554                     } catch (RemoteException e) {
2555                         throw e.rethrowAsRuntimeException();
2556                     }
2557                 }
2558             };
2559 
2560     /** @hide */
2561     @RequiresNoPermission
disableGetAdapterConnectionStateCache()2562     public void disableGetAdapterConnectionStateCache() {
2563         mBluetoothGetAdapterConnectionStateCache.disableLocal();
2564     }
2565 
2566     /** @hide */
invalidateGetAdapterConnectionStateCache()2567     public static void invalidateGetAdapterConnectionStateCache() {
2568         PropertyInvalidatedCache.invalidateCache(
2569             BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY);
2570     }
2571 
2572     /**
2573      * Get the current connection state of the local Bluetooth adapter.
2574      * This can be used to check whether the local Bluetooth adapter is connected
2575      * to any profile of any other remote Bluetooth Device.
2576      *
2577      * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED}
2578      * intent to get the connection state of the adapter.
2579      *
2580      * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED}, {@link
2581      * #STATE_CONNECTING} or {@link #STATE_DISCONNECTED}
2582      * @hide
2583      */
2584     @UnsupportedAppUsage
2585     @RequiresLegacyBluetoothPermission
2586     @RequiresNoPermission
getConnectionState()2587     public int getConnectionState() {
2588         if (getState() != STATE_ON) {
2589             return BluetoothAdapter.STATE_DISCONNECTED;
2590         }
2591         try {
2592             mServiceLock.readLock().lock();
2593             if (mService != null) {
2594                 return mBluetoothGetAdapterConnectionStateCache.query(null);
2595             }
2596         } catch (RuntimeException e) {
2597             if (e.getCause() instanceof RemoteException) {
2598                 Log.e(TAG, "getConnectionState:", e.getCause());
2599             } else {
2600                 throw e;
2601             }
2602         } finally {
2603             mServiceLock.readLock().unlock();
2604         }
2605         return BluetoothAdapter.STATE_DISCONNECTED;
2606     }
2607 
2608     private static final String BLUETOOTH_PROFILE_CACHE_PROPERTY =
2609             "cache_key.bluetooth.get_profile_connection_state";
2610     private final PropertyInvalidatedCache<Integer, Integer>
2611             mGetProfileConnectionStateCache =
2612             new PropertyInvalidatedCache<Integer, Integer>(
2613                 8, BLUETOOTH_PROFILE_CACHE_PROPERTY) {
2614                 @Override
2615                 @SuppressLint("AndroidFrameworkRequiresPermission")
2616                 protected Integer recompute(Integer query) {
2617                     try {
2618                         mServiceLock.readLock().lock();
2619                         if (mService != null) {
2620                             return mService.getProfileConnectionState(query);
2621                         }
2622                     } catch (RemoteException e) {
2623                         Log.e(TAG, "getProfileConnectionState:", e);
2624                     } finally {
2625                         mServiceLock.readLock().unlock();
2626                     }
2627                     return BluetoothProfile.STATE_DISCONNECTED;
2628                 }
2629                 @Override
2630                 public String queryToString(Integer query) {
2631                     return String.format("getProfileConnectionState(profile=\"%d\")",
2632                                          query);
2633                 }
2634             };
2635 
2636     /** @hide */
2637     @RequiresNoPermission
disableGetProfileConnectionStateCache()2638     public void disableGetProfileConnectionStateCache() {
2639         mGetProfileConnectionStateCache.disableLocal();
2640     }
2641 
2642     /** @hide */
invalidateGetProfileConnectionStateCache()2643     public static void invalidateGetProfileConnectionStateCache() {
2644         PropertyInvalidatedCache.invalidateCache(BLUETOOTH_PROFILE_CACHE_PROPERTY);
2645     }
2646 
2647     /**
2648      * Get the current connection state of a profile.
2649      * This function can be used to check whether the local Bluetooth adapter
2650      * is connected to any remote device for a specific profile.
2651      * Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}.
2652      *
2653      * <p> Return value can be one of
2654      * {@link BluetoothProfile#STATE_DISCONNECTED},
2655      * {@link BluetoothProfile#STATE_CONNECTING},
2656      * {@link BluetoothProfile#STATE_CONNECTED},
2657      * {@link BluetoothProfile#STATE_DISCONNECTING}
2658      */
2659     @RequiresLegacyBluetoothPermission
2660     @RequiresBluetoothConnectPermission
2661     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
2662     @SuppressLint("AndroidFrameworkRequiresPermission")
getProfileConnectionState(int profile)2663     public int getProfileConnectionState(int profile) {
2664         if (getState() != STATE_ON) {
2665             return BluetoothProfile.STATE_DISCONNECTED;
2666         }
2667         return mGetProfileConnectionStateCache.query(new Integer(profile));
2668     }
2669 
2670     /**
2671      * Create a listening, secure RFCOMM Bluetooth socket.
2672      * <p>A remote device connecting to this socket will be authenticated and
2673      * communication on this socket will be encrypted.
2674      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
2675      * connections from a listening {@link BluetoothServerSocket}.
2676      * <p>Valid RFCOMM channels are in range 1 to 30.
2677      *
2678      * @param channel RFCOMM channel to listen on
2679      * @return a listening RFCOMM BluetoothServerSocket
2680      * @throws IOException on error, for example Bluetooth not available, or insufficient
2681      * permissions, or channel in use.
2682      * @hide
2683      */
2684     @RequiresLegacyBluetoothAdminPermission
2685     @RequiresBluetoothConnectPermission
2686     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
listenUsingRfcommOn(int channel)2687     public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
2688         return listenUsingRfcommOn(channel, false, false);
2689     }
2690 
2691     /**
2692      * Create a listening, secure RFCOMM Bluetooth socket.
2693      * <p>A remote device connecting to this socket will be authenticated and
2694      * communication on this socket will be encrypted.
2695      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
2696      * connections from a listening {@link BluetoothServerSocket}.
2697      * <p>Valid RFCOMM channels are in range 1 to 30.
2698      * <p>To auto assign a channel without creating a SDP record use
2699      * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number.
2700      *
2701      * @param channel RFCOMM channel to listen on
2702      * @param mitm enforce person-in-the-middle protection for authentication.
2703      * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2
2704      * connections.
2705      * @return a listening RFCOMM BluetoothServerSocket
2706      * @throws IOException on error, for example Bluetooth not available, or insufficient
2707      * permissions, or channel in use.
2708      * @hide
2709      */
2710     @UnsupportedAppUsage
2711     @RequiresLegacyBluetoothAdminPermission
2712     @RequiresBluetoothConnectPermission
2713     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
listenUsingRfcommOn(int channel, boolean mitm, boolean min16DigitPin)2714     public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm,
2715             boolean min16DigitPin) throws IOException {
2716         BluetoothServerSocket socket =
2717                 new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm,
2718                         min16DigitPin);
2719         int errno = socket.mSocket.bindListen();
2720         if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
2721             socket.setChannel(socket.mSocket.getPort());
2722         }
2723         if (errno != 0) {
2724             //TODO(BT): Throw the same exception error code
2725             // that the previous code was using.
2726             //socket.mSocket.throwErrnoNative(errno);
2727             throw new IOException("Error: " + errno);
2728         }
2729         return socket;
2730     }
2731 
2732     /**
2733      * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
2734      * <p>A remote device connecting to this socket will be authenticated and
2735      * communication on this socket will be encrypted.
2736      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
2737      * connections from a listening {@link BluetoothServerSocket}.
2738      * <p>The system will assign an unused RFCOMM channel to listen on.
2739      * <p>The system will also register a Service Discovery
2740      * Protocol (SDP) record with the local SDP server containing the specified
2741      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
2742      * can use the same UUID to query our SDP server and discover which channel
2743      * to connect to. This SDP record will be removed when this socket is
2744      * closed, or if this application closes unexpectedly.
2745      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
2746      * connect to this socket from another device using the same {@link UUID}.
2747      *
2748      * @param name service name for SDP record
2749      * @param uuid uuid for SDP record
2750      * @return a listening RFCOMM BluetoothServerSocket
2751      * @throws IOException on error, for example Bluetooth not available, or insufficient
2752      * permissions, or channel in use.
2753      */
2754     @RequiresLegacyBluetoothPermission
2755     @RequiresBluetoothConnectPermission
2756     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
listenUsingRfcommWithServiceRecord(String name, UUID uuid)2757     public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
2758             throws IOException {
2759         return createNewRfcommSocketAndRecord(name, uuid, true, true);
2760     }
2761 
2762     /**
2763      * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
2764      * <p>The link key is not required to be authenticated, i.e the communication may be
2765      * vulnerable to Person In the Middle attacks. For Bluetooth 2.1 devices,
2766      * the link will be encrypted, as encryption is mandatory.
2767      * For legacy devices (pre Bluetooth 2.1 devices) the link will not
2768      * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
2769      * encrypted and authenticated communication channel is desired.
2770      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
2771      * connections from a listening {@link BluetoothServerSocket}.
2772      * <p>The system will assign an unused RFCOMM channel to listen on.
2773      * <p>The system will also register a Service Discovery
2774      * Protocol (SDP) record with the local SDP server containing the specified
2775      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
2776      * can use the same UUID to query our SDP server and discover which channel
2777      * to connect to. This SDP record will be removed when this socket is
2778      * closed, or if this application closes unexpectedly.
2779      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
2780      * connect to this socket from another device using the same {@link UUID}.
2781      *
2782      * @param name service name for SDP record
2783      * @param uuid uuid for SDP record
2784      * @return a listening RFCOMM BluetoothServerSocket
2785      * @throws IOException on error, for example Bluetooth not available, or insufficient
2786      * permissions, or channel in use.
2787      */
2788     @RequiresLegacyBluetoothPermission
2789     @RequiresBluetoothConnectPermission
2790     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)2791     public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
2792             throws IOException {
2793         return createNewRfcommSocketAndRecord(name, uuid, false, false);
2794     }
2795 
2796     /**
2797      * Create a listening, encrypted,
2798      * RFCOMM Bluetooth socket with Service Record.
2799      * <p>The link will be encrypted, but the link key is not required to be authenticated
2800      * i.e the communication is vulnerable to Person In the Middle attacks. Use
2801      * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key.
2802      * <p> Use this socket if authentication of link key is not possible.
2803      * For example, for Bluetooth 2.1 devices, if any of the devices does not have
2804      * an input and output capability or just has the ability to display a numeric key,
2805      * a secure socket connection is not possible and this socket can be used.
2806      * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required.
2807      * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandatory.
2808      * For more details, refer to the Security Model section 5.2 (vol 3) of
2809      * Bluetooth Core Specification version 2.1 + EDR.
2810      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
2811      * connections from a listening {@link BluetoothServerSocket}.
2812      * <p>The system will assign an unused RFCOMM channel to listen on.
2813      * <p>The system will also register a Service Discovery
2814      * Protocol (SDP) record with the local SDP server containing the specified
2815      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
2816      * can use the same UUID to query our SDP server and discover which channel
2817      * to connect to. This SDP record will be removed when this socket is
2818      * closed, or if this application closes unexpectedly.
2819      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
2820      * connect to this socket from another device using the same {@link UUID}.
2821      *
2822      * @param name service name for SDP record
2823      * @param uuid uuid for SDP record
2824      * @return a listening RFCOMM BluetoothServerSocket
2825      * @throws IOException on error, for example Bluetooth not available, or insufficient
2826      * permissions, or channel in use.
2827      * @hide
2828      */
2829     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2830     @RequiresLegacyBluetoothPermission
2831     @RequiresBluetoothConnectPermission
2832     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid)2833     public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid)
2834             throws IOException {
2835         return createNewRfcommSocketAndRecord(name, uuid, false, true);
2836     }
2837 
2838     @RequiresBluetoothConnectPermission
2839     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt)2840     private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
2841             boolean auth, boolean encrypt) throws IOException {
2842         BluetoothServerSocket socket;
2843         socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, encrypt,
2844                 new ParcelUuid(uuid));
2845         socket.setServiceName(name);
2846         int errno = socket.mSocket.bindListen();
2847         if (errno != 0) {
2848             //TODO(BT): Throw the same exception error code
2849             // that the previous code was using.
2850             //socket.mSocket.throwErrnoNative(errno);
2851             throw new IOException("Error: " + errno);
2852         }
2853         return socket;
2854     }
2855 
2856     /**
2857      * Construct an unencrypted, unauthenticated, RFCOMM server socket.
2858      * Call #accept to retrieve connections to this socket.
2859      *
2860      * @return An RFCOMM BluetoothServerSocket
2861      * @throws IOException On error, for example Bluetooth not available, or insufficient
2862      * permissions.
2863      * @hide
2864      */
2865     @RequiresBluetoothConnectPermission
2866     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
listenUsingInsecureRfcommOn(int port)2867     public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
2868         BluetoothServerSocket socket =
2869                 new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, false, port);
2870         int errno = socket.mSocket.bindListen();
2871         if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
2872             socket.setChannel(socket.mSocket.getPort());
2873         }
2874         if (errno != 0) {
2875             //TODO(BT): Throw the same exception error code
2876             // that the previous code was using.
2877             //socket.mSocket.throwErrnoNative(errno);
2878             throw new IOException("Error: " + errno);
2879         }
2880         return socket;
2881     }
2882 
2883     /**
2884      * Construct an encrypted, authenticated, L2CAP server socket.
2885      * Call #accept to retrieve connections to this socket.
2886      * <p>To auto assign a port without creating a SDP record use
2887      * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
2888      *
2889      * @param port the PSM to listen on
2890      * @param mitm enforce person-in-the-middle protection for authentication.
2891      * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2
2892      * connections.
2893      * @return An L2CAP BluetoothServerSocket
2894      * @throws IOException On error, for example Bluetooth not available, or insufficient
2895      * permissions.
2896      * @hide
2897      */
2898     @RequiresBluetoothConnectPermission
2899     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)2900     public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)
2901             throws IOException {
2902         BluetoothServerSocket socket =
2903                 new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, true, true, port, mitm,
2904                         min16DigitPin);
2905         int errno = socket.mSocket.bindListen();
2906         if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
2907             int assignedChannel = socket.mSocket.getPort();
2908             if (DBG) Log.d(TAG, "listenUsingL2capOn: set assigned channel to " + assignedChannel);
2909             socket.setChannel(assignedChannel);
2910         }
2911         if (errno != 0) {
2912             //TODO(BT): Throw the same exception error code
2913             // that the previous code was using.
2914             //socket.mSocket.throwErrnoNative(errno);
2915             throw new IOException("Error: " + errno);
2916         }
2917         return socket;
2918     }
2919 
2920     /**
2921      * Construct an encrypted, authenticated, L2CAP server socket.
2922      * Call #accept to retrieve connections to this socket.
2923      * <p>To auto assign a port without creating a SDP record use
2924      * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
2925      *
2926      * @param port the PSM to listen on
2927      * @return An L2CAP BluetoothServerSocket
2928      * @throws IOException On error, for example Bluetooth not available, or insufficient
2929      * permissions.
2930      * @hide
2931      */
2932     @RequiresBluetoothConnectPermission
2933     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
listenUsingL2capOn(int port)2934     public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException {
2935         return listenUsingL2capOn(port, false, false);
2936     }
2937 
2938     /**
2939      * Construct an insecure L2CAP server socket.
2940      * Call #accept to retrieve connections to this socket.
2941      * <p>To auto assign a port without creating a SDP record use
2942      * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
2943      *
2944      * @param port the PSM to listen on
2945      * @return An L2CAP BluetoothServerSocket
2946      * @throws IOException On error, for example Bluetooth not available, or insufficient
2947      * permissions.
2948      * @hide
2949      */
2950     @RequiresBluetoothConnectPermission
2951     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
listenUsingInsecureL2capOn(int port)2952     public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException {
2953         Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port);
2954         BluetoothServerSocket socket =
2955                 new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, false, false, port, false,
2956                                           false);
2957         int errno = socket.mSocket.bindListen();
2958         if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
2959             int assignedChannel = socket.mSocket.getPort();
2960             if (DBG) {
2961                 Log.d(TAG, "listenUsingInsecureL2capOn: set assigned channel to "
2962                         + assignedChannel);
2963             }
2964             socket.setChannel(assignedChannel);
2965         }
2966         if (errno != 0) {
2967             //TODO(BT): Throw the same exception error code
2968             // that the previous code was using.
2969             //socket.mSocket.throwErrnoNative(errno);
2970             throw new IOException("Error: " + errno);
2971         }
2972         return socket;
2973 
2974     }
2975 
2976     /**
2977      * Read the local Out of Band Pairing Data
2978      *
2979      * @return Pair<byte[], byte[]> of Hash and Randomizer
2980      * @hide
2981      */
2982     @RequiresLegacyBluetoothPermission
2983     @RequiresBluetoothConnectPermission
2984     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
2985     @SuppressLint("AndroidFrameworkRequiresPermission")
readOutOfBandData()2986     public Pair<byte[], byte[]> readOutOfBandData() {
2987         return null;
2988     }
2989 
2990     /**
2991      * Get the profile proxy object associated with the profile.
2992      *
2993      * <p>Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP},
2994      * {@link BluetoothProfile#GATT}, {@link BluetoothProfile#HEARING_AID}, or {@link
2995      * BluetoothProfile#GATT_SERVER}. Clients must implement {@link
2996      * BluetoothProfile.ServiceListener} to get notified of the connection status and to get the
2997      * proxy object.
2998      *
2999      * @param context Context of the application
3000      * @param listener The service Listener for connection callbacks.
3001      * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEADSET},
3002      * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, {@link
3003      * BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#GATT_SERVER}.
3004      * @return true on success, false on error
3005      */
3006     @SuppressLint({
3007         "AndroidFrameworkRequiresPermission",
3008         "AndroidFrameworkBluetoothPermission"
3009     })
getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile)3010     public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
3011             int profile) {
3012         if (context == null || listener == null) {
3013             return false;
3014         }
3015 
3016         if (profile == BluetoothProfile.HEADSET) {
3017             BluetoothHeadset headset = new BluetoothHeadset(context, listener, this);
3018             return true;
3019         } else if (profile == BluetoothProfile.A2DP) {
3020             BluetoothA2dp a2dp = new BluetoothA2dp(context, listener, this);
3021             return true;
3022         } else if (profile == BluetoothProfile.A2DP_SINK) {
3023             BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener, this);
3024             return true;
3025         } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
3026             BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener, this);
3027             return true;
3028         } else if (profile == BluetoothProfile.HID_HOST) {
3029             BluetoothHidHost iDev = new BluetoothHidHost(context, listener, this);
3030             return true;
3031         } else if (profile == BluetoothProfile.PAN) {
3032             BluetoothPan pan = new BluetoothPan(context, listener, this);
3033             return true;
3034         } else if (profile == BluetoothProfile.PBAP) {
3035             BluetoothPbap pbap = new BluetoothPbap(context, listener, this);
3036             return true;
3037         } else if (profile == BluetoothProfile.HEALTH) {
3038             Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated");
3039             return false;
3040         } else if (profile == BluetoothProfile.MAP) {
3041             BluetoothMap map = new BluetoothMap(context, listener, this);
3042             return true;
3043         } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
3044             BluetoothHeadsetClient headsetClient =
3045                     new BluetoothHeadsetClient(context, listener, this);
3046             return true;
3047         } else if (profile == BluetoothProfile.SAP) {
3048             BluetoothSap sap = new BluetoothSap(context, listener, this);
3049             return true;
3050         } else if (profile == BluetoothProfile.PBAP_CLIENT) {
3051             BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener, this);
3052             return true;
3053         } else if (profile == BluetoothProfile.MAP_CLIENT) {
3054             BluetoothMapClient mapClient = new BluetoothMapClient(context, listener, this);
3055             return true;
3056         } else if (profile == BluetoothProfile.HID_DEVICE) {
3057             BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener, this);
3058             return true;
3059         } else if (profile == BluetoothProfile.HEARING_AID) {
3060             if (isHearingAidProfileSupported()) {
3061                 BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener, this);
3062                 return true;
3063             }
3064             return false;
3065         } else if (profile == BluetoothProfile.LE_AUDIO) {
3066             BluetoothLeAudio leAudio = new BluetoothLeAudio(context, listener, this);
3067             return true;
3068         } else {
3069             return false;
3070         }
3071     }
3072 
3073     /**
3074      * Close the connection of the profile proxy to the Service.
3075      *
3076      * <p> Clients should call this when they are no longer using
3077      * the proxy obtained from {@link #getProfileProxy}.
3078      * Profile can be one of  {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}
3079      *
3080      * @param profile
3081      * @param proxy Profile proxy object
3082      */
3083     @SuppressLint({
3084             "AndroidFrameworkRequiresPermission",
3085             "AndroidFrameworkBluetoothPermission"
3086     })
closeProfileProxy(int profile, BluetoothProfile proxy)3087     public void closeProfileProxy(int profile, BluetoothProfile proxy) {
3088         if (proxy == null) {
3089             return;
3090         }
3091 
3092         switch (profile) {
3093             case BluetoothProfile.HEADSET:
3094                 BluetoothHeadset headset = (BluetoothHeadset) proxy;
3095                 headset.close();
3096                 break;
3097             case BluetoothProfile.A2DP:
3098                 BluetoothA2dp a2dp = (BluetoothA2dp) proxy;
3099                 a2dp.close();
3100                 break;
3101             case BluetoothProfile.A2DP_SINK:
3102                 BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink) proxy;
3103                 a2dpSink.close();
3104                 break;
3105             case BluetoothProfile.AVRCP_CONTROLLER:
3106                 BluetoothAvrcpController avrcp = (BluetoothAvrcpController) proxy;
3107                 avrcp.close();
3108                 break;
3109             case BluetoothProfile.HID_HOST:
3110                 BluetoothHidHost iDev = (BluetoothHidHost) proxy;
3111                 iDev.close();
3112                 break;
3113             case BluetoothProfile.PAN:
3114                 BluetoothPan pan = (BluetoothPan) proxy;
3115                 pan.close();
3116                 break;
3117             case BluetoothProfile.PBAP:
3118                 BluetoothPbap pbap = (BluetoothPbap) proxy;
3119                 pbap.close();
3120                 break;
3121             case BluetoothProfile.GATT:
3122                 BluetoothGatt gatt = (BluetoothGatt) proxy;
3123                 gatt.close();
3124                 break;
3125             case BluetoothProfile.GATT_SERVER:
3126                 BluetoothGattServer gattServer = (BluetoothGattServer) proxy;
3127                 gattServer.close();
3128                 break;
3129             case BluetoothProfile.MAP:
3130                 BluetoothMap map = (BluetoothMap) proxy;
3131                 map.close();
3132                 break;
3133             case BluetoothProfile.HEADSET_CLIENT:
3134                 BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient) proxy;
3135                 headsetClient.close();
3136                 break;
3137             case BluetoothProfile.SAP:
3138                 BluetoothSap sap = (BluetoothSap) proxy;
3139                 sap.close();
3140                 break;
3141             case BluetoothProfile.PBAP_CLIENT:
3142                 BluetoothPbapClient pbapClient = (BluetoothPbapClient) proxy;
3143                 pbapClient.close();
3144                 break;
3145             case BluetoothProfile.MAP_CLIENT:
3146                 BluetoothMapClient mapClient = (BluetoothMapClient) proxy;
3147                 mapClient.close();
3148                 break;
3149             case BluetoothProfile.HID_DEVICE:
3150                 BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy;
3151                 hidDevice.close();
3152                 break;
3153             case BluetoothProfile.HEARING_AID:
3154                 BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy;
3155                 hearingAid.close();
3156                 break;
3157             case BluetoothProfile.LE_AUDIO:
3158                 BluetoothLeAudio leAudio = (BluetoothLeAudio) proxy;
3159                 leAudio.close();
3160         }
3161     }
3162 
3163     private static final IBluetoothManagerCallback sManagerCallback =
3164             new IBluetoothManagerCallback.Stub() {
3165                 public void onBluetoothServiceUp(IBluetooth bluetoothService) {
3166                     if (DBG) {
3167                         Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
3168                     }
3169 
3170                     synchronized (sServiceLock) {
3171                         sService = bluetoothService;
3172                         for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
3173                             try {
3174                                 if (cb != null) {
3175                                     cb.onBluetoothServiceUp(bluetoothService);
3176                                 } else {
3177                                     Log.d(TAG, "onBluetoothServiceUp: cb is null!");
3178                                 }
3179                             } catch (Exception e) {
3180                                 Log.e(TAG, "", e);
3181                             }
3182                         }
3183                     }
3184                 }
3185 
3186                 public void onBluetoothServiceDown() {
3187                     if (DBG) {
3188                         Log.d(TAG, "onBluetoothServiceDown");
3189                     }
3190 
3191                     synchronized (sServiceLock) {
3192                         sService = null;
3193                         for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
3194                             try {
3195                                 if (cb != null) {
3196                                     cb.onBluetoothServiceDown();
3197                                 } else {
3198                                     Log.d(TAG, "onBluetoothServiceDown: cb is null!");
3199                                 }
3200                             } catch (Exception e) {
3201                                 Log.e(TAG, "", e);
3202                             }
3203                         }
3204                     }
3205                 }
3206 
3207                 public void onBrEdrDown() {
3208                     if (VDBG) {
3209                         Log.i(TAG, "onBrEdrDown");
3210                     }
3211 
3212                     synchronized (sServiceLock) {
3213                         for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
3214                             try {
3215                                 if (cb != null) {
3216                                     cb.onBrEdrDown();
3217                                 } else {
3218                                     Log.d(TAG, "onBrEdrDown: cb is null!");
3219                                 }
3220                             } catch (Exception e) {
3221                                 Log.e(TAG, "", e);
3222                             }
3223                         }
3224                     }
3225                 }
3226             };
3227 
3228     private final IBluetoothManagerCallback mManagerCallback =
3229             new IBluetoothManagerCallback.Stub() {
3230                 public void onBluetoothServiceUp(IBluetooth bluetoothService) {
3231                     synchronized (mServiceLock.writeLock()) {
3232                         mService = bluetoothService;
3233                     }
3234                     synchronized (mMetadataListeners) {
3235                         mMetadataListeners.forEach((device, pair) -> {
3236                             try {
3237                                 mService.registerMetadataListener(mBluetoothMetadataListener,
3238                                         device, mAttributionSource);
3239                             } catch (RemoteException e) {
3240                                 Log.e(TAG, "Failed to register metadata listener", e);
3241                             }
3242                         });
3243                     }
3244                     synchronized (mBluetoothConnectionCallbackExecutorMap) {
3245                         if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
3246                             try {
3247                                 mService.registerBluetoothConnectionCallback(mConnectionCallback,
3248                                         mAttributionSource);
3249                             } catch (RemoteException e) {
3250                                 Log.e(TAG, "onBluetoothServiceUp: Failed to register bluetooth"
3251                                         + "connection callback", e);
3252                             }
3253                         }
3254                     }
3255                 }
3256 
3257                 public void onBluetoothServiceDown() {
3258                     synchronized (mServiceLock.writeLock()) {
3259                         mService = null;
3260                         if (mLeScanClients != null) {
3261                             mLeScanClients.clear();
3262                         }
3263                         if (mBluetoothLeAdvertiser != null) {
3264                             mBluetoothLeAdvertiser.cleanup();
3265                         }
3266                         if (mBluetoothLeScanner != null) {
3267                             mBluetoothLeScanner.cleanup();
3268                         }
3269                     }
3270                 }
3271 
3272                 public void onBrEdrDown() {
3273                 }
3274             };
3275 
3276     /**
3277      * Enable the Bluetooth Adapter, but don't auto-connect devices
3278      * and don't persist state. Only for use by system applications.
3279      *
3280      * @hide
3281      */
3282     @SystemApi
3283     @RequiresLegacyBluetoothAdminPermission
3284     @RequiresBluetoothConnectPermission
3285     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
enableNoAutoConnect()3286     public boolean enableNoAutoConnect() {
3287         if (isEnabled()) {
3288             if (DBG) {
3289                 Log.d(TAG, "enableNoAutoConnect(): BT already enabled!");
3290             }
3291             return true;
3292         }
3293         try {
3294             return mManagerService.enableNoAutoConnect(mAttributionSource);
3295         } catch (RemoteException e) {
3296             Log.e(TAG, "", e);
3297         }
3298         return false;
3299     }
3300 
3301     /** @hide */
3302     @Retention(RetentionPolicy.SOURCE)
3303     @IntDef(value = {
3304             BluetoothStatusCodes.ERROR_UNKNOWN,
3305             BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
3306             BluetoothStatusCodes.ERROR_ANOTHER_ACTIVE_OOB_REQUEST,
3307     })
3308     public @interface OobError {}
3309 
3310     /**
3311      * Provides callback methods for receiving {@link OobData} from the host stack, as well as an
3312      * error interface in order to allow the caller to determine next steps based on the {@code
3313      * ErrorCode}.
3314      *
3315      * @hide
3316      */
3317     @SystemApi
3318     public interface OobDataCallback {
3319         /**
3320          * Handles the {@link OobData} received from the host stack.
3321          *
3322          * @param transport - whether the {@link OobData} is generated for LE or Classic.
3323          * @param oobData - data generated in the host stack(LE) or controller (Classic)
3324          */
onOobData(@ransport int transport, @NonNull OobData oobData)3325         void onOobData(@Transport int transport, @NonNull OobData oobData);
3326 
3327         /**
3328          * Provides feedback when things don't go as expected.
3329          *
3330          * @param errorCode - the code describing the type of error that occurred.
3331          */
onError(@obError int errorCode)3332         void onError(@OobError int errorCode);
3333     }
3334 
3335     /**
3336      * Wraps an AIDL interface around an {@link OobDataCallback} interface.
3337      *
3338      * @see {@link IBluetoothOobDataCallback} for interface definition.
3339      *
3340      * @hide
3341      */
3342     public class WrappedOobDataCallback extends IBluetoothOobDataCallback.Stub {
3343         private final OobDataCallback mCallback;
3344         private final Executor mExecutor;
3345 
3346         /**
3347          * @param callback - object to receive {@link OobData} must be a non null argument
3348          *
3349          * @throws NullPointerException if the callback is null.
3350          */
WrappedOobDataCallback(@onNull OobDataCallback callback, @NonNull @CallbackExecutor Executor executor)3351         WrappedOobDataCallback(@NonNull OobDataCallback callback,
3352                 @NonNull @CallbackExecutor Executor executor) {
3353             requireNonNull(callback);
3354             requireNonNull(executor);
3355             mCallback = callback;
3356             mExecutor = executor;
3357         }
3358         /**
3359          * Wrapper function to relay to the {@link OobDataCallback#onOobData}
3360          *
3361          * @param transport - whether the {@link OobData} is generated for LE or Classic.
3362          * @param oobData - data generated in the host stack(LE) or controller (Classic)
3363          *
3364          * @hide
3365          */
onOobData(@ransport int transport, @NonNull OobData oobData)3366         public void onOobData(@Transport int transport, @NonNull OobData oobData) {
3367             mExecutor.execute(new Runnable() {
3368                 public void run() {
3369                     mCallback.onOobData(transport, oobData);
3370                 }
3371             });
3372         }
3373         /**
3374          * Wrapper function to relay to the {@link OobDataCallback#onError}
3375          *
3376          * @param errorCode - the code descibing the type of error that occurred.
3377          *
3378          * @hide
3379          */
onError(@obError int errorCode)3380         public void onError(@OobError int errorCode) {
3381             mExecutor.execute(new Runnable() {
3382                 public void run() {
3383                     mCallback.onError(errorCode);
3384                 }
3385             });
3386         }
3387     }
3388 
3389     /**
3390      * Fetches a secret data value that can be used for a secure and simple pairing experience.
3391      *
3392      * <p>This is the Local Out of Band data the comes from the
3393      *
3394      * <p>This secret is the local Out of Band data.  This data is used to securely and quickly
3395      * pair two devices with minimal user interaction.
3396      *
3397      * <p>For example, this secret can be transferred to a remote device out of band (meaning any
3398      * other way besides using bluetooth).  Once the remote device finds this device using the
3399      * information given in the data, such as the PUBLIC ADDRESS, the remote device could then
3400      * connect to this device using this secret when the pairing sequenece asks for the secret.
3401      * This device will respond by automatically accepting the pairing due to the secret being so
3402      * trustworthy.
3403      *
3404      * @param transport - provide type of transport (e.g. LE or Classic).
3405      * @param callback - target object to receive the {@link OobData} value.
3406      *
3407      * @throws NullPointerException if callback is null.
3408      * @throws IllegalArgumentException if the transport is not valid.
3409      *
3410      * @hide
3411      */
3412     @SystemApi
3413     @RequiresBluetoothConnectPermission
3414     @RequiresPermission(allOf = {
3415             android.Manifest.permission.BLUETOOTH_CONNECT,
3416             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
3417     })
generateLocalOobData(@ransport int transport, @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback)3418     public void generateLocalOobData(@Transport int transport,
3419             @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback) {
3420         if (transport != BluetoothDevice.TRANSPORT_BREDR && transport
3421                 != BluetoothDevice.TRANSPORT_LE) {
3422             throw new IllegalArgumentException("Invalid transport '" + transport + "'!");
3423         }
3424         requireNonNull(callback);
3425         if (!isEnabled()) {
3426             Log.w(TAG, "generateLocalOobData(): Adapter isn't enabled!");
3427             callback.onError(BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
3428         } else {
3429             try {
3430                 mService.generateLocalOobData(transport, new WrappedOobDataCallback(callback,
3431                         executor), mAttributionSource);
3432             } catch (RemoteException e) {
3433                 Log.e(TAG, "", e);
3434             }
3435         }
3436     }
3437 
3438     /**
3439      * Enable control of the Bluetooth Adapter for a single application.
3440      *
3441      * <p>Some applications need to use Bluetooth for short periods of time to
3442      * transfer data but don't want all the associated implications like
3443      * automatic connection to headsets etc.
3444      *
3445      * <p> Multiple applications can call this. This is reference counted and
3446      * Bluetooth disabled only when no one else is using it. There will be no UI
3447      * shown to the user while bluetooth is being enabled. Any user action will
3448      * override this call. For example, if user wants Bluetooth on and the last
3449      * user of this API wanted to disable Bluetooth, Bluetooth will not be
3450      * turned off.
3451      *
3452      * <p> This API is only meant to be used by internal applications. Third
3453      * party applications but use {@link #enable} and {@link #disable} APIs.
3454      *
3455      * <p> If this API returns true, it means the callback will be called.
3456      * The callback will be called with the current state of Bluetooth.
3457      * If the state is not what was requested, an internal error would be the
3458      * reason. If Bluetooth is already on and if this function is called to turn
3459      * it on, the api will return true and a callback will be called.
3460      *
3461      * @param on True for on, false for off.
3462      * @param callback The callback to notify changes to the state.
3463      * @hide
3464      */
3465     @RequiresLegacyBluetoothPermission
3466     @RequiresBluetoothConnectPermission
3467     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
3468     @SuppressLint("AndroidFrameworkRequiresPermission")
changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback)3469     public boolean changeApplicationBluetoothState(boolean on,
3470             BluetoothStateChangeCallback callback) {
3471         return false;
3472     }
3473 
3474     /**
3475      * @hide
3476      */
3477     public interface BluetoothStateChangeCallback {
3478         /**
3479          * @hide
3480          */
onBluetoothStateChange(boolean on)3481         void onBluetoothStateChange(boolean on);
3482     }
3483 
3484     /**
3485      * @hide
3486      */
3487     public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
3488         private BluetoothStateChangeCallback mCallback;
3489 
StateChangeCallbackWrapper(BluetoothStateChangeCallback callback)3490         StateChangeCallbackWrapper(BluetoothStateChangeCallback callback) {
3491             mCallback = callback;
3492         }
3493 
3494         @Override
onBluetoothStateChange(boolean on)3495         public void onBluetoothStateChange(boolean on) {
3496             mCallback.onBluetoothStateChange(on);
3497         }
3498     }
3499 
toDeviceSet(List<BluetoothDevice> devices)3500     private Set<BluetoothDevice> toDeviceSet(List<BluetoothDevice> devices) {
3501         Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(devices);
3502         return Collections.unmodifiableSet(deviceSet);
3503     }
3504 
finalize()3505     protected void finalize() throws Throwable {
3506         try {
3507             removeServiceStateCallback(mManagerCallback);
3508         } finally {
3509             super.finalize();
3510         }
3511     }
3512 
3513     /**
3514      * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
3515      * <p>Alphabetic characters must be uppercase to be valid.
3516      *
3517      * @param address Bluetooth address as string
3518      * @return true if the address is valid, false otherwise
3519      */
checkBluetoothAddress(String address)3520     public static boolean checkBluetoothAddress(String address) {
3521         if (address == null || address.length() != ADDRESS_LENGTH) {
3522             return false;
3523         }
3524         for (int i = 0; i < ADDRESS_LENGTH; i++) {
3525             char c = address.charAt(i);
3526             switch (i % 3) {
3527                 case 0:
3528                 case 1:
3529                     if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
3530                         // hex character, OK
3531                         break;
3532                     }
3533                     return false;
3534                 case 2:
3535                     if (c == ':') {
3536                         break;  // OK
3537                     }
3538                     return false;
3539             }
3540         }
3541         return true;
3542     }
3543 
3544     /**
3545      * Determines whether a String Bluetooth address, such as "F0:43:A8:23:10:00"
3546      * is a RANDOM STATIC address.
3547      *
3548      * RANDOM STATIC: (addr & 0xC0) == 0xC0
3549      * RANDOM RESOLVABLE: (addr &  0xC0) == 0x40
3550      * RANDOM non-RESOLVABLE: (addr &  0xC0) == 0x00
3551      *
3552      * @param address Bluetooth address as string
3553      * @return true if the 2 Most Significant Bits of the address equals 0xC0.
3554      *
3555      * @hide
3556      */
isAddressRandomStatic(@onNull String address)3557     public static boolean isAddressRandomStatic(@NonNull String address) {
3558         requireNonNull(address);
3559         return checkBluetoothAddress(address)
3560                 && (Integer.parseInt(address.split(":")[0], 16) & 0xC0) == 0xC0;
3561     }
3562 
3563     /** {@hide} */
3564     @UnsupportedAppUsage
3565     @RequiresNoPermission
getBluetoothManager()3566     public IBluetoothManager getBluetoothManager() {
3567         return mManagerService;
3568     }
3569 
3570     /** {@hide} */
3571     @RequiresNoPermission
getAttributionSource()3572     public AttributionSource getAttributionSource() {
3573         return mAttributionSource;
3574     }
3575 
3576     @GuardedBy("sServiceLock")
3577     private static final WeakHashMap<IBluetoothManagerCallback, Void> sProxyServiceStateCallbacks =
3578             new WeakHashMap<>();
3579 
getBluetoothService()3580     /*package*/ IBluetooth getBluetoothService() {
3581         synchronized (sServiceLock) {
3582             if (sProxyServiceStateCallbacks.isEmpty()) {
3583                 throw new IllegalStateException(
3584                         "Anonymous service access requires at least one lifecycle in process");
3585             }
3586             return sService;
3587         }
3588     }
3589 
3590     @UnsupportedAppUsage
getBluetoothService(IBluetoothManagerCallback cb)3591     /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
3592         Objects.requireNonNull(cb);
3593         synchronized (sServiceLock) {
3594             sProxyServiceStateCallbacks.put(cb, null);
3595             registerOrUnregisterAdapterLocked();
3596             return sService;
3597         }
3598     }
3599 
removeServiceStateCallback(IBluetoothManagerCallback cb)3600     /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
3601         Objects.requireNonNull(cb);
3602         synchronized (sServiceLock) {
3603             sProxyServiceStateCallbacks.remove(cb);
3604             registerOrUnregisterAdapterLocked();
3605         }
3606     }
3607 
3608     /**
3609      * Handle registering (or unregistering) a single process-wide
3610      * {@link IBluetoothManagerCallback} based on the presence of local
3611      * {@link #sProxyServiceStateCallbacks} clients.
3612      */
3613     @GuardedBy("sServiceLock")
registerOrUnregisterAdapterLocked()3614     private void registerOrUnregisterAdapterLocked() {
3615         final boolean isRegistered = sServiceRegistered;
3616         final boolean wantRegistered = !sProxyServiceStateCallbacks.isEmpty();
3617 
3618         if (isRegistered != wantRegistered) {
3619             if (wantRegistered) {
3620                 try {
3621                     sService = mManagerService.registerAdapter(sManagerCallback);
3622                 } catch (RemoteException e) {
3623                     throw e.rethrowFromSystemServer();
3624                 }
3625             } else {
3626                 try {
3627                     mManagerService.unregisterAdapter(sManagerCallback);
3628                     sService = null;
3629                 } catch (RemoteException e) {
3630                     throw e.rethrowFromSystemServer();
3631                 }
3632             }
3633             sServiceRegistered = wantRegistered;
3634         }
3635     }
3636 
3637     /**
3638      * Callback interface used to deliver LE scan results.
3639      *
3640      * @see #startLeScan(LeScanCallback)
3641      * @see #startLeScan(UUID[], LeScanCallback)
3642      */
3643     public interface LeScanCallback {
3644         /**
3645          * Callback reporting an LE device found during a device scan initiated
3646          * by the {@link BluetoothAdapter#startLeScan} function.
3647          *
3648          * @param device Identifies the remote device
3649          * @param rssi The RSSI value for the remote device as reported by the Bluetooth hardware. 0
3650          * if no RSSI value is available.
3651          * @param scanRecord The content of the advertisement record offered by the remote device.
3652          */
onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)3653         void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
3654     }
3655 
3656     /**
3657      * Register a callback to receive events whenever the bluetooth stack goes down and back up,
3658      * e.g. in the event the bluetooth is turned off/on via settings.
3659      *
3660      * If the bluetooth stack is currently up, there will not be an initial callback call.
3661      * You can use the return value as an indication of this being the case.
3662      *
3663      * Callbacks will be delivered on a binder thread.
3664      *
3665      * @return whether bluetooth is already up currently
3666      *
3667      * @hide
3668      */
registerServiceLifecycleCallback(ServiceLifecycleCallback callback)3669     public boolean registerServiceLifecycleCallback(ServiceLifecycleCallback callback) {
3670         return getBluetoothService(callback.mRemote) != null;
3671     }
3672 
3673     /**
3674      * Unregister a callback registered via {@link #registerServiceLifecycleCallback}
3675      *
3676      * @hide
3677      */
unregisterServiceLifecycleCallback(ServiceLifecycleCallback callback)3678     public void unregisterServiceLifecycleCallback(ServiceLifecycleCallback callback) {
3679         removeServiceStateCallback(callback.mRemote);
3680     }
3681 
3682     /**
3683      * A callback for {@link #registerServiceLifecycleCallback}
3684      *
3685      * @hide
3686      */
3687     public abstract static class ServiceLifecycleCallback {
3688 
3689         /** Called when the bluetooth stack is up */
onBluetoothServiceUp()3690         public abstract void onBluetoothServiceUp();
3691 
3692         /** Called when the bluetooth stack is down */
onBluetoothServiceDown()3693         public abstract void onBluetoothServiceDown();
3694 
3695         IBluetoothManagerCallback mRemote = new IBluetoothManagerCallback.Stub() {
3696             @Override
3697             public void onBluetoothServiceUp(IBluetooth bluetoothService) {
3698                 ServiceLifecycleCallback.this.onBluetoothServiceUp();
3699             }
3700 
3701             @Override
3702             public void onBluetoothServiceDown() {
3703                 ServiceLifecycleCallback.this.onBluetoothServiceDown();
3704             }
3705 
3706             @Override
3707             public void onBrEdrDown() {}
3708         };
3709     }
3710 
3711     /**
3712      * Starts a scan for Bluetooth LE devices.
3713      *
3714      * <p>Results of the scan are reported using the
3715      * {@link LeScanCallback#onLeScan} callback.
3716      *
3717      * @param callback the callback LE scan results are delivered
3718      * @return true, if the scan was started successfully
3719      * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)}
3720      * instead.
3721      */
3722     @Deprecated
3723     @RequiresLegacyBluetoothAdminPermission
3724     @RequiresBluetoothScanPermission
3725     @RequiresBluetoothLocationPermission
3726     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
startLeScan(LeScanCallback callback)3727     public boolean startLeScan(LeScanCallback callback) {
3728         return startLeScan(null, callback);
3729     }
3730 
3731     /**
3732      * Starts a scan for Bluetooth LE devices, looking for devices that
3733      * advertise given services.
3734      *
3735      * <p>Devices which advertise all specified services are reported using the
3736      * {@link LeScanCallback#onLeScan} callback.
3737      *
3738      * @param serviceUuids Array of services to look for
3739      * @param callback the callback LE scan results are delivered
3740      * @return true, if the scan was started successfully
3741      * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)}
3742      * instead.
3743      */
3744     @Deprecated
3745     @RequiresLegacyBluetoothAdminPermission
3746     @RequiresBluetoothScanPermission
3747     @RequiresBluetoothLocationPermission
3748     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
startLeScan(final UUID[] serviceUuids, final LeScanCallback callback)3749     public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {
3750         if (DBG) {
3751             Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids));
3752         }
3753         if (callback == null) {
3754             if (DBG) {
3755                 Log.e(TAG, "startLeScan: null callback");
3756             }
3757             return false;
3758         }
3759         BluetoothLeScanner scanner = getBluetoothLeScanner();
3760         if (scanner == null) {
3761             if (DBG) {
3762                 Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner");
3763             }
3764             return false;
3765         }
3766 
3767         synchronized (mLeScanClients) {
3768             if (mLeScanClients.containsKey(callback)) {
3769                 if (DBG) {
3770                     Log.e(TAG, "LE Scan has already started");
3771                 }
3772                 return false;
3773             }
3774 
3775             try {
3776                 IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
3777                 if (iGatt == null) {
3778                     // BLE is not supported
3779                     return false;
3780                 }
3781 
3782                 @SuppressLint("AndroidFrameworkBluetoothPermission")
3783                 ScanCallback scanCallback = new ScanCallback() {
3784                     @Override
3785                     public void onScanResult(int callbackType, ScanResult result) {
3786                         if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
3787                             // Should not happen.
3788                             Log.e(TAG, "LE Scan has already started");
3789                             return;
3790                         }
3791                         ScanRecord scanRecord = result.getScanRecord();
3792                         if (scanRecord == null) {
3793                             return;
3794                         }
3795                         if (serviceUuids != null) {
3796                             List<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
3797                             for (UUID uuid : serviceUuids) {
3798                                 uuids.add(new ParcelUuid(uuid));
3799                             }
3800                             List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids();
3801                             if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) {
3802                                 if (DBG) {
3803                                     Log.d(TAG, "uuids does not match");
3804                                 }
3805                                 return;
3806                             }
3807                         }
3808                         callback.onLeScan(result.getDevice(), result.getRssi(),
3809                                 scanRecord.getBytes());
3810                     }
3811                 };
3812                 ScanSettings settings = new ScanSettings.Builder().setCallbackType(
3813                         ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
3814                         .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
3815                         .build();
3816 
3817                 List<ScanFilter> filters = new ArrayList<ScanFilter>();
3818                 if (serviceUuids != null && serviceUuids.length > 0) {
3819                     // Note scan filter does not support matching an UUID array so we put one
3820                     // UUID to hardware and match the whole array in callback.
3821                     ScanFilter filter =
3822                             new ScanFilter.Builder().setServiceUuid(new ParcelUuid(serviceUuids[0]))
3823                                     .build();
3824                     filters.add(filter);
3825                 }
3826                 scanner.startScan(filters, settings, scanCallback);
3827 
3828                 mLeScanClients.put(callback, scanCallback);
3829                 return true;
3830 
3831             } catch (RemoteException e) {
3832                 Log.e(TAG, "", e);
3833             }
3834         }
3835         return false;
3836     }
3837 
3838     /**
3839      * Stops an ongoing Bluetooth LE device scan.
3840      *
3841      * @param callback used to identify which scan to stop must be the same handle used to start the
3842      * scan
3843      * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead.
3844      */
3845     @Deprecated
3846     @RequiresLegacyBluetoothAdminPermission
3847     @RequiresBluetoothScanPermission
3848     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
stopLeScan(LeScanCallback callback)3849     public void stopLeScan(LeScanCallback callback) {
3850         if (DBG) {
3851             Log.d(TAG, "stopLeScan()");
3852         }
3853         BluetoothLeScanner scanner = getBluetoothLeScanner();
3854         if (scanner == null) {
3855             return;
3856         }
3857         synchronized (mLeScanClients) {
3858             ScanCallback scanCallback = mLeScanClients.remove(callback);
3859             if (scanCallback == null) {
3860                 if (DBG) {
3861                     Log.d(TAG, "scan not started yet");
3862                 }
3863                 return;
3864             }
3865             scanner.stopScan(scanCallback);
3866         }
3867     }
3868 
3869     /**
3870      * Create a secure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
3871      * assign a dynamic protocol/service multiplexer (PSM) value. This socket can be used to listen
3872      * for incoming connections. The supported Bluetooth transport is LE only.
3873      * <p>A remote device connecting to this socket will be authenticated and communication on this
3874      * socket will be encrypted.
3875      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
3876      * {@link BluetoothServerSocket}.
3877      * <p>The system will assign a dynamic PSM value. This PSM value can be read from the {@link
3878      * BluetoothServerSocket#getPsm()} and this value will be released when this server socket is
3879      * closed, Bluetooth is turned off, or the application exits unexpectedly.
3880      * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
3881      * defined and performed by the application.
3882      * <p>Use {@link BluetoothDevice#createL2capChannel(int)} to connect to this server
3883      * socket from another Android device that is given the PSM value.
3884      *
3885      * @return an L2CAP CoC BluetoothServerSocket
3886      * @throws IOException on error, for example Bluetooth not available, or insufficient
3887      * permissions, or unable to start this CoC
3888      */
3889     @RequiresLegacyBluetoothPermission
3890     @RequiresBluetoothConnectPermission
3891     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
listenUsingL2capChannel()3892     public @NonNull BluetoothServerSocket listenUsingL2capChannel()
3893             throws IOException {
3894         BluetoothServerSocket socket =
3895                             new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true,
3896                                       SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false);
3897         int errno = socket.mSocket.bindListen();
3898         if (errno != 0) {
3899             throw new IOException("Error: " + errno);
3900         }
3901 
3902         int assignedPsm = socket.mSocket.getPort();
3903         if (assignedPsm == 0) {
3904             throw new IOException("Error: Unable to assign PSM value");
3905         }
3906         if (DBG) {
3907             Log.d(TAG, "listenUsingL2capChannel: set assigned PSM to "
3908                     + assignedPsm);
3909         }
3910         socket.setChannel(assignedPsm);
3911 
3912         return socket;
3913     }
3914 
3915     /**
3916      * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
3917      * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The
3918      * supported Bluetooth transport is LE only.
3919      * <p>The link key is not required to be authenticated, i.e the communication may be vulnerable
3920      * to person-in-the-middle attacks. Use {@link #listenUsingL2capChannel}, if an encrypted and
3921      * authenticated communication channel is desired.
3922      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
3923      * {@link BluetoothServerSocket}.
3924      * <p>The system will assign a dynamic protocol/service multiplexer (PSM) value. This PSM value
3925      * can be read from the {@link BluetoothServerSocket#getPsm()} and this value will be released
3926      * when this server socket is closed, Bluetooth is turned off, or the application exits
3927      * unexpectedly.
3928      * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
3929      * defined and performed by the application.
3930      * <p>Use {@link BluetoothDevice#createInsecureL2capChannel(int)} to connect to this server
3931      * socket from another Android device that is given the PSM value.
3932      *
3933      * @return an L2CAP CoC BluetoothServerSocket
3934      * @throws IOException on error, for example Bluetooth not available, or insufficient
3935      * permissions, or unable to start this CoC
3936      */
3937     @RequiresLegacyBluetoothPermission
3938     @RequiresBluetoothConnectPermission
3939     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
listenUsingInsecureL2capChannel()3940     public @NonNull BluetoothServerSocket listenUsingInsecureL2capChannel()
3941             throws IOException {
3942         BluetoothServerSocket socket =
3943                             new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false,
3944                                       SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false);
3945         int errno = socket.mSocket.bindListen();
3946         if (errno != 0) {
3947             throw new IOException("Error: " + errno);
3948         }
3949 
3950         int assignedPsm = socket.mSocket.getPort();
3951         if (assignedPsm == 0) {
3952             throw new IOException("Error: Unable to assign PSM value");
3953         }
3954         if (DBG) {
3955             Log.d(TAG, "listenUsingInsecureL2capChannel: set assigned PSM to "
3956                     + assignedPsm);
3957         }
3958         socket.setChannel(assignedPsm);
3959 
3960         return socket;
3961     }
3962 
3963     /**
3964      * Register a {@link #OnMetadataChangedListener} to receive update about metadata
3965      * changes for this {@link BluetoothDevice}.
3966      * Registration must be done when Bluetooth is ON and will last until
3967      * {@link #removeOnMetadataChangedListener(BluetoothDevice)} is called, even when Bluetooth
3968      * restarted in the middle.
3969      * All input parameters should not be null or {@link NullPointerException} will be triggered.
3970      * The same {@link BluetoothDevice} and {@link #OnMetadataChangedListener} pair can only be
3971      * registered once, double registration would cause {@link IllegalArgumentException}.
3972      *
3973      * @param device {@link BluetoothDevice} that will be registered
3974      * @param executor the executor for listener callback
3975      * @param listener {@link #OnMetadataChangedListener} that will receive asynchronous callbacks
3976      * @return true on success, false on error
3977      * @throws NullPointerException If one of {@code listener}, {@code device} or {@code executor}
3978      * is null.
3979      * @throws IllegalArgumentException The same {@link #OnMetadataChangedListener} and
3980      * {@link BluetoothDevice} are registered twice.
3981      * @hide
3982      */
3983     @SystemApi
3984     @RequiresBluetoothConnectPermission
3985     @RequiresPermission(allOf = {
3986             android.Manifest.permission.BLUETOOTH_CONNECT,
3987             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
3988     })
addOnMetadataChangedListener(@onNull BluetoothDevice device, @NonNull Executor executor, @NonNull OnMetadataChangedListener listener)3989     public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device,
3990             @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) {
3991         if (DBG) Log.d(TAG, "addOnMetadataChangedListener()");
3992 
3993         final IBluetooth service = mService;
3994         if (service == null) {
3995             Log.e(TAG, "Bluetooth is not enabled. Cannot register metadata listener");
3996             return false;
3997         }
3998         if (listener == null) {
3999             throw new NullPointerException("listener is null");
4000         }
4001         if (device == null) {
4002             throw new NullPointerException("device is null");
4003         }
4004         if (executor == null) {
4005             throw new NullPointerException("executor is null");
4006         }
4007 
4008         synchronized (mMetadataListeners) {
4009             List<Pair<OnMetadataChangedListener, Executor>> listenerList =
4010                     mMetadataListeners.get(device);
4011             if (listenerList == null) {
4012                 // Create new listener/executor list for registeration
4013                 listenerList = new ArrayList<>();
4014                 mMetadataListeners.put(device, listenerList);
4015             } else {
4016                 // Check whether this device was already registed by the lisenter
4017                 if (listenerList.stream().anyMatch((pair) -> (pair.first.equals(listener)))) {
4018                     throw new IllegalArgumentException("listener was already regestered"
4019                             + " for the device");
4020                 }
4021             }
4022 
4023             Pair<OnMetadataChangedListener, Executor> listenerPair = new Pair(listener, executor);
4024             listenerList.add(listenerPair);
4025 
4026             boolean ret = false;
4027             try {
4028                 ret = service.registerMetadataListener(mBluetoothMetadataListener, device,
4029                         mAttributionSource);
4030             } catch (RemoteException e) {
4031                 Log.e(TAG, "registerMetadataListener fail", e);
4032             } finally {
4033                 if (!ret) {
4034                     // Remove listener registered earlier when fail.
4035                     listenerList.remove(listenerPair);
4036                     if (listenerList.isEmpty()) {
4037                         // Remove the device if its listener list is empty
4038                         mMetadataListeners.remove(device);
4039                     }
4040                 }
4041             }
4042             return ret;
4043         }
4044     }
4045 
4046     /**
4047      * Unregister a {@link #OnMetadataChangedListener} from a registered {@link BluetoothDevice}.
4048      * Unregistration can be done when Bluetooth is either ON or OFF.
4049      * {@link #addOnMetadataChangedListener(OnMetadataChangedListener, BluetoothDevice, Executor)}
4050      * must be called before unregisteration.
4051      *
4052      * @param device {@link BluetoothDevice} that will be unregistered. It
4053      * should not be null or {@link NullPointerException} will be triggered.
4054      * @param listener {@link OnMetadataChangedListener} that will be unregistered. It
4055      * should not be null or {@link NullPointerException} will be triggered.
4056      * @return true on success, false on error
4057      * @throws NullPointerException If {@code listener} or {@code device} is null.
4058      * @throws IllegalArgumentException If {@code device} has not been registered before.
4059      * @hide
4060      */
4061     @SystemApi
4062     @RequiresBluetoothConnectPermission
4063     @RequiresPermission(allOf = {
4064             android.Manifest.permission.BLUETOOTH_CONNECT,
4065             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
4066     })
removeOnMetadataChangedListener(@onNull BluetoothDevice device, @NonNull OnMetadataChangedListener listener)4067     public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device,
4068             @NonNull OnMetadataChangedListener listener) {
4069         if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()");
4070         if (device == null) {
4071             throw new NullPointerException("device is null");
4072         }
4073         if (listener == null) {
4074             throw new NullPointerException("listener is null");
4075         }
4076 
4077         synchronized (mMetadataListeners) {
4078             if (!mMetadataListeners.containsKey(device)) {
4079                 throw new IllegalArgumentException("device was not registered");
4080             }
4081             // Remove issued listener from the registered device
4082             mMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener)));
4083 
4084             if (mMetadataListeners.get(device).isEmpty()) {
4085                 // Unregister to Bluetooth service if all listeners are removed from
4086                 // the registered device
4087                 mMetadataListeners.remove(device);
4088                 final IBluetooth service = mService;
4089                 if (service == null) {
4090                     // Bluetooth is OFF, do nothing to Bluetooth service.
4091                     return true;
4092                 }
4093                 try {
4094                     return service.unregisterMetadataListener(device, mAttributionSource);
4095                 } catch (RemoteException e) {
4096                     Log.e(TAG, "unregisterMetadataListener fail", e);
4097                     return false;
4098                 }
4099             }
4100         }
4101         return true;
4102     }
4103 
4104     /**
4105      * This interface is used to implement {@link BluetoothAdapter} metadata listener.
4106      * @hide
4107      */
4108     @SystemApi
4109     public interface OnMetadataChangedListener {
4110         /**
4111          * Callback triggered if the metadata of {@link BluetoothDevice} registered in
4112          * {@link #addOnMetadataChangedListener}.
4113          *
4114          * @param device changed {@link BluetoothDevice}.
4115          * @param key changed metadata key, one of BluetoothDevice.METADATA_*.
4116          * @param value the new value of metadata as byte array.
4117          */
onMetadataChanged(@onNull BluetoothDevice device, int key, @Nullable byte[] value)4118         void onMetadataChanged(@NonNull BluetoothDevice device, int key,
4119                 @Nullable byte[] value);
4120     }
4121 
4122     @SuppressLint("AndroidFrameworkBluetoothPermission")
4123     private final IBluetoothConnectionCallback mConnectionCallback =
4124             new IBluetoothConnectionCallback.Stub() {
4125         @Override
4126         public void onDeviceConnected(BluetoothDevice device) {
4127             Attributable.setAttributionSource(device, mAttributionSource);
4128             for (Map.Entry<BluetoothConnectionCallback, Executor> callbackExecutorEntry:
4129                     mBluetoothConnectionCallbackExecutorMap.entrySet()) {
4130                 BluetoothConnectionCallback callback = callbackExecutorEntry.getKey();
4131                 Executor executor = callbackExecutorEntry.getValue();
4132                 executor.execute(() -> callback.onDeviceConnected(device));
4133             }
4134         }
4135 
4136         @Override
4137         public void onDeviceDisconnected(BluetoothDevice device, int hciReason) {
4138             Attributable.setAttributionSource(device, mAttributionSource);
4139             for (Map.Entry<BluetoothConnectionCallback, Executor> callbackExecutorEntry:
4140                     mBluetoothConnectionCallbackExecutorMap.entrySet()) {
4141                 BluetoothConnectionCallback callback = callbackExecutorEntry.getKey();
4142                 Executor executor = callbackExecutorEntry.getValue();
4143                 executor.execute(() -> callback.onDeviceDisconnected(device, hciReason));
4144             }
4145         }
4146     };
4147 
4148     /**
4149      * Registers the BluetoothConnectionCallback to receive callback events when a bluetooth device
4150      * (classic or low energy) is connected or disconnected.
4151      *
4152      * @param executor is the callback executor
4153      * @param callback is the connection callback you wish to register
4154      * @return true if the callback was registered successfully, false otherwise
4155      * @throws IllegalArgumentException if the callback is already registered
4156      * @hide
4157      */
4158     @RequiresBluetoothConnectPermission
4159     @RequiresPermission(allOf = {
4160             android.Manifest.permission.BLUETOOTH_CONNECT,
4161             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
4162     })
registerBluetoothConnectionCallback(@onNull @allbackExecutor Executor executor, @NonNull BluetoothConnectionCallback callback)4163     public boolean registerBluetoothConnectionCallback(@NonNull @CallbackExecutor Executor executor,
4164             @NonNull BluetoothConnectionCallback callback) {
4165         if (DBG) Log.d(TAG, "registerBluetoothConnectionCallback()");
4166         if (callback == null) {
4167             return false;
4168         }
4169 
4170         synchronized (mBluetoothConnectionCallbackExecutorMap) {
4171             // If the callback map is empty, we register the service-to-app callback
4172             if (mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
4173                 try {
4174                     mServiceLock.readLock().lock();
4175                     if (mService != null) {
4176                         if (!mService.registerBluetoothConnectionCallback(mConnectionCallback,
4177                                 mAttributionSource)) {
4178                             return false;
4179                         }
4180                     }
4181                 } catch (RemoteException e) {
4182                     Log.e(TAG, "", e);
4183                     mBluetoothConnectionCallbackExecutorMap.remove(callback);
4184                 } finally {
4185                     mServiceLock.readLock().unlock();
4186                 }
4187             }
4188 
4189             // Adds the passed in callback to our map of callbacks to executors
4190             if (mBluetoothConnectionCallbackExecutorMap.containsKey(callback)) {
4191                 throw new IllegalArgumentException("This callback has already been registered");
4192             }
4193             mBluetoothConnectionCallbackExecutorMap.put(callback, executor);
4194         }
4195 
4196         return true;
4197     }
4198 
4199     /**
4200      * Unregisters the BluetoothConnectionCallback that was previously registered by the application
4201      *
4202      * @param callback is the connection callback you wish to unregister
4203      * @return true if the callback was unregistered successfully, false otherwise
4204      * @hide
4205      */
4206     @RequiresBluetoothConnectPermission
4207     @RequiresPermission(allOf = {
4208             android.Manifest.permission.BLUETOOTH_CONNECT,
4209             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
4210     })
unregisterBluetoothConnectionCallback( @onNull BluetoothConnectionCallback callback)4211     public boolean unregisterBluetoothConnectionCallback(
4212             @NonNull BluetoothConnectionCallback callback) {
4213         if (DBG) Log.d(TAG, "unregisterBluetoothConnectionCallback()");
4214         if (callback == null) {
4215             return false;
4216         }
4217 
4218         synchronized (mBluetoothConnectionCallbackExecutorMap) {
4219             if (mBluetoothConnectionCallbackExecutorMap.remove(callback) != null) {
4220                 return false;
4221             }
4222         }
4223 
4224         if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
4225             return true;
4226         }
4227 
4228         // If the callback map is empty, we unregister the service-to-app callback
4229         try {
4230             mServiceLock.readLock().lock();
4231             if (mService != null) {
4232                 return mService.unregisterBluetoothConnectionCallback(mConnectionCallback,
4233                         mAttributionSource);
4234             }
4235         } catch (RemoteException e) {
4236             Log.e(TAG, "", e);
4237         } finally {
4238             mServiceLock.readLock().unlock();
4239         }
4240 
4241         return false;
4242     }
4243 
4244     /**
4245      * This abstract class is used to implement callbacks for when a bluetooth classic or Bluetooth
4246      * Low Energy (BLE) device is either connected or disconnected.
4247      *
4248      * @hide
4249      */
4250     public abstract static class BluetoothConnectionCallback {
4251         /**
4252          * Callback triggered when a bluetooth device (classic or BLE) is connected
4253          * @param device is the connected bluetooth device
4254          */
onDeviceConnected(BluetoothDevice device)4255         public void onDeviceConnected(BluetoothDevice device) {}
4256 
4257         /**
4258          * Callback triggered when a bluetooth device (classic or BLE) is disconnected
4259          * @param device is the disconnected bluetooth device
4260          * @param reason is the disconnect reason
4261          */
onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason)4262         public void onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason) {}
4263 
4264         /**
4265          * @hide
4266          */
4267         @Retention(RetentionPolicy.SOURCE)
4268         @IntDef(prefix = { "REASON_" }, value = {
4269                 BluetoothStatusCodes.ERROR_UNKNOWN,
4270                 BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST,
4271                 BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE_REQUEST,
4272                 BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL,
4273                 BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE,
4274                 BluetoothStatusCodes.ERROR_DISCONNECT_REASON_TIMEOUT,
4275                 BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SECURITY,
4276                 BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SYSTEM_POLICY,
4277                 BluetoothStatusCodes.ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED,
4278                 BluetoothStatusCodes.ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS,
4279                 BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS})
4280         public @interface DisconnectReason {}
4281 
4282         /**
4283          * Returns human-readable strings corresponding to {@link DisconnectReason}.
4284          */
disconnectReasonText(@isconnectReason int reason)4285         public static String disconnectReasonText(@DisconnectReason int reason) {
4286             switch (reason) {
4287                 case BluetoothStatusCodes.ERROR_UNKNOWN:
4288                     return "Reason unknown";
4289                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST:
4290                     return "Local request";
4291                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE_REQUEST:
4292                     return "Remote request";
4293                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL:
4294                     return "Local error";
4295                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE:
4296                     return "Remote error";
4297                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_TIMEOUT:
4298                     return "Timeout";
4299                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SECURITY:
4300                     return "Security";
4301                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SYSTEM_POLICY:
4302                     return "System policy";
4303                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED:
4304                     return "Resource constrained";
4305                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS:
4306                     return "Connection already exists";
4307                 case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS:
4308                     return "Bad parameters";
4309                 default:
4310                     return "Unrecognized disconnect reason: " + reason;
4311             }
4312         }
4313     }
4314 
4315     /**
4316      * Converts old constant of priority to the new for connection policy
4317      *
4318      * @param priority is the priority to convert to connection policy
4319      * @return the equivalent connection policy constant to the priority
4320      *
4321      * @hide
4322      */
priorityToConnectionPolicy(int priority)4323     public static @ConnectionPolicy int priorityToConnectionPolicy(int priority) {
4324         switch(priority) {
4325             case BluetoothProfile.PRIORITY_AUTO_CONNECT:
4326                 return BluetoothProfile.CONNECTION_POLICY_ALLOWED;
4327             case BluetoothProfile.PRIORITY_ON:
4328                 return BluetoothProfile.CONNECTION_POLICY_ALLOWED;
4329             case BluetoothProfile.PRIORITY_OFF:
4330                 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
4331             case BluetoothProfile.PRIORITY_UNDEFINED:
4332                 return BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
4333             default:
4334                 Log.e(TAG, "setPriority: Invalid priority: " + priority);
4335                 return BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
4336         }
4337     }
4338 
4339     /**
4340      * Converts new constant of connection policy to the old for priority
4341      *
4342      * @param connectionPolicy is the connection policy to convert to priority
4343      * @return the equivalent priority constant to the connectionPolicy
4344      *
4345      * @hide
4346      */
connectionPolicyToPriority(@onnectionPolicy int connectionPolicy)4347     public static int connectionPolicyToPriority(@ConnectionPolicy int connectionPolicy) {
4348         switch(connectionPolicy) {
4349             case BluetoothProfile.CONNECTION_POLICY_ALLOWED:
4350                 return BluetoothProfile.PRIORITY_ON;
4351             case BluetoothProfile.CONNECTION_POLICY_FORBIDDEN:
4352                 return BluetoothProfile.PRIORITY_OFF;
4353             case BluetoothProfile.CONNECTION_POLICY_UNKNOWN:
4354                 return BluetoothProfile.PRIORITY_UNDEFINED;
4355         }
4356         return BluetoothProfile.PRIORITY_UNDEFINED;
4357     }
4358 }
4359