1219 lines
45 KiB
Java
1219 lines
45 KiB
Java
![]() |
/*
|
||
|
* Copyright 2020 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.uwb;
|
||
|
|
||
|
import static com.android.internal.util.Preconditions.checkNotNull;
|
||
|
|
||
|
import android.Manifest.permission;
|
||
|
import android.annotation.CallbackExecutor;
|
||
|
import android.annotation.FlaggedApi;
|
||
|
import android.annotation.IntDef;
|
||
|
import android.annotation.IntRange;
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.annotation.RequiresPermission;
|
||
|
import android.annotation.SuppressLint;
|
||
|
import android.annotation.SystemApi;
|
||
|
import android.annotation.SystemService;
|
||
|
import android.content.Context;
|
||
|
import android.os.Binder;
|
||
|
import android.os.Build;
|
||
|
import android.os.CancellationSignal;
|
||
|
import android.os.PersistableBundle;
|
||
|
import android.os.RemoteException;
|
||
|
import android.util.Log;
|
||
|
|
||
|
import androidx.annotation.RequiresApi;
|
||
|
|
||
|
import com.android.internal.annotations.GuardedBy;
|
||
|
|
||
|
import java.lang.annotation.Retention;
|
||
|
import java.lang.annotation.RetentionPolicy;
|
||
|
import java.util.List;
|
||
|
import java.util.Objects;
|
||
|
import java.util.concurrent.Executor;
|
||
|
import java.util.function.Consumer;
|
||
|
|
||
|
/**
|
||
|
* This class provides a way to perform Ultra Wideband (UWB) operations such as querying the
|
||
|
* device's capabilities and determining the distance and angle between the local device and a
|
||
|
* remote device.
|
||
|
*
|
||
|
* <p>To get a {@link UwbManager}, call the <code>Context.getSystemService(UwbManager.class)</code>.
|
||
|
*
|
||
|
* <p> Note: This API surface uses opaque {@link PersistableBundle} params. These params are to be
|
||
|
* created using the provided UWB support library. The support library is present in this
|
||
|
* location on AOSP: <code>packages/modules/Uwb/service/support_lib/</code>
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
@SystemApi
|
||
|
@SystemService(Context.UWB_SERVICE)
|
||
|
public final class UwbManager {
|
||
|
private static final String TAG = "UwbManager";
|
||
|
|
||
|
private final Context mContext;
|
||
|
private final IUwbAdapter mUwbAdapter;
|
||
|
private final AdapterStateListener mAdapterStateListener;
|
||
|
private final RangingManager mRangingManager;
|
||
|
private final UwbVendorUciCallbackListener mUwbVendorUciCallbackListener;
|
||
|
private final UwbOemExtensionCallbackListener mUwbOemExtensionCallbackListener;
|
||
|
|
||
|
/**
|
||
|
* Interface for receiving UWB adapter state changes
|
||
|
*/
|
||
|
public interface AdapterStateCallback {
|
||
|
/**
|
||
|
* @hide
|
||
|
*/
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
@IntDef(value = {
|
||
|
STATE_CHANGED_REASON_SESSION_STARTED,
|
||
|
STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED,
|
||
|
STATE_CHANGED_REASON_SYSTEM_POLICY,
|
||
|
STATE_CHANGED_REASON_SYSTEM_BOOT,
|
||
|
STATE_CHANGED_REASON_ERROR_UNKNOWN,
|
||
|
STATE_CHANGED_REASON_SYSTEM_REGULATION})
|
||
|
@interface StateChangedReason {}
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
*/
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
@IntDef(value = {
|
||
|
STATE_ENABLED_INACTIVE,
|
||
|
STATE_ENABLED_ACTIVE,
|
||
|
STATE_DISABLED,
|
||
|
STATE_ENABLED_HW_IDLE})
|
||
|
@interface State {}
|
||
|
|
||
|
/**
|
||
|
* Indicates that the state change was due to opening of first UWB session
|
||
|
*/
|
||
|
int STATE_CHANGED_REASON_SESSION_STARTED = 0;
|
||
|
|
||
|
/**
|
||
|
* Indicates that the state change was due to closure of all UWB sessions
|
||
|
*/
|
||
|
int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1;
|
||
|
|
||
|
/**
|
||
|
* Indicates that the state change was due to changes in system policy
|
||
|
*/
|
||
|
int STATE_CHANGED_REASON_SYSTEM_POLICY = 2;
|
||
|
|
||
|
/**
|
||
|
* Indicates that the current state is due to a system boot
|
||
|
*/
|
||
|
int STATE_CHANGED_REASON_SYSTEM_BOOT = 3;
|
||
|
|
||
|
/**
|
||
|
* Indicates that the state change was due to some unknown error
|
||
|
*/
|
||
|
int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4;
|
||
|
|
||
|
/**
|
||
|
* Indicates that the state change is due to a system regulation.
|
||
|
*/
|
||
|
int STATE_CHANGED_REASON_SYSTEM_REGULATION = 5;
|
||
|
|
||
|
/**
|
||
|
* Indicates that UWB is disabled on device
|
||
|
*/
|
||
|
int STATE_DISABLED = 0;
|
||
|
/**
|
||
|
* Indicates that UWB is enabled on device but has no active ranging sessions
|
||
|
*/
|
||
|
int STATE_ENABLED_INACTIVE = 1;
|
||
|
|
||
|
/**
|
||
|
* Indicates that UWB is enabled and has active ranging session
|
||
|
*/
|
||
|
int STATE_ENABLED_ACTIVE = 2;
|
||
|
|
||
|
/**
|
||
|
* The state when UWB is enabled by user but the hardware is not enabled since no clients
|
||
|
* have requested for it.
|
||
|
* Only sent if the device supports {@link #isUwbHwIdleTurnOffEnabled()} feature.
|
||
|
*/
|
||
|
@FlaggedApi("com.android.uwb.flags.hw_state")
|
||
|
int STATE_ENABLED_HW_IDLE = 3;
|
||
|
|
||
|
/**
|
||
|
* Invoked when underlying UWB adapter's state is changed
|
||
|
* <p>Invoked with the adapter's current state after registering an
|
||
|
* {@link AdapterStateCallback} using
|
||
|
* {@link UwbManager#registerAdapterStateCallback(Executor, AdapterStateCallback)}.
|
||
|
*
|
||
|
* <p>Possible reasons for the state to change are
|
||
|
* {@link #STATE_CHANGED_REASON_SESSION_STARTED},
|
||
|
* {@link #STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED},
|
||
|
* {@link #STATE_CHANGED_REASON_SYSTEM_POLICY},
|
||
|
* {@link #STATE_CHANGED_REASON_SYSTEM_BOOT},
|
||
|
* {@link #STATE_CHANGED_REASON_ERROR_UNKNOWN}.
|
||
|
* {@link #STATE_CHANGED_REASON_SYSTEM_REGULATION}.
|
||
|
*
|
||
|
* <p>Possible values for the UWB state are
|
||
|
* {@link #STATE_ENABLED_INACTIVE},
|
||
|
* {@link #STATE_ENABLED_ACTIVE},
|
||
|
* {@link #STATE_DISABLED}.
|
||
|
*
|
||
|
* @param state the UWB state; inactive, active or disabled
|
||
|
* @param reason the reason for the state change
|
||
|
*/
|
||
|
void onStateChanged(@State int state, @StateChangedReason int reason);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Abstract class for receiving ADF provisioning state.
|
||
|
* Should be extended by applications and set when calling
|
||
|
* {@link UwbManager#provisionProfileAdfByScript(PersistableBundle, Executor,
|
||
|
* AdfProvisionStateCallback)}
|
||
|
*/
|
||
|
public abstract static class AdfProvisionStateCallback {
|
||
|
private final AdfProvisionStateCallbackProxy mAdfProvisionStateCallbackProxy;
|
||
|
|
||
|
public AdfProvisionStateCallback() {
|
||
|
mAdfProvisionStateCallbackProxy = new AdfProvisionStateCallbackProxy();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
*/
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
@IntDef(value = {
|
||
|
REASON_INVALID_OID,
|
||
|
REASON_SE_FAILURE,
|
||
|
REASON_UNKNOWN
|
||
|
})
|
||
|
@interface Reason { }
|
||
|
|
||
|
/**
|
||
|
* Indicates that the OID provided was not valid.
|
||
|
*/
|
||
|
public static final int REASON_INVALID_OID = 1;
|
||
|
|
||
|
/**
|
||
|
* Indicates that there was some SE (secure element) failure while provisioning.
|
||
|
*/
|
||
|
public static final int REASON_SE_FAILURE = 2;
|
||
|
|
||
|
/**
|
||
|
* No known reason for the failure.
|
||
|
*/
|
||
|
public static final int REASON_UNKNOWN = 3;
|
||
|
|
||
|
/**
|
||
|
* Invoked when {@link UwbManager#provisionProfileAdfByScript(PersistableBundle, Executor,
|
||
|
* AdfProvisionStateCallback)} is successful.
|
||
|
*
|
||
|
* @param params protocol specific params that provide the caller with provisioning info
|
||
|
**/
|
||
|
public abstract void onProfileAdfsProvisioned(@NonNull PersistableBundle params);
|
||
|
|
||
|
/**
|
||
|
* Invoked when {@link UwbManager#provisionProfileAdfByScript(PersistableBundle, Executor,
|
||
|
* AdfProvisionStateCallback)} fails.
|
||
|
*
|
||
|
* @param reason Reason for failure
|
||
|
* @param params protocol specific parameters to indicate failure reason
|
||
|
*/
|
||
|
public abstract void onProfileAdfsProvisionFailed(
|
||
|
@Reason int reason, @NonNull PersistableBundle params);
|
||
|
|
||
|
/*package*/
|
||
|
@NonNull
|
||
|
AdfProvisionStateCallbackProxy getProxy() {
|
||
|
return mAdfProvisionStateCallbackProxy;
|
||
|
}
|
||
|
|
||
|
private static class AdfProvisionStateCallbackProxy extends
|
||
|
IUwbAdfProvisionStateCallbacks.Stub {
|
||
|
private final Object mLock = new Object();
|
||
|
@Nullable
|
||
|
@GuardedBy("mLock")
|
||
|
private Executor mExecutor;
|
||
|
@Nullable
|
||
|
@GuardedBy("mLock")
|
||
|
private AdfProvisionStateCallback mCallback;
|
||
|
|
||
|
AdfProvisionStateCallbackProxy() {
|
||
|
mCallback = null;
|
||
|
mExecutor = null;
|
||
|
}
|
||
|
|
||
|
/*package*/ void initProxy(@NonNull Executor executor,
|
||
|
@NonNull AdfProvisionStateCallback callback) {
|
||
|
synchronized (mLock) {
|
||
|
mExecutor = executor;
|
||
|
mCallback = callback;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*package*/ void cleanUpProxy() {
|
||
|
synchronized (mLock) {
|
||
|
mExecutor = null;
|
||
|
mCallback = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void onProfileAdfsProvisioned(@NonNull PersistableBundle params) {
|
||
|
Log.v(TAG, "AdfProvisionStateCallbackProxy: onProfileAdfsProvisioned : " + params);
|
||
|
AdfProvisionStateCallback callback;
|
||
|
Executor executor;
|
||
|
synchronized (mLock) {
|
||
|
executor = mExecutor;
|
||
|
callback = mCallback;
|
||
|
}
|
||
|
if (callback == null || executor == null) {
|
||
|
return;
|
||
|
}
|
||
|
Binder.clearCallingIdentity();
|
||
|
executor.execute(() -> callback.onProfileAdfsProvisioned(params));
|
||
|
cleanUpProxy();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void onProfileAdfsProvisionFailed(@AdfProvisionStateCallback.Reason int reason,
|
||
|
@NonNull PersistableBundle params) {
|
||
|
Log.v(TAG, "AdfProvisionStateCallbackProxy: onProfileAdfsProvisionFailed : "
|
||
|
+ reason + ", " + params);
|
||
|
AdfProvisionStateCallback callback;
|
||
|
Executor executor;
|
||
|
synchronized (mLock) {
|
||
|
executor = mExecutor;
|
||
|
callback = mCallback;
|
||
|
}
|
||
|
if (callback == null || executor == null) {
|
||
|
return;
|
||
|
}
|
||
|
Binder.clearCallingIdentity();
|
||
|
executor.execute(() -> callback.onProfileAdfsProvisionFailed(reason, params));
|
||
|
cleanUpProxy();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Interface for receiving vendor UCI responses and notifications.
|
||
|
*/
|
||
|
public interface UwbVendorUciCallback {
|
||
|
/**
|
||
|
* Invoked when a vendor specific UCI response is received.
|
||
|
*
|
||
|
* @param gid Group ID of the command. This needs to be one of the vendor reserved GIDs from
|
||
|
* the UCI specification.
|
||
|
* @param oid Opcode ID of the command. This is left to the OEM / vendor to decide.
|
||
|
* @param payload containing vendor Uci message payload.
|
||
|
*/
|
||
|
void onVendorUciResponse(
|
||
|
@IntRange(from = 0, to = 15) int gid, int oid, @NonNull byte[] payload);
|
||
|
|
||
|
/**
|
||
|
* Invoked when a vendor specific UCI notification is received.
|
||
|
*
|
||
|
* @param gid Group ID of the command. This needs to be one of the vendor reserved GIDs from
|
||
|
* the UCI specification.
|
||
|
* @param oid Opcode ID of the command. This is left to the OEM / vendor to decide.
|
||
|
* @param payload containing vendor Uci message payload.
|
||
|
*/
|
||
|
void onVendorUciNotification(
|
||
|
@IntRange(from = 9, to = 15) int gid, int oid, @NonNull byte[] payload);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
* Vendor configuration successful for the session
|
||
|
*/
|
||
|
public static final int VENDOR_SET_SESSION_CONFIGURATION_SUCCESS = 0;
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
* Failure to set vendor configuration for the session
|
||
|
*/
|
||
|
public static final int VENDOR_SET_SESSION_CONFIGURATION_FAILURE = 1;
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
*/
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
@IntDef(value = {
|
||
|
VENDOR_SET_SESSION_CONFIGURATION_SUCCESS,
|
||
|
VENDOR_SET_SESSION_CONFIGURATION_FAILURE,
|
||
|
})
|
||
|
@interface VendorConfigStatus {}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Interface for Oem extensions on ongoing session
|
||
|
*/
|
||
|
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||
|
public interface UwbOemExtensionCallback {
|
||
|
/**
|
||
|
* Invoked when session status changes.
|
||
|
*
|
||
|
* @param sessionStatusBundle session related info
|
||
|
*/
|
||
|
void onSessionStatusNotificationReceived(@NonNull PersistableBundle sessionStatusBundle);
|
||
|
|
||
|
/**
|
||
|
* Invoked when DeviceStatusNotification is received from UCI.
|
||
|
*
|
||
|
* @param deviceStatusBundle device state
|
||
|
*/
|
||
|
void onDeviceStatusNotificationReceived(@NonNull PersistableBundle deviceStatusBundle);
|
||
|
|
||
|
/**
|
||
|
* Invoked when session configuration is complete.
|
||
|
*
|
||
|
* @param openSessionBundle Session Params
|
||
|
* @return Error code
|
||
|
*/
|
||
|
@NonNull @VendorConfigStatus int onSessionConfigurationComplete(
|
||
|
@NonNull PersistableBundle openSessionBundle);
|
||
|
|
||
|
/**
|
||
|
* Invoked when ranging report is generated.
|
||
|
*
|
||
|
* @param rangingReport ranging report generated
|
||
|
* @return Oem modified ranging report
|
||
|
*/
|
||
|
@NonNull RangingReport onRangingReportReceived(
|
||
|
@NonNull RangingReport rangingReport);
|
||
|
|
||
|
/**
|
||
|
* Invoked to check pointed target decision by Oem.
|
||
|
*
|
||
|
* @param pointedTargetBundle pointed target params
|
||
|
* @return Oem pointed status
|
||
|
*/
|
||
|
boolean onCheckPointedTarget(@NonNull PersistableBundle pointedTargetBundle);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Use <code>Context.getSystemService(UwbManager.class)</code> to get an instance.
|
||
|
*
|
||
|
* @param ctx Context of the client.
|
||
|
* @param adapter an instance of an {@link android.uwb.IUwbAdapter}
|
||
|
* @hide
|
||
|
*/
|
||
|
public UwbManager(@NonNull Context ctx, @NonNull IUwbAdapter adapter) {
|
||
|
mContext = ctx;
|
||
|
mUwbAdapter = adapter;
|
||
|
mAdapterStateListener = new AdapterStateListener(adapter);
|
||
|
mRangingManager = new RangingManager(adapter);
|
||
|
mUwbVendorUciCallbackListener = new UwbVendorUciCallbackListener(adapter);
|
||
|
mUwbOemExtensionCallbackListener = new UwbOemExtensionCallbackListener(adapter);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register an {@link AdapterStateCallback} to listen for UWB adapter state changes
|
||
|
* <p>The provided callback will be invoked by the given {@link Executor}.
|
||
|
*
|
||
|
* <p>When first registering a callback, the callbacks's
|
||
|
* {@link AdapterStateCallback#onStateChanged(int, int)} is immediately invoked to indicate
|
||
|
* the current state of the underlying UWB adapter with the most recent
|
||
|
* {@link AdapterStateCallback.StateChangedReason} that caused the change.
|
||
|
*
|
||
|
* @param executor an {@link Executor} to execute given callback
|
||
|
* @param callback user implementation of the {@link AdapterStateCallback}
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public void registerAdapterStateCallback(@NonNull @CallbackExecutor Executor executor,
|
||
|
@NonNull AdapterStateCallback callback) {
|
||
|
mAdapterStateListener.register(executor, callback);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Unregister the specified {@link AdapterStateCallback}
|
||
|
* <p>The same {@link AdapterStateCallback} object used when calling
|
||
|
* {@link #registerAdapterStateCallback(Executor, AdapterStateCallback)} must be used.
|
||
|
*
|
||
|
* <p>Callbacks are automatically unregistered when application process goes away
|
||
|
*
|
||
|
* @param callback user implementation of the {@link AdapterStateCallback}
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public void unregisterAdapterStateCallback(@NonNull AdapterStateCallback callback) {
|
||
|
mAdapterStateListener.unregister(callback);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register an {@link UwbVendorUciCallback} to listen for UWB vendor responses and notifications
|
||
|
* <p>The provided callback will be invoked by the given {@link Executor}.
|
||
|
*
|
||
|
* <p>When first registering a callback, the callbacks's
|
||
|
* {@link UwbVendorUciCallback#onVendorUciCallBack(byte[])} is immediately invoked to
|
||
|
* notify the vendor notification.
|
||
|
*
|
||
|
* @param executor an {@link Executor} to execute given callback
|
||
|
* @param callback user implementation of the {@link UwbVendorUciCallback}
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public void registerUwbVendorUciCallback(@NonNull @CallbackExecutor Executor executor,
|
||
|
@NonNull UwbVendorUciCallback callback) {
|
||
|
mUwbVendorUciCallbackListener.register(executor, callback);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Unregister the specified {@link UwbVendorUciCallback}
|
||
|
*
|
||
|
* <p>The same {@link UwbVendorUciCallback} object used when calling
|
||
|
* {@link #registerUwbVendorUciCallback(Executor, UwbVendorUciCallback)} must be used.
|
||
|
*
|
||
|
* <p>Callbacks are automatically unregistered when application process goes away
|
||
|
*
|
||
|
* @param callback user implementation of the {@link UwbVendorUciCallback}
|
||
|
*/
|
||
|
public void unregisterUwbVendorUciCallback(@NonNull UwbVendorUciCallback callback) {
|
||
|
mUwbVendorUciCallbackListener.unregister(callback);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register an {@link UwbOemExtensionCallback} to listen for UWB oem extension callbacks
|
||
|
* <p>The provided callback will be invoked by the given {@link Executor}.
|
||
|
*
|
||
|
* @param executor an {@link Executor} to execute given callback
|
||
|
* @param callback oem implementation of {@link UwbOemExtensionCallback}
|
||
|
*/
|
||
|
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public void registerUwbOemExtensionCallback(@NonNull @CallbackExecutor Executor executor,
|
||
|
@NonNull UwbOemExtensionCallback callback) {
|
||
|
mUwbOemExtensionCallbackListener.register(executor, callback);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Unregister the specified {@link UwbOemExtensionCallback}
|
||
|
*
|
||
|
* <p>The same {@link UwbOemExtensionCallback} object used when calling
|
||
|
* {@link #registerUwbOemExtensionCallback(Executor, UwbOemExtensionCallback)} must be used.
|
||
|
*
|
||
|
* <p>Callbacks are automatically unregistered when an application process goes away
|
||
|
*
|
||
|
* @param callback oem implementation of {@link UwbOemExtensionCallback}
|
||
|
*/
|
||
|
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public void unregisterUwbOemExtensionCallback(@NonNull UwbOemExtensionCallback callback) {
|
||
|
mUwbOemExtensionCallbackListener.unregister(callback);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get a {@link PersistableBundle} with the supported UWB protocols and parameters.
|
||
|
* <p>The {@link PersistableBundle} should be parsed using a support library
|
||
|
*
|
||
|
* <p>Android reserves the '^android.*' namespace</p>
|
||
|
*
|
||
|
* @return {@link PersistableBundle} of the device's supported UWB protocols and parameters
|
||
|
*/
|
||
|
@NonNull
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public PersistableBundle getSpecificationInfo() {
|
||
|
return getSpecificationInfoInternal(/* chipId= */ null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get a {@link PersistableBundle} with the supported UWB protocols and parameters.
|
||
|
*
|
||
|
* @see #getSpecificationInfo() if you don't need multi-HAL support
|
||
|
*
|
||
|
* @param chipId identifier of UWB chip for multi-HAL devices
|
||
|
*
|
||
|
* @return {@link PersistableBundle} of the device's supported UWB protocols and parameters
|
||
|
*/
|
||
|
// TODO(b/205614701): Add documentation about how to find the relevant chipId
|
||
|
@NonNull
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public PersistableBundle getSpecificationInfo(@NonNull String chipId) {
|
||
|
checkNotNull(chipId);
|
||
|
return getSpecificationInfoInternal(chipId);
|
||
|
}
|
||
|
|
||
|
private PersistableBundle getSpecificationInfoInternal(String chipId) {
|
||
|
try {
|
||
|
return mUwbAdapter.getSpecificationInfo(chipId);
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get uwbs timestamp in micros.
|
||
|
*
|
||
|
* @return uwb device timestamp in micros.
|
||
|
*/
|
||
|
@NonNull
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
@FlaggedApi("com.android.uwb.flags.query_timestamp_micros")
|
||
|
public long queryUwbsTimestampMicros() {
|
||
|
try {
|
||
|
return mUwbAdapter.queryUwbsTimestampMicros();
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the timestamp resolution for events in nanoseconds
|
||
|
* <p>This value defines the maximum error of all timestamps for events reported to
|
||
|
* {@link RangingSession.Callback}.
|
||
|
*
|
||
|
* @return the timestamp resolution in nanoseconds
|
||
|
*/
|
||
|
@SuppressLint("MethodNameUnits")
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public long elapsedRealtimeResolutionNanos() {
|
||
|
return elapsedRealtimeResolutionNanosInternal(/* chipId= */ null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the timestamp resolution for events in nanoseconds
|
||
|
*
|
||
|
* @see #elapsedRealtimeResolutionNanos() if you don't need multi-HAL support
|
||
|
*
|
||
|
* @param chipId identifier of UWB chip for multi-HAL devices
|
||
|
*
|
||
|
* @return the timestamp resolution in nanoseconds
|
||
|
*/
|
||
|
@SuppressLint("MethodNameUnits")
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public long elapsedRealtimeResolutionNanos(@NonNull String chipId) {
|
||
|
checkNotNull(chipId);
|
||
|
return elapsedRealtimeResolutionNanosInternal(chipId);
|
||
|
}
|
||
|
|
||
|
private long elapsedRealtimeResolutionNanosInternal(String chipId) {
|
||
|
try {
|
||
|
return mUwbAdapter.getTimestampResolutionNanos(chipId);
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Open a {@link RangingSession} with the given parameters
|
||
|
* <p>The {@link RangingSession.Callback#onOpened(RangingSession)} function is called with a
|
||
|
* {@link RangingSession} object used to control ranging when the session is successfully
|
||
|
* opened.
|
||
|
*
|
||
|
* if this session uses FIRA defined profile (not custom profile), this triggers:
|
||
|
* - OOB discovery using service UUID
|
||
|
* - OOB connection establishment after discovery for session params
|
||
|
* negotiation.
|
||
|
* - Secure element interactions needed for dynamic STS based session establishment.
|
||
|
* - Setup the UWB session based on the parameters negotiated via OOB.
|
||
|
* - Note: The OOB flow requires additional BLE Permissions
|
||
|
* {permission.BLUETOOTH_ADVERTISE/permission.BLUETOOTH_SCAN
|
||
|
* and permission.BLUETOOTH_CONNECT}.
|
||
|
*
|
||
|
* <p>If a session cannot be opened, then
|
||
|
* {@link RangingSession.Callback#onClosed(int, PersistableBundle)} will be invoked with the
|
||
|
* appropriate {@link RangingSession.Callback.Reason}.
|
||
|
*
|
||
|
* <p>An open {@link RangingSession} will be automatically closed if client application process
|
||
|
* dies.
|
||
|
*
|
||
|
* <p>A UWB support library must be used in order to construct the {@code parameter}
|
||
|
* {@link PersistableBundle}.
|
||
|
*
|
||
|
* @param parameters the parameters that define the ranging session
|
||
|
* @param executor {@link Executor} to run callbacks
|
||
|
* @param callbacks {@link RangingSession.Callback} to associate with the
|
||
|
* {@link RangingSession} that is being opened.
|
||
|
*
|
||
|
* @return an {@link CancellationSignal} that is able to be used to cancel the opening of a
|
||
|
* {@link RangingSession} that has been requested through {@link #openRangingSession}
|
||
|
* but has not yet been made available by
|
||
|
* {@link RangingSession.Callback#onOpened(RangingSession)}.
|
||
|
*/
|
||
|
@NonNull
|
||
|
@RequiresPermission(allOf = {
|
||
|
permission.UWB_PRIVILEGED,
|
||
|
permission.UWB_RANGING
|
||
|
})
|
||
|
public CancellationSignal openRangingSession(@NonNull PersistableBundle parameters,
|
||
|
@NonNull @CallbackExecutor Executor executor,
|
||
|
@NonNull RangingSession.Callback callbacks) {
|
||
|
return openRangingSessionInternal(parameters, executor, callbacks, /* chipId= */ null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Open a {@link RangingSession} with the given parameters on a specific UWB subsystem
|
||
|
*
|
||
|
* @see #openRangingSession(PersistableBundle, Executor, RangingSession.Callback) if you don't
|
||
|
* need multi-HAL support
|
||
|
*
|
||
|
* @param parameters the parameters that define the ranging session
|
||
|
* @param executor {@link Executor} to run callbacks
|
||
|
* @param callbacks {@link RangingSession.Callback} to associate with the
|
||
|
* {@link RangingSession} that is being opened.
|
||
|
* @param chipId identifier of UWB chip for multi-HAL devices
|
||
|
*
|
||
|
* @return an {@link CancellationSignal} that is able to be used to cancel the opening of a
|
||
|
* {@link RangingSession} that has been requested through {@link #openRangingSession}
|
||
|
* but has not yet been made available by
|
||
|
* {@link RangingSession.Callback#onOpened(RangingSession)}.
|
||
|
*/
|
||
|
@NonNull
|
||
|
@RequiresPermission(allOf = {
|
||
|
permission.UWB_PRIVILEGED,
|
||
|
permission.UWB_RANGING
|
||
|
})
|
||
|
public CancellationSignal openRangingSession(@NonNull PersistableBundle parameters,
|
||
|
@NonNull @CallbackExecutor Executor executor,
|
||
|
@NonNull RangingSession.Callback callbacks,
|
||
|
@SuppressLint("ListenerLast") @NonNull String chipId) {
|
||
|
checkNotNull(chipId);
|
||
|
return openRangingSessionInternal(parameters, executor, callbacks, chipId);
|
||
|
}
|
||
|
|
||
|
private CancellationSignal openRangingSessionInternal(PersistableBundle parameters,
|
||
|
Executor executor, RangingSession.Callback callbacks, String chipId) {
|
||
|
return mRangingManager.openSession(
|
||
|
mContext.getAttributionSource(), parameters, executor, callbacks, chipId);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the current enabled/disabled state for UWB.
|
||
|
*
|
||
|
* Possible values are:
|
||
|
* AdapterStateCallback#STATE_DISABLED
|
||
|
* AdapterStateCallback#STATE_ENABLED_INACTIVE
|
||
|
* AdapterStateCallback#STATE_ENABLED_ACTIVE
|
||
|
*
|
||
|
* @return value representing current enabled/disabled state for UWB.
|
||
|
*/
|
||
|
public @AdapterStateCallback.State int getAdapterState() {
|
||
|
return mAdapterStateListener.getAdapterState();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Whether UWB is enabled or disabled.
|
||
|
*
|
||
|
* <p>
|
||
|
* If disabled, this could indicate that either
|
||
|
* <li> User has toggled UWB off from settings, OR </li>
|
||
|
* <li> UWB subsystem has shut down due to a fatal error. </li>
|
||
|
* </p>
|
||
|
*
|
||
|
* @return true if enabled, false otherwise.
|
||
|
*
|
||
|
* @see #getAdapterState()
|
||
|
* @see #setUwbEnabled(boolean)
|
||
|
*/
|
||
|
public boolean isUwbEnabled() {
|
||
|
int adapterState = getAdapterState();
|
||
|
return adapterState != AdapterStateCallback.STATE_DISABLED;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Disables or enables UWB by the user.
|
||
|
*
|
||
|
* If enabled any subsequent calls to
|
||
|
* {@link #openRangingSession(PersistableBundle, Executor, RangingSession.Callback)} will be
|
||
|
* allowed. If disabled, all active ranging sessions will be closed and subsequent calls to
|
||
|
* {@link #openRangingSession(PersistableBundle, Executor, RangingSession.Callback)} will be
|
||
|
* disallowed.
|
||
|
*
|
||
|
* @param enabled value representing intent to disable or enable UWB.
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public void setUwbEnabled(boolean enabled) {
|
||
|
mAdapterStateListener.setEnabled(enabled);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Whether UWB hardware will automatically turn off when there are no clients requesting it.
|
||
|
* This feature is only turned on non-phone form factor devices which needs to keep the UWB
|
||
|
* hardware turned to avoid battery drain.
|
||
|
*
|
||
|
* <p>
|
||
|
* If the device supports automatically turning off UWB hardware, the state of UWB hardware
|
||
|
* is controlled by:
|
||
|
* <li> UWB user toggle state or Airplane mode state, AND </li>
|
||
|
* <li> Whether any clients are actively enabling UWB </li>
|
||
|
* </p>
|
||
|
*
|
||
|
* @return true if enabled, false otherwise.
|
||
|
*
|
||
|
* @see #isUwbHwEnableRequested()
|
||
|
* @see #requestUwbHwEnable(boolean)
|
||
|
*/
|
||
|
@FlaggedApi("com.android.uwb.flags.hw_state")
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public boolean isUwbHwIdleTurnOffEnabled() {
|
||
|
try {
|
||
|
return mUwbAdapter.isHwIdleTurnOffEnabled();
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Whether this client has requested for UWB hardware to be enabled or disabled.
|
||
|
* Only supported on devices which supports hw idle turn off (indicated by
|
||
|
* {@link #isUwbHwIdleTurnOffEnabled()})
|
||
|
*
|
||
|
* <p>
|
||
|
* This does not indicate the global state of UWB, this only indicates whether this app
|
||
|
* (identified by {@link Context#getAttributionSource()}) has requested for UWB hardware to be
|
||
|
* enabled or disabled.
|
||
|
* </p>
|
||
|
*
|
||
|
* @return true if enabled, false otherwise.
|
||
|
* @throws IllegalStateException if the device does not support this feature
|
||
|
*
|
||
|
* @see #isUwbHwIdleTurnOffEnabled()
|
||
|
* @see #requestUwbHwEnable(boolean)
|
||
|
*/
|
||
|
@FlaggedApi("com.android.uwb.flags.hw_state")
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public boolean isUwbHwEnableRequested() {
|
||
|
try {
|
||
|
return mUwbAdapter.isHwEnableRequested(mContext.getAttributionSource());
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This client has requested for UWB hardware to be enabled or disabled.
|
||
|
* Only supported on devices which supports hw idle turn off (indicated by
|
||
|
* {@link #isUwbHwIdleTurnOffEnabled()})
|
||
|
*
|
||
|
* <p>
|
||
|
* This does not indicate the global state of UWB, this only indicates whether this app
|
||
|
* (identified by {@link Context#getAttributionSource()}) has requested for UWB hardware to be
|
||
|
* enabled or disabled.
|
||
|
* If UWB is enabled by the user and has at least 1 privileged client requesting UWB toggle on,
|
||
|
* then UWB hardware is enabled, else the UWB hardware is disabled.
|
||
|
* </p>
|
||
|
*
|
||
|
* @param enabled value representing intent to disable or enable UWB.
|
||
|
* @throws IllegalStateException if the device does not support this feature
|
||
|
*
|
||
|
* @see #isUwbHwIdleTurnOffEnabled()
|
||
|
* @see #isUwbHwEnableRequested() ()
|
||
|
*/
|
||
|
@FlaggedApi("com.android.uwb.flags.hw_state")
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public void requestUwbHwEnabled(boolean enabled) {
|
||
|
try {
|
||
|
mUwbAdapter.requestHwEnabled(
|
||
|
enabled, mContext.getAttributionSource(),
|
||
|
new Binder(mContext.getPackageName()));
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a list of UWB chip infos in a {@link PersistableBundle}.
|
||
|
*
|
||
|
* Callers can invoke methods on a specific UWB chip by passing its {@code chipId} to the
|
||
|
* method, which can be determined by calling:
|
||
|
* <pre>
|
||
|
* List<PersistableBundle> chipInfos = getChipInfos();
|
||
|
* for (PersistableBundle chipInfo : chipInfos) {
|
||
|
* String chipId = ChipInfoParams.fromBundle(chipInfo).getChipId();
|
||
|
* }
|
||
|
* </pre>
|
||
|
*
|
||
|
* @return list of {@link PersistableBundle} containing info about UWB chips for a multi-HAL
|
||
|
* system, or a list of info for a single chip for a single HAL system.
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
@NonNull
|
||
|
public List<PersistableBundle> getChipInfos() {
|
||
|
try {
|
||
|
return mUwbAdapter.getChipInfos();
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the default UWB chip identifier.
|
||
|
*
|
||
|
* If callers do not pass a specific {@code chipId} to UWB methods, then the method will be
|
||
|
* invoked on the default chip, which is determined at system initialization from a
|
||
|
* configuration file.
|
||
|
*
|
||
|
* @return default UWB chip identifier for a multi-HAL system, or the identifier of the only UWB
|
||
|
* chip in a single HAL system.
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
@NonNull
|
||
|
public String getDefaultChipId() {
|
||
|
try {
|
||
|
return mUwbAdapter.getDefaultChipId();
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register the UWB service profile.
|
||
|
* This profile instance is persisted by the platform until explicitly removed
|
||
|
* using {@link #removeServiceProfile(PersistableBundle)}
|
||
|
*
|
||
|
* @param parameters the parameters that define the service profile.
|
||
|
* @return Protocol specific params to be used as handle for triggering the profile.
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
@NonNull
|
||
|
public PersistableBundle addServiceProfile(@NonNull PersistableBundle parameters) {
|
||
|
try {
|
||
|
return mUwbAdapter.addServiceProfile(parameters);
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Successfully removed the service profile.
|
||
|
*/
|
||
|
public static final int REMOVE_SERVICE_PROFILE_SUCCESS = 0;
|
||
|
|
||
|
/**
|
||
|
* Failed to remove service since the service profile is unknown.
|
||
|
*/
|
||
|
public static final int REMOVE_SERVICE_PROFILE_ERROR_UNKNOWN_SERVICE = 1;
|
||
|
|
||
|
/**
|
||
|
* Failed to remove service due to some internal error while processing the request.
|
||
|
*/
|
||
|
public static final int REMOVE_SERVICE_PROFILE_ERROR_INTERNAL = 2;
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
*/
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
@IntDef(value = {
|
||
|
REMOVE_SERVICE_PROFILE_SUCCESS,
|
||
|
REMOVE_SERVICE_PROFILE_ERROR_UNKNOWN_SERVICE,
|
||
|
REMOVE_SERVICE_PROFILE_ERROR_INTERNAL
|
||
|
})
|
||
|
@interface RemoveServiceProfile {}
|
||
|
|
||
|
/**
|
||
|
* Remove the service profile registered with {@link #addServiceProfile} and
|
||
|
* all related resources.
|
||
|
*
|
||
|
* @param parameters the parameters that define the service profile.
|
||
|
*
|
||
|
* @return true if the service profile is removed, false otherwise.
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public @RemoveServiceProfile int removeServiceProfile(@NonNull PersistableBundle parameters) {
|
||
|
try {
|
||
|
return mUwbAdapter.removeServiceProfile(parameters);
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get all service profiles initialized with {@link #addServiceProfile}
|
||
|
*
|
||
|
* @return the parameters that define the service profiles.
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
@NonNull
|
||
|
public PersistableBundle getAllServiceProfiles() {
|
||
|
try {
|
||
|
return mUwbAdapter.getAllServiceProfiles();
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the list of ADF (application defined file) provisioning authorities available for the UWB
|
||
|
* applet in SE (secure element).
|
||
|
*
|
||
|
* @param serviceProfileBundle Parameters representing the profile to use.
|
||
|
* @return The list of key information of ADF provisioning authority defined in FiRa
|
||
|
* CSML 8.2.2.7.2.4 and 8.2.2.14.4.1.2.
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
@NonNull
|
||
|
public PersistableBundle getAdfProvisioningAuthorities(
|
||
|
@NonNull PersistableBundle serviceProfileBundle) {
|
||
|
try {
|
||
|
return mUwbAdapter.getAdfProvisioningAuthorities(serviceProfileBundle);
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get certificate information for the UWB applet in SE (secure element) that can be used to
|
||
|
* provision ADF (application defined file).
|
||
|
*
|
||
|
* @param serviceProfileBundle Parameters representing the profile to use.
|
||
|
* @return The Fira applet certificate information defined in FiRa CSML 7.3.4.3 and
|
||
|
* 8.2.2.14.4.1.1
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
@NonNull
|
||
|
public PersistableBundle getAdfCertificateInfo(
|
||
|
@NonNull PersistableBundle serviceProfileBundle) {
|
||
|
try {
|
||
|
return mUwbAdapter.getAdfCertificateAndInfo(serviceProfileBundle);
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Mechanism to provision ADFs (application defined file) in the UWB applet present in SE
|
||
|
* (secure element) for a profile instance.
|
||
|
*
|
||
|
* @param serviceProfileBundle Parameters representing the profile to use.
|
||
|
* @param executor an {@link Executor} to execute given callback
|
||
|
* @param callback user implementation of the {@link AdapterStateCallback}
|
||
|
*/
|
||
|
public void provisionProfileAdfByScript(@NonNull PersistableBundle serviceProfileBundle,
|
||
|
@NonNull @CallbackExecutor Executor executor,
|
||
|
@NonNull AdfProvisionStateCallback callback) {
|
||
|
if (executor == null) throw new IllegalArgumentException("executor must not be null");
|
||
|
if (callback == null) throw new IllegalArgumentException("callback must not be null");
|
||
|
AdfProvisionStateCallback.AdfProvisionStateCallbackProxy proxy = callback.getProxy();
|
||
|
proxy.initProxy(executor, callback);
|
||
|
try {
|
||
|
mUwbAdapter.provisionProfileAdfByScript(serviceProfileBundle, proxy);
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Successfully removed the profile ADF.
|
||
|
*/
|
||
|
public static final int REMOVE_PROFILE_ADF_SUCCESS = 0;
|
||
|
|
||
|
/**
|
||
|
* Failed to remove ADF since the service profile is unknown.
|
||
|
*/
|
||
|
public static final int REMOVE_PROFILE_ADF_ERROR_UNKNOWN_SERVICE = 1;
|
||
|
|
||
|
/**
|
||
|
* Failed to remove ADF due to some internal error while processing the request.
|
||
|
*/
|
||
|
public static final int REMOVE_PROFILE_ADF_ERROR_INTERNAL = 2;
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
*/
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
@IntDef(value = {
|
||
|
REMOVE_PROFILE_ADF_SUCCESS,
|
||
|
REMOVE_PROFILE_ADF_ERROR_UNKNOWN_SERVICE,
|
||
|
REMOVE_PROFILE_ADF_ERROR_INTERNAL
|
||
|
})
|
||
|
@interface RemoveProfileAdf {}
|
||
|
|
||
|
/**
|
||
|
* Remove the ADF (application defined file) provisioned by {@link #provisionProfileAdfByScript}
|
||
|
*
|
||
|
* @param serviceProfileBundle Parameters representing the profile to use.
|
||
|
* @return true if the ADF is removed, false otherwise.
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public @RemoveProfileAdf int removeProfileAdf(@NonNull PersistableBundle serviceProfileBundle) {
|
||
|
try {
|
||
|
return mUwbAdapter.removeProfileAdf(serviceProfileBundle);
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Successfully sent the UCI message.
|
||
|
*/
|
||
|
public static final int SEND_VENDOR_UCI_SUCCESS = 0;
|
||
|
|
||
|
/**
|
||
|
* Failed to send the UCI message because of an error returned from the HAL interface.
|
||
|
*/
|
||
|
public static final int SEND_VENDOR_UCI_ERROR_HW = 1;
|
||
|
|
||
|
/**
|
||
|
* Failed to send the UCI message since UWB is toggled off.
|
||
|
*/
|
||
|
public static final int SEND_VENDOR_UCI_ERROR_OFF = 2;
|
||
|
|
||
|
/**
|
||
|
* Failed to send the UCI message since UWB UCI command is malformed.
|
||
|
* GID.
|
||
|
*/
|
||
|
public static final int SEND_VENDOR_UCI_ERROR_INVALID_ARGS = 3;
|
||
|
|
||
|
/**
|
||
|
* Failed to send the UCI message since UWB GID used is invalid.
|
||
|
*/
|
||
|
public static final int SEND_VENDOR_UCI_ERROR_INVALID_GID = 4;
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
*/
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
@IntDef(value = {
|
||
|
SEND_VENDOR_UCI_SUCCESS,
|
||
|
SEND_VENDOR_UCI_ERROR_HW,
|
||
|
SEND_VENDOR_UCI_ERROR_OFF,
|
||
|
SEND_VENDOR_UCI_ERROR_INVALID_ARGS,
|
||
|
SEND_VENDOR_UCI_ERROR_INVALID_GID,
|
||
|
})
|
||
|
@interface SendVendorUciStatus {}
|
||
|
|
||
|
/**
|
||
|
* Message Type for UCI Command.
|
||
|
*/
|
||
|
public static final int MESSAGE_TYPE_COMMAND = 1;
|
||
|
/**
|
||
|
* Message Type for C-APDU (Command - Application Protocol Data Unit),
|
||
|
* used for communication with secure component.
|
||
|
*/
|
||
|
public static final int MESSAGE_TYPE_TEST_1 = 4;
|
||
|
|
||
|
/**
|
||
|
* Message Type for R-APDU (Response - Application Protocol Data Unit),
|
||
|
* used for communication with secure component.
|
||
|
*/
|
||
|
public static final int MESSAGE_TYPE_TEST_2 = 5;
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
*/
|
||
|
@Retention(RetentionPolicy.SOURCE)
|
||
|
@IntDef(value = {
|
||
|
MESSAGE_TYPE_COMMAND,
|
||
|
MESSAGE_TYPE_TEST_1,
|
||
|
MESSAGE_TYPE_TEST_2,
|
||
|
})
|
||
|
@interface MessageType {}
|
||
|
|
||
|
/**
|
||
|
* Send Vendor specific Uci Messages.
|
||
|
*
|
||
|
* The format of the UCI messages are defined in the UCI specification. The platform is
|
||
|
* responsible for fragmenting the payload if necessary.
|
||
|
*
|
||
|
* @param gid Group ID of the command. This needs to be one of the vendor reserved GIDs from
|
||
|
* the UCI specification.
|
||
|
* @param oid Opcode ID of the command. This is left to the OEM / vendor to decide.
|
||
|
* @param payload containing vendor Uci message payload.
|
||
|
*/
|
||
|
@NonNull
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public @SendVendorUciStatus int sendVendorUciMessage(
|
||
|
@IntRange(from = 0, to = 15) int gid, int oid, @NonNull byte[] payload) {
|
||
|
Objects.requireNonNull(payload, "Payload must not be null");
|
||
|
try {
|
||
|
return mUwbAdapter.sendVendorUciMessage(MESSAGE_TYPE_COMMAND, gid, oid, payload);
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Send Vendor specific Uci Messages with custom message type.
|
||
|
*
|
||
|
* The format of the UCI messages are defined in the UCI specification. The platform is
|
||
|
* responsible for fragmenting the payload if necessary.
|
||
|
*
|
||
|
* Note that mt (message type) is added at the beginning of method parameters as it is more
|
||
|
* distinctive than other parameters and was requested from vendor.
|
||
|
*
|
||
|
* @param mt Message Type of the command
|
||
|
* @param gid Group ID of the command. This needs to be one of the vendor reserved GIDs from
|
||
|
* the UCI specification
|
||
|
* @param oid Opcode ID of the command. This is left to the OEM / vendor to decide
|
||
|
* @param payload containing vendor Uci message payload
|
||
|
*/
|
||
|
@NonNull
|
||
|
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public @SendVendorUciStatus int sendVendorUciMessage(@MessageType int mt,
|
||
|
@IntRange(from = 0, to = 15) int gid, int oid, @NonNull byte[] payload) {
|
||
|
Objects.requireNonNull(payload, "Payload must not be null");
|
||
|
try {
|
||
|
return mUwbAdapter.sendVendorUciMessage(mt, gid, oid, payload);
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static class OnUwbActivityEnergyInfoProxy
|
||
|
extends IOnUwbActivityEnergyInfoListener.Stub {
|
||
|
private final Object mLock = new Object();
|
||
|
@Nullable @GuardedBy("mLock") private Executor mExecutor;
|
||
|
@Nullable @GuardedBy("mLock") private Consumer<UwbActivityEnergyInfo> mListener;
|
||
|
|
||
|
OnUwbActivityEnergyInfoProxy(Executor executor,
|
||
|
Consumer<UwbActivityEnergyInfo> listener) {
|
||
|
mExecutor = executor;
|
||
|
mListener = listener;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void onUwbActivityEnergyInfo(UwbActivityEnergyInfo info) {
|
||
|
Executor executor;
|
||
|
Consumer<UwbActivityEnergyInfo> listener;
|
||
|
synchronized (mLock) {
|
||
|
if (mExecutor == null || mListener == null) {
|
||
|
return;
|
||
|
}
|
||
|
executor = mExecutor;
|
||
|
listener = mListener;
|
||
|
// null out to allow garbage collection, prevent triggering listener more than once
|
||
|
mExecutor = null;
|
||
|
mListener = null;
|
||
|
}
|
||
|
Binder.clearCallingIdentity();
|
||
|
executor.execute(() -> listener.accept(info));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Request to get the current {@link UwbActivityEnergyInfo} asynchronously.
|
||
|
*
|
||
|
* @param executor the executor that the listener will be invoked on
|
||
|
* @param listener the listener that will receive the {@link UwbActivityEnergyInfo} object
|
||
|
* when it becomes available. The listener will be triggered at most once for
|
||
|
* each call to this method.
|
||
|
*/
|
||
|
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||
|
public void getUwbActivityEnergyInfoAsync(
|
||
|
@NonNull @CallbackExecutor Executor executor,
|
||
|
@NonNull Consumer<UwbActivityEnergyInfo> listener) {
|
||
|
Objects.requireNonNull(executor, "executor cannot be null");
|
||
|
Objects.requireNonNull(listener, "listener cannot be null");
|
||
|
try {
|
||
|
mUwbAdapter.getUwbActivityEnergyInfoAsync(
|
||
|
new OnUwbActivityEnergyInfoProxy(executor, listener));
|
||
|
} catch (RemoteException e) {
|
||
|
throw e.rethrowFromSystemServer();
|
||
|
}
|
||
|
}
|
||
|
}
|