1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.uwb;
18 
19 import static com.android.internal.util.Preconditions.checkNotNull;
20 
21 import android.Manifest.permission;
22 import android.annotation.CallbackExecutor;
23 import android.annotation.FlaggedApi;
24 import android.annotation.IntDef;
25 import android.annotation.IntRange;
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.annotation.RequiresPermission;
29 import android.annotation.SuppressLint;
30 import android.annotation.SystemApi;
31 import android.annotation.SystemService;
32 import android.content.Context;
33 import android.os.Binder;
34 import android.os.Build;
35 import android.os.CancellationSignal;
36 import android.os.PersistableBundle;
37 import android.os.RemoteException;
38 import android.util.Log;
39 
40 import androidx.annotation.RequiresApi;
41 
42 import com.android.internal.annotations.GuardedBy;
43 
44 import java.lang.annotation.Retention;
45 import java.lang.annotation.RetentionPolicy;
46 import java.util.List;
47 import java.util.Objects;
48 import java.util.concurrent.Executor;
49 import java.util.function.Consumer;
50 
51 /**
52  * This class provides a way to perform Ultra Wideband (UWB) operations such as querying the
53  * device's capabilities and determining the distance and angle between the local device and a
54  * remote device.
55  *
56  * <p>To get a {@link UwbManager}, call the <code>Context.getSystemService(UwbManager.class)</code>.
57  *
58  * <p> Note: This API surface uses opaque {@link PersistableBundle} params. These params are to be
59  * created using the provided UWB support library. The support library is present in this
60  * location on AOSP: <code>packages/modules/Uwb/service/support_lib/</code>
61  *
62  * @hide
63  */
64 @SystemApi
65 @SystemService(Context.UWB_SERVICE)
66 public final class UwbManager {
67     private static final String TAG = "UwbManager";
68 
69     private final Context mContext;
70     private final IUwbAdapter mUwbAdapter;
71     private final AdapterStateListener mAdapterStateListener;
72     private final RangingManager mRangingManager;
73     private final UwbVendorUciCallbackListener mUwbVendorUciCallbackListener;
74     private final UwbOemExtensionCallbackListener mUwbOemExtensionCallbackListener;
75 
76     /**
77      * Interface for receiving UWB adapter state changes
78      */
79     public interface AdapterStateCallback {
80         /**
81          * @hide
82          */
83         @Retention(RetentionPolicy.SOURCE)
84         @IntDef(value = {
85                 STATE_CHANGED_REASON_SESSION_STARTED,
86                 STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED,
87                 STATE_CHANGED_REASON_SYSTEM_POLICY,
88                 STATE_CHANGED_REASON_SYSTEM_BOOT,
89                 STATE_CHANGED_REASON_ERROR_UNKNOWN,
90                 STATE_CHANGED_REASON_SYSTEM_REGULATION})
91         @interface StateChangedReason {}
92 
93         /**
94          * @hide
95          */
96         @Retention(RetentionPolicy.SOURCE)
97         @IntDef(value = {
98                 STATE_ENABLED_INACTIVE,
99                 STATE_ENABLED_ACTIVE,
100                 STATE_DISABLED,
101                 STATE_ENABLED_HW_IDLE})
102         @interface State {}
103 
104         /**
105          * Indicates that the state change was due to opening of first UWB session
106          */
107         int STATE_CHANGED_REASON_SESSION_STARTED = 0;
108 
109         /**
110          * Indicates that the state change was due to closure of all UWB sessions
111          */
112         int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1;
113 
114         /**
115          * Indicates that the state change was due to changes in system policy
116          */
117         int STATE_CHANGED_REASON_SYSTEM_POLICY = 2;
118 
119         /**
120          * Indicates that the current state is due to a system boot
121          */
122         int STATE_CHANGED_REASON_SYSTEM_BOOT = 3;
123 
124         /**
125          * Indicates that the state change was due to some unknown error
126          */
127         int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4;
128 
129         /**
130          * Indicates that the state change is due to a system regulation.
131          */
132         int STATE_CHANGED_REASON_SYSTEM_REGULATION = 5;
133 
134         /**
135          * Indicates that UWB is disabled on device
136          */
137         int STATE_DISABLED = 0;
138         /**
139          * Indicates that UWB is enabled on device but has no active ranging sessions
140          */
141         int STATE_ENABLED_INACTIVE = 1;
142 
143         /**
144          * Indicates that UWB is enabled and has active ranging session
145          */
146         int STATE_ENABLED_ACTIVE = 2;
147 
148         /**
149          * The state when UWB is enabled by user but the hardware is not enabled since no clients
150          * have requested for it.
151          * Only sent if the device supports {@link #isUwbHwIdleTurnOffEnabled()} feature.
152          */
153         @FlaggedApi("com.android.uwb.flags.hw_state")
154         int STATE_ENABLED_HW_IDLE = 3;
155 
156         /**
157          * Invoked when underlying UWB adapter's state is changed
158          * <p>Invoked with the adapter's current state after registering an
159          * {@link AdapterStateCallback} using
160          * {@link UwbManager#registerAdapterStateCallback(Executor, AdapterStateCallback)}.
161          *
162          * <p>Possible reasons for the state to change are
163          * {@link #STATE_CHANGED_REASON_SESSION_STARTED},
164          * {@link #STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED},
165          * {@link #STATE_CHANGED_REASON_SYSTEM_POLICY},
166          * {@link #STATE_CHANGED_REASON_SYSTEM_BOOT},
167          * {@link #STATE_CHANGED_REASON_ERROR_UNKNOWN}.
168          * {@link #STATE_CHANGED_REASON_SYSTEM_REGULATION}.
169          *
170          * <p>Possible values for the UWB state are
171          * {@link #STATE_ENABLED_INACTIVE},
172          * {@link #STATE_ENABLED_ACTIVE},
173          * {@link #STATE_DISABLED}.
174          *
175          * @param state the UWB state; inactive, active or disabled
176          * @param reason the reason for the state change
177          */
onStateChanged(@tate int state, @StateChangedReason int reason)178         void onStateChanged(@State int state, @StateChangedReason int reason);
179     }
180 
181     /**
182      * Abstract class for receiving ADF provisioning state.
183      * Should be extended by applications and set when calling
184      * {@link UwbManager#provisionProfileAdfByScript(PersistableBundle, Executor,
185      * AdfProvisionStateCallback)}
186      */
187     public abstract static class AdfProvisionStateCallback {
188         private final AdfProvisionStateCallbackProxy mAdfProvisionStateCallbackProxy;
189 
AdfProvisionStateCallback()190         public AdfProvisionStateCallback() {
191             mAdfProvisionStateCallbackProxy = new AdfProvisionStateCallbackProxy();
192         }
193 
194         /**
195          * @hide
196          */
197         @Retention(RetentionPolicy.SOURCE)
198         @IntDef(value = {
199                 REASON_INVALID_OID,
200                 REASON_SE_FAILURE,
201                 REASON_UNKNOWN
202         })
203         @interface Reason { }
204 
205         /**
206          * Indicates that the OID provided was not valid.
207          */
208         public static final int REASON_INVALID_OID = 1;
209 
210         /**
211          * Indicates that there was some SE (secure element) failure while provisioning.
212          */
213         public static final int REASON_SE_FAILURE = 2;
214 
215         /**
216          * No known reason for the failure.
217          */
218         public static final int REASON_UNKNOWN = 3;
219 
220         /**
221          * Invoked when {@link UwbManager#provisionProfileAdfByScript(PersistableBundle, Executor,
222          * AdfProvisionStateCallback)} is successful.
223          *
224          * @param params protocol specific params that provide the caller with provisioning info
225          **/
onProfileAdfsProvisioned(@onNull PersistableBundle params)226         public abstract void onProfileAdfsProvisioned(@NonNull PersistableBundle params);
227 
228         /**
229          * Invoked when {@link UwbManager#provisionProfileAdfByScript(PersistableBundle, Executor,
230          * AdfProvisionStateCallback)} fails.
231          *
232          * @param reason Reason for failure
233          * @param params protocol specific parameters to indicate failure reason
234          */
onProfileAdfsProvisionFailed( @eason int reason, @NonNull PersistableBundle params)235         public abstract void onProfileAdfsProvisionFailed(
236                 @Reason int reason, @NonNull PersistableBundle params);
237 
238         /*package*/
239         @NonNull
getProxy()240         AdfProvisionStateCallbackProxy getProxy() {
241             return mAdfProvisionStateCallbackProxy;
242         }
243 
244         private static class AdfProvisionStateCallbackProxy extends
245                 IUwbAdfProvisionStateCallbacks.Stub {
246             private final Object mLock = new Object();
247             @Nullable
248             @GuardedBy("mLock")
249             private Executor mExecutor;
250             @Nullable
251             @GuardedBy("mLock")
252             private AdfProvisionStateCallback mCallback;
253 
AdfProvisionStateCallbackProxy()254             AdfProvisionStateCallbackProxy() {
255                 mCallback = null;
256                 mExecutor = null;
257             }
258 
initProxy(@onNull Executor executor, @NonNull AdfProvisionStateCallback callback)259             /*package*/ void initProxy(@NonNull Executor executor,
260                     @NonNull AdfProvisionStateCallback callback) {
261                 synchronized (mLock) {
262                     mExecutor = executor;
263                     mCallback = callback;
264                 }
265             }
266 
cleanUpProxy()267             /*package*/ void cleanUpProxy() {
268                 synchronized (mLock) {
269                     mExecutor = null;
270                     mCallback = null;
271                 }
272             }
273 
274             @Override
onProfileAdfsProvisioned(@onNull PersistableBundle params)275             public void onProfileAdfsProvisioned(@NonNull PersistableBundle params) {
276                 Log.v(TAG, "AdfProvisionStateCallbackProxy: onProfileAdfsProvisioned : " + params);
277                 AdfProvisionStateCallback callback;
278                 Executor executor;
279                 synchronized (mLock) {
280                     executor = mExecutor;
281                     callback = mCallback;
282                 }
283                 if (callback == null || executor == null) {
284                     return;
285                 }
286                 Binder.clearCallingIdentity();
287                 executor.execute(() -> callback.onProfileAdfsProvisioned(params));
288                 cleanUpProxy();
289             }
290 
291             @Override
onProfileAdfsProvisionFailed(@dfProvisionStateCallback.Reason int reason, @NonNull PersistableBundle params)292             public void onProfileAdfsProvisionFailed(@AdfProvisionStateCallback.Reason int reason,
293                     @NonNull PersistableBundle params) {
294                 Log.v(TAG, "AdfProvisionStateCallbackProxy: onProfileAdfsProvisionFailed : "
295                         + reason + ", " + params);
296                 AdfProvisionStateCallback callback;
297                 Executor executor;
298                 synchronized (mLock) {
299                     executor = mExecutor;
300                     callback = mCallback;
301                 }
302                 if (callback == null || executor == null) {
303                     return;
304                 }
305                 Binder.clearCallingIdentity();
306                 executor.execute(() -> callback.onProfileAdfsProvisionFailed(reason, params));
307                 cleanUpProxy();
308             }
309         }
310     }
311 
312     /**
313      * Interface for receiving vendor UCI responses and notifications.
314      */
315     public interface UwbVendorUciCallback {
316         /**
317          * Invoked when a vendor specific UCI response is received.
318          *
319          * @param gid Group ID of the command. This needs to be one of the vendor reserved GIDs from
320          *            the UCI specification.
321          * @param oid Opcode ID of the command. This is left to the OEM / vendor to decide.
322          * @param payload containing vendor Uci message payload.
323          */
onVendorUciResponse( @ntRangefrom = 0, to = 15) int gid, int oid, @NonNull byte[] payload)324         void onVendorUciResponse(
325                 @IntRange(from = 0, to = 15) int gid, int oid, @NonNull byte[] payload);
326 
327         /**
328          * Invoked when a vendor specific UCI notification is received.
329          *
330          * @param gid Group ID of the command. This needs to be one of the vendor reserved GIDs from
331          *            the UCI specification.
332          * @param oid Opcode ID of the command. This is left to the OEM / vendor to decide.
333          * @param payload containing vendor Uci message payload.
334          */
onVendorUciNotification( @ntRangefrom = 9, to = 15) int gid, int oid, @NonNull byte[] payload)335         void onVendorUciNotification(
336                 @IntRange(from = 9, to = 15) int gid, int oid, @NonNull byte[] payload);
337     }
338 
339 
340     /**
341      * @hide
342      * Vendor configuration successful for the session
343      */
344     public static final int VENDOR_SET_SESSION_CONFIGURATION_SUCCESS = 0;
345 
346     /**
347      * @hide
348      * Failure to set vendor configuration for the session
349      */
350     public static final int VENDOR_SET_SESSION_CONFIGURATION_FAILURE = 1;
351 
352     /**
353      * @hide
354      */
355     @Retention(RetentionPolicy.SOURCE)
356     @IntDef(value = {
357             VENDOR_SET_SESSION_CONFIGURATION_SUCCESS,
358             VENDOR_SET_SESSION_CONFIGURATION_FAILURE,
359     })
360     @interface VendorConfigStatus {}
361 
362 
363     /**
364      * Interface for Oem extensions on ongoing session
365      */
366     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
367     public interface UwbOemExtensionCallback {
368         /**
369          * Invoked when session status changes.
370          *
371          * @param sessionStatusBundle session related info
372          */
onSessionStatusNotificationReceived(@onNull PersistableBundle sessionStatusBundle)373         void onSessionStatusNotificationReceived(@NonNull PersistableBundle sessionStatusBundle);
374 
375         /**
376          * Invoked when DeviceStatusNotification is received from UCI.
377          *
378          * @param deviceStatusBundle device state
379          */
onDeviceStatusNotificationReceived(@onNull PersistableBundle deviceStatusBundle)380         void onDeviceStatusNotificationReceived(@NonNull PersistableBundle deviceStatusBundle);
381 
382         /**
383          * Invoked when session configuration is complete.
384          *
385          * @param openSessionBundle Session Params
386          * @return Error code
387          */
onSessionConfigurationComplete( @onNull PersistableBundle openSessionBundle)388         @NonNull @VendorConfigStatus int onSessionConfigurationComplete(
389                 @NonNull PersistableBundle openSessionBundle);
390 
391         /**
392          * Invoked when ranging report is generated.
393          *
394          * @param rangingReport ranging report generated
395          * @return Oem modified ranging report
396          */
onRangingReportReceived( @onNull RangingReport rangingReport)397         @NonNull RangingReport onRangingReportReceived(
398                 @NonNull RangingReport rangingReport);
399 
400         /**
401          * Invoked to check pointed target decision by Oem.
402          *
403          * @param pointedTargetBundle pointed target params
404          * @return Oem pointed status
405          */
onCheckPointedTarget(@onNull PersistableBundle pointedTargetBundle)406         boolean onCheckPointedTarget(@NonNull PersistableBundle pointedTargetBundle);
407     }
408 
409     /**
410      * Use <code>Context.getSystemService(UwbManager.class)</code> to get an instance.
411      *
412      * @param ctx Context of the client.
413      * @param adapter an instance of an {@link android.uwb.IUwbAdapter}
414      * @hide
415      */
UwbManager(@onNull Context ctx, @NonNull IUwbAdapter adapter)416     public UwbManager(@NonNull Context ctx, @NonNull IUwbAdapter adapter) {
417         mContext = ctx;
418         mUwbAdapter = adapter;
419         mAdapterStateListener = new AdapterStateListener(adapter);
420         mRangingManager = new RangingManager(adapter);
421         mUwbVendorUciCallbackListener = new UwbVendorUciCallbackListener(adapter);
422         mUwbOemExtensionCallbackListener = new UwbOemExtensionCallbackListener(adapter);
423     }
424 
425     /**
426      * Register an {@link AdapterStateCallback} to listen for UWB adapter state changes
427      * <p>The provided callback will be invoked by the given {@link Executor}.
428      *
429      * <p>When first registering a callback, the callbacks's
430      * {@link AdapterStateCallback#onStateChanged(int, int)} is immediately invoked to indicate
431      * the current state of the underlying UWB adapter with the most recent
432      * {@link AdapterStateCallback.StateChangedReason} that caused the change.
433      *
434      * @param executor an {@link Executor} to execute given callback
435      * @param callback user implementation of the {@link AdapterStateCallback}
436      */
437     @RequiresPermission(permission.UWB_PRIVILEGED)
registerAdapterStateCallback(@onNull @allbackExecutor Executor executor, @NonNull AdapterStateCallback callback)438     public void registerAdapterStateCallback(@NonNull @CallbackExecutor Executor executor,
439             @NonNull AdapterStateCallback callback) {
440         mAdapterStateListener.register(executor, callback);
441     }
442 
443     /**
444      * Unregister the specified {@link AdapterStateCallback}
445      * <p>The same {@link AdapterStateCallback} object used when calling
446      * {@link #registerAdapterStateCallback(Executor, AdapterStateCallback)} must be used.
447      *
448      * <p>Callbacks are automatically unregistered when application process goes away
449      *
450      * @param callback user implementation of the {@link AdapterStateCallback}
451      */
452     @RequiresPermission(permission.UWB_PRIVILEGED)
unregisterAdapterStateCallback(@onNull AdapterStateCallback callback)453     public void unregisterAdapterStateCallback(@NonNull AdapterStateCallback callback) {
454         mAdapterStateListener.unregister(callback);
455     }
456 
457     /**
458      * Register an {@link UwbVendorUciCallback} to listen for UWB vendor responses and notifications
459      * <p>The provided callback will be invoked by the given {@link Executor}.
460      *
461      * <p>When first registering a callback, the callbacks's
462      * {@link UwbVendorUciCallback#onVendorUciCallBack(byte[])} is immediately invoked to
463      * notify the vendor notification.
464      *
465      * @param executor an {@link Executor} to execute given callback
466      * @param callback user implementation of the {@link UwbVendorUciCallback}
467      */
468     @RequiresPermission(permission.UWB_PRIVILEGED)
registerUwbVendorUciCallback(@onNull @allbackExecutor Executor executor, @NonNull UwbVendorUciCallback callback)469     public void registerUwbVendorUciCallback(@NonNull @CallbackExecutor Executor executor,
470             @NonNull UwbVendorUciCallback callback) {
471         mUwbVendorUciCallbackListener.register(executor, callback);
472     }
473 
474     /**
475      * Unregister the specified {@link UwbVendorUciCallback}
476      *
477      * <p>The same {@link UwbVendorUciCallback} object used when calling
478      * {@link #registerUwbVendorUciCallback(Executor, UwbVendorUciCallback)} must be used.
479      *
480      * <p>Callbacks are automatically unregistered when application process goes away
481      *
482      * @param callback user implementation of the {@link UwbVendorUciCallback}
483      */
unregisterUwbVendorUciCallback(@onNull UwbVendorUciCallback callback)484     public void unregisterUwbVendorUciCallback(@NonNull UwbVendorUciCallback callback) {
485         mUwbVendorUciCallbackListener.unregister(callback);
486     }
487 
488     /**
489      * Register an {@link UwbOemExtensionCallback} to listen for UWB oem extension callbacks
490      * <p>The provided callback will be invoked by the given {@link Executor}.
491      *
492      * @param executor an {@link Executor} to execute given callback
493      * @param callback oem implementation of {@link UwbOemExtensionCallback}
494      */
495     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
496     @RequiresPermission(permission.UWB_PRIVILEGED)
registerUwbOemExtensionCallback(@onNull @allbackExecutor Executor executor, @NonNull UwbOemExtensionCallback callback)497     public void registerUwbOemExtensionCallback(@NonNull @CallbackExecutor Executor executor,
498             @NonNull UwbOemExtensionCallback callback) {
499         mUwbOemExtensionCallbackListener.register(executor, callback);
500     }
501 
502     /**
503      * Unregister the specified {@link UwbOemExtensionCallback}
504      *
505      * <p>The same {@link UwbOemExtensionCallback} object used when calling
506      * {@link #registerUwbOemExtensionCallback(Executor, UwbOemExtensionCallback)} must be used.
507      *
508      * <p>Callbacks are automatically unregistered when an application process goes away
509      *
510      * @param callback oem implementation of {@link UwbOemExtensionCallback}
511      */
512     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
513     @RequiresPermission(permission.UWB_PRIVILEGED)
unregisterUwbOemExtensionCallback(@onNull UwbOemExtensionCallback callback)514     public void unregisterUwbOemExtensionCallback(@NonNull UwbOemExtensionCallback callback) {
515         mUwbOemExtensionCallbackListener.unregister(callback);
516     }
517 
518     /**
519      * Get a {@link PersistableBundle} with the supported UWB protocols and parameters.
520      * <p>The {@link PersistableBundle} should be parsed using a support library
521      *
522      * <p>Android reserves the '^android.*' namespace</p>
523      *
524      * @return {@link PersistableBundle} of the device's supported UWB protocols and parameters
525      */
526     @NonNull
527     @RequiresPermission(permission.UWB_PRIVILEGED)
getSpecificationInfo()528     public PersistableBundle getSpecificationInfo() {
529         return getSpecificationInfoInternal(/* chipId= */ null);
530     }
531 
532     /**
533      * Get a {@link PersistableBundle} with the supported UWB protocols and parameters.
534      *
535      * @see #getSpecificationInfo() if you don't need multi-HAL support
536      *
537      * @param chipId identifier of UWB chip for multi-HAL devices
538      *
539      * @return {@link PersistableBundle} of the device's supported UWB protocols and parameters
540      */
541     // TODO(b/205614701): Add documentation about how to find the relevant chipId
542     @NonNull
543     @RequiresPermission(permission.UWB_PRIVILEGED)
getSpecificationInfo(@onNull String chipId)544     public PersistableBundle getSpecificationInfo(@NonNull String chipId) {
545         checkNotNull(chipId);
546         return getSpecificationInfoInternal(chipId);
547     }
548 
getSpecificationInfoInternal(String chipId)549     private PersistableBundle getSpecificationInfoInternal(String chipId) {
550         try {
551             return mUwbAdapter.getSpecificationInfo(chipId);
552         } catch (RemoteException e) {
553             throw e.rethrowFromSystemServer();
554         }
555     }
556 
557     /**
558      * Get uwbs timestamp in micros.
559      *
560      * @return uwb device timestamp in micros.
561      */
562     @NonNull
563     @RequiresPermission(permission.UWB_PRIVILEGED)
564     @FlaggedApi("com.android.uwb.flags.query_timestamp_micros")
queryUwbsTimestampMicros()565     public long queryUwbsTimestampMicros() {
566         try {
567             return mUwbAdapter.queryUwbsTimestampMicros();
568         } catch (RemoteException e) {
569             throw e.rethrowFromSystemServer();
570         }
571     }
572 
573     /**
574      * Get the timestamp resolution for events in nanoseconds
575      * <p>This value defines the maximum error of all timestamps for events reported to
576      * {@link RangingSession.Callback}.
577      *
578      * @return the timestamp resolution in nanoseconds
579      */
580     @SuppressLint("MethodNameUnits")
581     @RequiresPermission(permission.UWB_PRIVILEGED)
elapsedRealtimeResolutionNanos()582     public long elapsedRealtimeResolutionNanos() {
583         return elapsedRealtimeResolutionNanosInternal(/* chipId= */ null);
584     }
585 
586     /**
587      * Get the timestamp resolution for events in nanoseconds
588      *
589      * @see #elapsedRealtimeResolutionNanos() if you don't need multi-HAL support
590      *
591      * @param chipId identifier of UWB chip for multi-HAL devices
592      *
593      * @return the timestamp resolution in nanoseconds
594      */
595     @SuppressLint("MethodNameUnits")
596     @RequiresPermission(permission.UWB_PRIVILEGED)
elapsedRealtimeResolutionNanos(@onNull String chipId)597     public long elapsedRealtimeResolutionNanos(@NonNull String chipId) {
598         checkNotNull(chipId);
599         return elapsedRealtimeResolutionNanosInternal(chipId);
600     }
601 
elapsedRealtimeResolutionNanosInternal(String chipId)602     private long elapsedRealtimeResolutionNanosInternal(String chipId) {
603         try {
604             return mUwbAdapter.getTimestampResolutionNanos(chipId);
605         } catch (RemoteException e) {
606             throw e.rethrowFromSystemServer();
607         }
608     }
609 
610     /**
611      * Open a {@link RangingSession} with the given parameters
612      * <p>The {@link RangingSession.Callback#onOpened(RangingSession)} function is called with a
613      * {@link RangingSession} object used to control ranging when the session is successfully
614      * opened.
615      *
616      * if this session uses FIRA defined profile (not custom profile), this triggers:
617      *   - OOB discovery using service UUID
618      *   - OOB connection establishment after discovery for session params
619      *     negotiation.
620      *   - Secure element interactions needed for dynamic STS based session establishment.
621      *   - Setup the UWB session based on the parameters negotiated via OOB.
622      *   - Note: The OOB flow requires additional BLE Permissions
623      *     {permission.BLUETOOTH_ADVERTISE/permission.BLUETOOTH_SCAN
624      *      and permission.BLUETOOTH_CONNECT}.
625      *
626      * <p>If a session cannot be opened, then
627      * {@link RangingSession.Callback#onClosed(int, PersistableBundle)} will be invoked with the
628      * appropriate {@link RangingSession.Callback.Reason}.
629      *
630      * <p>An open {@link RangingSession} will be automatically closed if client application process
631      * dies.
632      *
633      * <p>A UWB support library must be used in order to construct the {@code parameter}
634      * {@link PersistableBundle}.
635      *
636      * @param parameters the parameters that define the ranging session
637      * @param executor {@link Executor} to run callbacks
638      * @param callbacks {@link RangingSession.Callback} to associate with the
639      *                  {@link RangingSession} that is being opened.
640      *
641      * @return an {@link CancellationSignal} that is able to be used to cancel the opening of a
642      *         {@link RangingSession} that has been requested through {@link #openRangingSession}
643      *         but has not yet been made available by
644      *         {@link RangingSession.Callback#onOpened(RangingSession)}.
645      */
646     @NonNull
647     @RequiresPermission(allOf = {
648             permission.UWB_PRIVILEGED,
649             permission.UWB_RANGING
650     })
openRangingSession(@onNull PersistableBundle parameters, @NonNull @CallbackExecutor Executor executor, @NonNull RangingSession.Callback callbacks)651     public CancellationSignal openRangingSession(@NonNull PersistableBundle parameters,
652             @NonNull @CallbackExecutor Executor executor,
653             @NonNull RangingSession.Callback callbacks) {
654         return openRangingSessionInternal(parameters, executor, callbacks, /* chipId= */ null);
655     }
656 
657     /**
658      * Open a {@link RangingSession} with the given parameters on a specific UWB subsystem
659      *
660      * @see #openRangingSession(PersistableBundle, Executor, RangingSession.Callback) if you don't
661      * need multi-HAL support
662      *
663      * @param parameters the parameters that define the ranging session
664      * @param executor {@link Executor} to run callbacks
665      * @param callbacks {@link RangingSession.Callback} to associate with the
666      *                  {@link RangingSession} that is being opened.
667      * @param chipId identifier of UWB chip for multi-HAL devices
668      *
669      * @return an {@link CancellationSignal} that is able to be used to cancel the opening of a
670      *         {@link RangingSession} that has been requested through {@link #openRangingSession}
671      *         but has not yet been made available by
672      *         {@link RangingSession.Callback#onOpened(RangingSession)}.
673      */
674     @NonNull
675     @RequiresPermission(allOf = {
676             permission.UWB_PRIVILEGED,
677             permission.UWB_RANGING
678     })
openRangingSession(@onNull PersistableBundle parameters, @NonNull @CallbackExecutor Executor executor, @NonNull RangingSession.Callback callbacks, @SuppressLint("ListenerLast") @NonNull String chipId)679     public CancellationSignal openRangingSession(@NonNull PersistableBundle parameters,
680             @NonNull @CallbackExecutor Executor executor,
681             @NonNull RangingSession.Callback callbacks,
682             @SuppressLint("ListenerLast") @NonNull String chipId) {
683         checkNotNull(chipId);
684         return openRangingSessionInternal(parameters, executor, callbacks, chipId);
685     }
686 
openRangingSessionInternal(PersistableBundle parameters, Executor executor, RangingSession.Callback callbacks, String chipId)687     private CancellationSignal openRangingSessionInternal(PersistableBundle parameters,
688             Executor executor, RangingSession.Callback callbacks, String chipId) {
689         return mRangingManager.openSession(
690                 mContext.getAttributionSource(), parameters, executor, callbacks, chipId);
691     }
692 
693     /**
694      * Returns the current enabled/disabled state for UWB.
695      *
696      * Possible values are:
697      * AdapterStateCallback#STATE_DISABLED
698      * AdapterStateCallback#STATE_ENABLED_INACTIVE
699      * AdapterStateCallback#STATE_ENABLED_ACTIVE
700      *
701      * @return value representing current enabled/disabled state for UWB.
702      */
getAdapterState()703     public @AdapterStateCallback.State int getAdapterState() {
704         return mAdapterStateListener.getAdapterState();
705     }
706 
707     /**
708      * Whether UWB is enabled or disabled.
709      *
710      * <p>
711      * If disabled, this could indicate that either
712      * <li> User has toggled UWB off from settings, OR </li>
713      * <li> UWB subsystem has shut down due to a fatal error. </li>
714      * </p>
715      *
716      * @return true if enabled, false otherwise.
717      *
718      * @see #getAdapterState()
719      * @see #setUwbEnabled(boolean)
720      */
isUwbEnabled()721     public boolean isUwbEnabled() {
722         int adapterState = getAdapterState();
723         return adapterState != AdapterStateCallback.STATE_DISABLED;
724     }
725 
726     /**
727      * Disables or enables UWB by the user.
728      *
729      * If enabled any subsequent calls to
730      * {@link #openRangingSession(PersistableBundle, Executor, RangingSession.Callback)} will be
731      * allowed. If disabled, all active ranging sessions will be closed and subsequent calls to
732      * {@link #openRangingSession(PersistableBundle, Executor, RangingSession.Callback)} will be
733      * disallowed.
734      *
735      * @param enabled value representing intent to disable or enable UWB.
736      */
737     @RequiresPermission(permission.UWB_PRIVILEGED)
setUwbEnabled(boolean enabled)738     public void setUwbEnabled(boolean enabled) {
739         mAdapterStateListener.setEnabled(enabled);
740     }
741 
742     /**
743      * Whether UWB hardware will automatically turn off when there are no clients requesting it.
744      * This feature is only turned on non-phone form factor devices which needs to keep the UWB
745      * hardware turned to avoid battery drain.
746      *
747      * <p>
748      * If the device supports automatically turning off UWB hardware, the state of UWB hardware
749      * is controlled by:
750      * <li> UWB user toggle state or Airplane mode state, AND </li>
751      * <li> Whether any clients are actively enabling UWB </li>
752      * </p>
753      *
754      * @return true if enabled, false otherwise.
755      *
756      * @see #isUwbHwEnableRequested()
757      * @see #requestUwbHwEnable(boolean)
758      */
759     @FlaggedApi("com.android.uwb.flags.hw_state")
760     @RequiresPermission(permission.UWB_PRIVILEGED)
isUwbHwIdleTurnOffEnabled()761     public boolean isUwbHwIdleTurnOffEnabled() {
762         try {
763             return mUwbAdapter.isHwIdleTurnOffEnabled();
764         } catch (RemoteException e) {
765             throw e.rethrowFromSystemServer();
766         }
767     }
768 
769     /**
770      * Whether this client has requested for UWB hardware to be enabled or disabled.
771      * Only supported on devices which supports hw idle turn off (indicated by
772      * {@link #isUwbHwIdleTurnOffEnabled()})
773      *
774      * <p>
775      * This does not indicate the global state of UWB, this only indicates whether this app
776      * (identified by {@link Context#getAttributionSource()}) has requested for UWB hardware to be
777      * enabled or disabled.
778      * </p>
779      *
780      * @return true if enabled, false otherwise.
781      * @throws IllegalStateException if the device does not support this feature
782      *
783      * @see #isUwbHwIdleTurnOffEnabled()
784      * @see #requestUwbHwEnable(boolean)
785      */
786     @FlaggedApi("com.android.uwb.flags.hw_state")
787     @RequiresPermission(permission.UWB_PRIVILEGED)
isUwbHwEnableRequested()788     public boolean isUwbHwEnableRequested() {
789         try {
790             return mUwbAdapter.isHwEnableRequested(mContext.getAttributionSource());
791         } catch (RemoteException e) {
792             throw e.rethrowFromSystemServer();
793         }
794     }
795 
796     /**
797      * This client has requested for UWB hardware to be enabled or disabled.
798      * Only supported on devices which supports hw idle turn off (indicated by
799      * {@link #isUwbHwIdleTurnOffEnabled()})
800      *
801      * <p>
802      * This does not indicate the global state of UWB, this only indicates whether this app
803      * (identified by {@link Context#getAttributionSource()}) has requested for UWB hardware to be
804      * enabled or disabled.
805      * If UWB is enabled by the user and has at least 1 privileged client requesting UWB toggle on,
806      * then UWB hardware is enabled, else the UWB hardware is disabled.
807      * </p>
808      *
809      * @param enabled value representing intent to disable or enable UWB.
810      * @throws IllegalStateException if the device does not support this feature
811      *
812      * @see #isUwbHwIdleTurnOffEnabled()
813      * @see #isUwbHwEnableRequested() ()
814      */
815     @FlaggedApi("com.android.uwb.flags.hw_state")
816     @RequiresPermission(permission.UWB_PRIVILEGED)
requestUwbHwEnabled(boolean enabled)817     public void requestUwbHwEnabled(boolean enabled) {
818         try {
819             mUwbAdapter.requestHwEnabled(
820                     enabled, mContext.getAttributionSource(),
821                     new Binder(mContext.getPackageName()));
822         } catch (RemoteException e) {
823             throw e.rethrowFromSystemServer();
824         }
825     }
826 
827     /**
828      * Returns a list of UWB chip infos in a {@link PersistableBundle}.
829      *
830      * Callers can invoke methods on a specific UWB chip by passing its {@code chipId} to the
831      * method, which can be determined by calling:
832      * <pre>
833      * List<PersistableBundle> chipInfos = getChipInfos();
834      * for (PersistableBundle chipInfo : chipInfos) {
835      *     String chipId = ChipInfoParams.fromBundle(chipInfo).getChipId();
836      * }
837      * </pre>
838      *
839      * @return list of {@link PersistableBundle} containing info about UWB chips for a multi-HAL
840      * system, or a list of info for a single chip for a single HAL system.
841      */
842     @RequiresPermission(permission.UWB_PRIVILEGED)
843     @NonNull
getChipInfos()844     public List<PersistableBundle> getChipInfos() {
845         try {
846             return mUwbAdapter.getChipInfos();
847         } catch (RemoteException e) {
848             throw e.rethrowFromSystemServer();
849         }
850     }
851 
852     /**
853      * Returns the default UWB chip identifier.
854      *
855      * If callers do not pass a specific {@code chipId} to UWB methods, then the method will be
856      * invoked on the default chip, which is determined at system initialization from a
857      * configuration file.
858      *
859      * @return default UWB chip identifier for a multi-HAL system, or the identifier of the only UWB
860      * chip in a single HAL system.
861      */
862     @RequiresPermission(permission.UWB_PRIVILEGED)
863     @NonNull
getDefaultChipId()864     public String getDefaultChipId() {
865         try {
866             return mUwbAdapter.getDefaultChipId();
867         } catch (RemoteException e) {
868             throw e.rethrowFromSystemServer();
869         }
870     }
871 
872     /**
873      * Register the UWB service profile.
874      * This profile instance is persisted by the platform until explicitly removed
875      * using {@link #removeServiceProfile(PersistableBundle)}
876      *
877      * @param parameters the parameters that define the service profile.
878      * @return Protocol specific params to be used as handle for triggering the profile.
879      */
880     @RequiresPermission(permission.UWB_PRIVILEGED)
881     @NonNull
addServiceProfile(@onNull PersistableBundle parameters)882     public PersistableBundle addServiceProfile(@NonNull PersistableBundle parameters) {
883         try {
884             return mUwbAdapter.addServiceProfile(parameters);
885         } catch (RemoteException e) {
886             throw e.rethrowFromSystemServer();
887         }
888     }
889 
890     /**
891      * Successfully removed the service profile.
892      */
893     public static final int REMOVE_SERVICE_PROFILE_SUCCESS = 0;
894 
895     /**
896      * Failed to remove service since the service profile is unknown.
897      */
898     public static final int REMOVE_SERVICE_PROFILE_ERROR_UNKNOWN_SERVICE = 1;
899 
900     /**
901      * Failed to remove service due to some internal error while processing the request.
902      */
903     public static final int REMOVE_SERVICE_PROFILE_ERROR_INTERNAL = 2;
904 
905     /**
906      * @hide
907      */
908     @Retention(RetentionPolicy.SOURCE)
909     @IntDef(value = {
910             REMOVE_SERVICE_PROFILE_SUCCESS,
911             REMOVE_SERVICE_PROFILE_ERROR_UNKNOWN_SERVICE,
912             REMOVE_SERVICE_PROFILE_ERROR_INTERNAL
913     })
914     @interface RemoveServiceProfile {}
915 
916     /**
917      * Remove the service profile registered with {@link #addServiceProfile} and
918      * all related resources.
919      *
920      * @param parameters the parameters that define the service profile.
921      *
922      * @return true if the service profile is removed, false otherwise.
923      */
924     @RequiresPermission(permission.UWB_PRIVILEGED)
removeServiceProfile(@onNull PersistableBundle parameters)925     public @RemoveServiceProfile int removeServiceProfile(@NonNull PersistableBundle parameters) {
926         try {
927             return mUwbAdapter.removeServiceProfile(parameters);
928         } catch (RemoteException e) {
929             throw e.rethrowFromSystemServer();
930         }
931     }
932 
933     /**
934      * Get all service profiles initialized with {@link #addServiceProfile}
935      *
936      * @return the parameters that define the service profiles.
937      */
938     @RequiresPermission(permission.UWB_PRIVILEGED)
939     @NonNull
getAllServiceProfiles()940     public PersistableBundle getAllServiceProfiles() {
941         try {
942             return mUwbAdapter.getAllServiceProfiles();
943         } catch (RemoteException e) {
944             throw e.rethrowFromSystemServer();
945         }
946     }
947 
948     /**
949      * Get the list of ADF (application defined file) provisioning authorities available for the UWB
950      * applet in SE (secure element).
951      *
952      * @param serviceProfileBundle Parameters representing the profile to use.
953      * @return The list of key information of ADF provisioning authority defined in FiRa
954      * CSML 8.2.2.7.2.4 and 8.2.2.14.4.1.2.
955      */
956     @RequiresPermission(permission.UWB_PRIVILEGED)
957     @NonNull
getAdfProvisioningAuthorities( @onNull PersistableBundle serviceProfileBundle)958     public PersistableBundle getAdfProvisioningAuthorities(
959             @NonNull PersistableBundle serviceProfileBundle) {
960         try {
961             return mUwbAdapter.getAdfProvisioningAuthorities(serviceProfileBundle);
962         } catch (RemoteException e) {
963             throw e.rethrowFromSystemServer();
964         }
965     }
966 
967     /**
968      * Get certificate information for the UWB applet in SE (secure element) that can be used to
969      * provision ADF (application defined file).
970      *
971      * @param serviceProfileBundle Parameters representing the profile to use.
972      * @return The Fira applet certificate information defined in FiRa CSML 7.3.4.3 and
973      * 8.2.2.14.4.1.1
974      */
975     @RequiresPermission(permission.UWB_PRIVILEGED)
976     @NonNull
getAdfCertificateInfo( @onNull PersistableBundle serviceProfileBundle)977     public PersistableBundle getAdfCertificateInfo(
978             @NonNull PersistableBundle serviceProfileBundle) {
979         try {
980             return mUwbAdapter.getAdfCertificateAndInfo(serviceProfileBundle);
981         } catch (RemoteException e) {
982             throw e.rethrowFromSystemServer();
983         }
984     }
985 
986     /**
987      * Mechanism to provision ADFs (application defined file) in the UWB applet present in SE
988      * (secure element) for a profile instance.
989      *
990      * @param serviceProfileBundle Parameters representing the profile to use.
991      * @param executor an {@link Executor} to execute given callback
992      * @param callback user implementation of the {@link AdapterStateCallback}
993      */
provisionProfileAdfByScript(@onNull PersistableBundle serviceProfileBundle, @NonNull @CallbackExecutor Executor executor, @NonNull AdfProvisionStateCallback callback)994     public void provisionProfileAdfByScript(@NonNull PersistableBundle serviceProfileBundle,
995             @NonNull @CallbackExecutor Executor executor,
996             @NonNull AdfProvisionStateCallback callback) {
997         if (executor == null) throw new IllegalArgumentException("executor must not be null");
998         if (callback == null) throw new IllegalArgumentException("callback must not be null");
999         AdfProvisionStateCallback.AdfProvisionStateCallbackProxy proxy = callback.getProxy();
1000         proxy.initProxy(executor, callback);
1001         try {
1002             mUwbAdapter.provisionProfileAdfByScript(serviceProfileBundle, proxy);
1003         } catch (RemoteException e) {
1004             throw e.rethrowFromSystemServer();
1005         }
1006     }
1007 
1008     /**
1009      * Successfully removed the profile ADF.
1010      */
1011     public static final int REMOVE_PROFILE_ADF_SUCCESS = 0;
1012 
1013     /**
1014      * Failed to remove ADF since the service profile is unknown.
1015      */
1016     public static final int REMOVE_PROFILE_ADF_ERROR_UNKNOWN_SERVICE = 1;
1017 
1018     /**
1019      * Failed to remove ADF due to some internal error while processing the request.
1020      */
1021     public static final int REMOVE_PROFILE_ADF_ERROR_INTERNAL = 2;
1022 
1023     /**
1024      * @hide
1025      */
1026     @Retention(RetentionPolicy.SOURCE)
1027     @IntDef(value = {
1028             REMOVE_PROFILE_ADF_SUCCESS,
1029             REMOVE_PROFILE_ADF_ERROR_UNKNOWN_SERVICE,
1030             REMOVE_PROFILE_ADF_ERROR_INTERNAL
1031     })
1032     @interface RemoveProfileAdf {}
1033 
1034     /**
1035      * Remove the ADF (application defined file) provisioned by {@link #provisionProfileAdfByScript}
1036      *
1037      * @param serviceProfileBundle Parameters representing the profile to use.
1038      * @return true if the ADF is removed, false otherwise.
1039      */
1040     @RequiresPermission(permission.UWB_PRIVILEGED)
removeProfileAdf(@onNull PersistableBundle serviceProfileBundle)1041     public @RemoveProfileAdf int removeProfileAdf(@NonNull PersistableBundle serviceProfileBundle) {
1042         try {
1043             return mUwbAdapter.removeProfileAdf(serviceProfileBundle);
1044         } catch (RemoteException e) {
1045             throw e.rethrowFromSystemServer();
1046         }
1047     }
1048 
1049     /**
1050      * Successfully sent the UCI message.
1051      */
1052     public static final int SEND_VENDOR_UCI_SUCCESS = 0;
1053 
1054     /**
1055      * Failed to send the UCI message because of an error returned from the HAL interface.
1056      */
1057     public static final int SEND_VENDOR_UCI_ERROR_HW = 1;
1058 
1059     /**
1060      * Failed to send the UCI message since UWB is toggled off.
1061      */
1062     public static final int SEND_VENDOR_UCI_ERROR_OFF = 2;
1063 
1064     /**
1065      * Failed to send the UCI message since UWB UCI command is malformed.
1066      * GID.
1067      */
1068     public static final int SEND_VENDOR_UCI_ERROR_INVALID_ARGS = 3;
1069 
1070     /**
1071      * Failed to send the UCI message since UWB GID used is invalid.
1072      */
1073     public static final int SEND_VENDOR_UCI_ERROR_INVALID_GID = 4;
1074 
1075     /**
1076      * @hide
1077      */
1078     @Retention(RetentionPolicy.SOURCE)
1079     @IntDef(value = {
1080             SEND_VENDOR_UCI_SUCCESS,
1081             SEND_VENDOR_UCI_ERROR_HW,
1082             SEND_VENDOR_UCI_ERROR_OFF,
1083             SEND_VENDOR_UCI_ERROR_INVALID_ARGS,
1084             SEND_VENDOR_UCI_ERROR_INVALID_GID,
1085     })
1086     @interface SendVendorUciStatus {}
1087 
1088     /**
1089      * Message Type for UCI Command.
1090      */
1091     public static final int MESSAGE_TYPE_COMMAND = 1;
1092     /**
1093      * Message Type for C-APDU (Command - Application Protocol Data Unit),
1094      * used for communication with secure component.
1095      */
1096     public static final int MESSAGE_TYPE_TEST_1 = 4;
1097 
1098     /**
1099      * Message Type for R-APDU (Response - Application Protocol Data Unit),
1100      * used for communication with secure component.
1101      */
1102     public static final int MESSAGE_TYPE_TEST_2 = 5;
1103 
1104     /**
1105      * @hide
1106      */
1107     @Retention(RetentionPolicy.SOURCE)
1108     @IntDef(value = {
1109             MESSAGE_TYPE_COMMAND,
1110             MESSAGE_TYPE_TEST_1,
1111             MESSAGE_TYPE_TEST_2,
1112     })
1113     @interface MessageType {}
1114 
1115     /**
1116      * Send Vendor specific Uci Messages.
1117      *
1118      * The format of the UCI messages are defined in the UCI specification. The platform is
1119      * responsible for fragmenting the payload if necessary.
1120      *
1121      * @param gid Group ID of the command. This needs to be one of the vendor reserved GIDs from
1122      *            the UCI specification.
1123      * @param oid Opcode ID of the command. This is left to the OEM / vendor to decide.
1124      * @param payload containing vendor Uci message payload.
1125      */
1126     @NonNull
1127     @RequiresPermission(permission.UWB_PRIVILEGED)
sendVendorUciMessage( @ntRangefrom = 0, to = 15) int gid, int oid, @NonNull byte[] payload)1128     public @SendVendorUciStatus int sendVendorUciMessage(
1129             @IntRange(from = 0, to = 15) int gid, int oid, @NonNull byte[] payload) {
1130         Objects.requireNonNull(payload, "Payload must not be null");
1131         try {
1132             return mUwbAdapter.sendVendorUciMessage(MESSAGE_TYPE_COMMAND, gid, oid, payload);
1133         } catch (RemoteException e) {
1134             throw e.rethrowFromSystemServer();
1135         }
1136     }
1137 
1138     /**
1139      * Send Vendor specific Uci Messages with custom message type.
1140      *
1141      * The format of the UCI messages are defined in the UCI specification. The platform is
1142      * responsible for fragmenting the payload if necessary.
1143      *
1144      * Note that mt (message type) is added at the beginning of method parameters as it is more
1145      * distinctive than other parameters and was requested from vendor.
1146      *
1147      * @param mt Message Type of the command
1148      * @param gid Group ID of the command. This needs to be one of the vendor reserved GIDs from
1149      *            the UCI specification
1150      * @param oid Opcode ID of the command. This is left to the OEM / vendor to decide
1151      * @param payload containing vendor Uci message payload
1152      */
1153     @NonNull
1154     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
1155     @RequiresPermission(permission.UWB_PRIVILEGED)
sendVendorUciMessage(@essageType int mt, @IntRange(from = 0, to = 15) int gid, int oid, @NonNull byte[] payload)1156     public @SendVendorUciStatus int sendVendorUciMessage(@MessageType int mt,
1157             @IntRange(from = 0, to = 15) int gid, int oid, @NonNull byte[] payload) {
1158         Objects.requireNonNull(payload, "Payload must not be null");
1159         try {
1160             return mUwbAdapter.sendVendorUciMessage(mt, gid, oid, payload);
1161         } catch (RemoteException e) {
1162             throw e.rethrowFromSystemServer();
1163         }
1164     }
1165 
1166     private static class OnUwbActivityEnergyInfoProxy
1167             extends IOnUwbActivityEnergyInfoListener.Stub {
1168         private final Object mLock = new Object();
1169         @Nullable @GuardedBy("mLock") private Executor mExecutor;
1170         @Nullable @GuardedBy("mLock") private Consumer<UwbActivityEnergyInfo> mListener;
1171 
OnUwbActivityEnergyInfoProxy(Executor executor, Consumer<UwbActivityEnergyInfo> listener)1172         OnUwbActivityEnergyInfoProxy(Executor executor,
1173                 Consumer<UwbActivityEnergyInfo> listener) {
1174             mExecutor = executor;
1175             mListener = listener;
1176         }
1177 
1178         @Override
onUwbActivityEnergyInfo(UwbActivityEnergyInfo info)1179         public void onUwbActivityEnergyInfo(UwbActivityEnergyInfo info) {
1180             Executor executor;
1181             Consumer<UwbActivityEnergyInfo> listener;
1182             synchronized (mLock) {
1183                 if (mExecutor == null || mListener == null) {
1184                     return;
1185                 }
1186                 executor = mExecutor;
1187                 listener = mListener;
1188                 // null out to allow garbage collection, prevent triggering listener more than once
1189                 mExecutor = null;
1190                 mListener = null;
1191             }
1192             Binder.clearCallingIdentity();
1193             executor.execute(() -> listener.accept(info));
1194         }
1195     }
1196 
1197     /**
1198      * Request to get the current {@link UwbActivityEnergyInfo} asynchronously.
1199      *
1200      * @param executor the executor that the listener will be invoked on
1201      * @param listener the listener that will receive the {@link UwbActivityEnergyInfo} object
1202      *                 when it becomes available. The listener will be triggered at most once for
1203      *                 each call to this method.
1204      */
1205     @RequiresPermission(permission.UWB_PRIVILEGED)
getUwbActivityEnergyInfoAsync( @onNull @allbackExecutor Executor executor, @NonNull Consumer<UwbActivityEnergyInfo> listener)1206     public void getUwbActivityEnergyInfoAsync(
1207             @NonNull @CallbackExecutor Executor executor,
1208             @NonNull Consumer<UwbActivityEnergyInfo> listener) {
1209         Objects.requireNonNull(executor, "executor cannot be null");
1210         Objects.requireNonNull(listener, "listener cannot be null");
1211         try {
1212             mUwbAdapter.getUwbActivityEnergyInfoAsync(
1213                     new OnUwbActivityEnergyInfoProxy(executor, listener));
1214         } catch (RemoteException e) {
1215             throw e.rethrowFromSystemServer();
1216         }
1217     }
1218 }
1219