/* * 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 android.Manifest; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.os.Binder; import android.os.Build; import android.os.PersistableBundle; import android.os.RemoteException; import android.util.Log; import androidx.annotation.RequiresApi; import com.android.modules.utils.build.SdkLevel; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; /** * This class provides a way to control an active UWB ranging session. *
It also defines the required {@link RangingSession.Callback} that must be implemented * in order to be notified of UWB ranging results and status events related to the * {@link RangingSession}. * *
To get an instance of {@link RangingSession}, first use * {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)} to request to open a * session. Once the session is opened, a {@link RangingSession} object is provided through * {@link RangingSession.Callback#onOpened(RangingSession)}. If opening a session fails, the failure * is reported through {@link RangingSession.Callback#onOpenFailed(int, PersistableBundle)} with the * failure reason. * * @hide */ @SystemApi public final class RangingSession implements AutoCloseable { private final String mTag = "Uwb.RangingSession[" + this + "]"; private final SessionHandle mSessionHandle; private final IUwbAdapter mAdapter; private final Executor mExecutor; private final Callback mCallback; private final String mChipId; private enum State { /** * The state of the {@link RangingSession} until * {@link RangingSession.Callback#onOpened(RangingSession)} is invoked */ INIT, /** * The {@link RangingSession} is initialized and ready to begin ranging */ IDLE, /** * The {@link RangingSession} is actively ranging */ ACTIVE, /** * The {@link RangingSession} is closed and may not be used for ranging. */ CLOSED } private State mState = State.INIT; /** * Interface for receiving {@link RangingSession} events */ public interface Callback { /** * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { REASON_UNKNOWN, REASON_LOCAL_REQUEST, REASON_REMOTE_REQUEST, REASON_BAD_PARAMETERS, REASON_GENERIC_ERROR, REASON_MAX_SESSIONS_REACHED, REASON_SYSTEM_POLICY, REASON_PROTOCOL_SPECIFIC_ERROR, REASON_MAX_RR_RETRY_REACHED, REASON_SERVICE_DISCOVERY_FAILURE, REASON_SERVICE_CONNECTION_FAILURE, REASON_SE_NOT_SUPPORTED, REASON_SE_INTERACTION_FAILURE, REASON_INSUFFICIENT_SLOTS_PER_RR, REASON_SYSTEM_REGULATION, REASON_INBAND_SESSION_STOP, }) @interface Reason {} /** * Indicates that the session was closed or failed to open due to an unknown reason */ int REASON_UNKNOWN = 0; /** * Indicates that the session was closed or failed to open because * {@link AutoCloseable#close()} or {@link RangingSession#close()} was called */ int REASON_LOCAL_REQUEST = 1; /** * Indicates that the session was closed or failed to open due to an explicit request from * the remote device. */ int REASON_REMOTE_REQUEST = 2; /** * Indicates that the session was closed or failed to open due to erroneous parameters */ int REASON_BAD_PARAMETERS = 3; /** * Indicates an error on this device besides the error code already listed */ int REASON_GENERIC_ERROR = 4; /** * Indicates that the number of currently open sessions supported by the device and * additional sessions may not be opened. */ int REASON_MAX_SESSIONS_REACHED = 5; /** * Indicates that the local system policy caused the change, such * as privacy policy, power management policy, permissions, and more. */ int REASON_SYSTEM_POLICY = 6; /** * Indicates a protocol specific error. The associated {@link PersistableBundle} should be * consulted for additional information. */ int REASON_PROTOCOL_SPECIFIC_ERROR = 7; /** * Indicates that the max number of retry attempts for a ranging attempt has been reached. */ int REASON_MAX_RR_RETRY_REACHED = 9; /** * Indicates a failure to discover the service after activation. */ int REASON_SERVICE_DISCOVERY_FAILURE = 10; /** * Indicates a failure to connect to the service after discovery. */ int REASON_SERVICE_CONNECTION_FAILURE = 11; /** * The device doesn’t support FiRA Applet. */ int REASON_SE_NOT_SUPPORTED = 12; /** * SE interactions failed. */ int REASON_SE_INTERACTION_FAILURE = 13; /** * Indicate insufficient slots per ranging round. */ int REASON_INSUFFICIENT_SLOTS_PER_RR = 14; /** * Indicate that a system regulation caused the change, such as no allowed UWB channels in * the country. */ int REASON_SYSTEM_REGULATION = 15; /** * Indicates session was stopped due to inband signal. */ @FlaggedApi("com.android.uwb.flags.reason_inband_session_stop") int REASON_INBAND_SESSION_STOP = 16; /** * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { CONTROLEE_FAILURE_REASON_MAX_CONTROLEE_REACHED, }) @interface ControleeFailureReason {} /** * Indicates that the session has reached the max number of controlees supported by the * device. This is applicable to only one to many sessions and sent in response to a * request to add a new controlee to an ongoing session. */ int CONTROLEE_FAILURE_REASON_MAX_CONTROLEE_REACHED = 0; /** * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { DATA_FAILURE_REASON_DATA_SIZE_TOO_LARGE, }) @interface DataFailureReason {} /** * Indicates that the size of the data being sent or received is too large. */ int DATA_FAILURE_REASON_DATA_SIZE_TOO_LARGE = 10; /** * Invoked when {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)} * is successful * * @param session the newly opened {@link RangingSession} */ void onOpened(@NonNull RangingSession session); /** * Invoked if {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}} * fails * * @param reason the failure reason * @param params protocol specific parameters */ void onOpenFailed(@Reason int reason, @NonNull PersistableBundle params); /** * Invoked either, * - when {@link RangingSession#start(PersistableBundle)} is successful if the session is * using a custom profile, OR * - when platform starts ranging after OOB discovery + negotiation if the session is * using a platform defined profile. * @param sessionInfo session specific parameters from the lower layers */ void onStarted(@NonNull PersistableBundle sessionInfo); /** * Invoked either, * - when {@link RangingSession#start(PersistableBundle)} fails if * the session is using a custom profile, OR * - when platform fails ranging after OOB discovery + negotiation if the * session is using a platform defined profile. * * @param reason the failure reason * @param params protocol specific parameters */ void onStartFailed(@Reason int reason, @NonNull PersistableBundle params); /** * Invoked when a request to reconfigure the session succeeds * * @param params the updated ranging configuration */ void onReconfigured(@NonNull PersistableBundle params); /** * Invoked when a request to reconfigure the session fails * * @param reason reason the session failed to be reconfigured * @param params protocol specific failure reasons */ void onReconfigureFailed(@Reason int reason, @NonNull PersistableBundle params); /** * Invoked when a request to stop the session succeeds * * @param reason reason for the session stop * @param parameters protocol specific parameters related to the stop reason */ void onStopped(@Reason int reason, @NonNull PersistableBundle parameters); /** * Invoked when a request to stop the session fails * * @param reason reason the session failed to be stopped * @param params protocol specific failure reasons */ void onStopFailed(@Reason int reason, @NonNull PersistableBundle params); /** * Invoked when session is either closed spontaneously, or per user request via * {@link RangingSession#close()} or {@link AutoCloseable#close()}. * * @param reason reason for the session closure * @param parameters protocol specific parameters related to the close reason */ void onClosed(@Reason int reason, @NonNull PersistableBundle parameters); /** * Called once per ranging interval even when a ranging measurement fails * * @param rangingReport ranging report for this interval's measurements */ void onReportReceived(@NonNull RangingReport rangingReport); /** * Invoked when a new controlee is added to an ongoing one-to many session. * * @param parameters protocol specific parameters for the new controlee */ default void onControleeAdded(@NonNull PersistableBundle parameters) {} /** * Invoked when a new controlee is added to an ongoing one-to many session. * * @param reason reason for the controlee add failure * @param parameters protocol specific parameters related to the failure */ default void onControleeAddFailed( @ControleeFailureReason int reason, @NonNull PersistableBundle parameters) {} /** * Invoked when an existing controlee is removed from an ongoing one-to many session. * * @param parameters protocol specific parameters for the existing controlee */ default void onControleeRemoved(@NonNull PersistableBundle parameters) {} /** * Invoked when a new controlee is added to an ongoing one-to many session. * * @param reason reason for the controlee remove failure * @param parameters protocol specific parameters related to the failure */ default void onControleeRemoveFailed( @ControleeFailureReason int reason, @NonNull PersistableBundle parameters) {} /** * Invoked when an ongoing session is successfully pauseed. * * @param parameters protocol specific parameters sent for suspension */ default void onPaused(@NonNull PersistableBundle parameters) {} /** * Invoked when an ongoing session suspension fails. * * @param reason reason for the suspension failure * @param parameters protocol specific parameters for suspension failure */ default void onPauseFailed(@Reason int reason, @NonNull PersistableBundle parameters) {} /** * Invoked when a pauseed session is successfully resumed. * * @param parameters protocol specific parameters sent for suspension */ default void onResumed(@NonNull PersistableBundle parameters) {} /** * Invoked when a pauseed session resumption fails. * * @param reason reason for the resumption failure * @param parameters protocol specific parameters for resumption failure */ default void onResumeFailed(@Reason int reason, @NonNull PersistableBundle parameters) {} /** * Invoked when data is successfully sent via {@link RangingSession#sendData(UwbAddress, * PersistableBundle, byte[])}. * * @param remoteDeviceAddress remote device's address * @param parameters protocol specific parameters sent for suspension */ default void onDataSent(@NonNull UwbAddress remoteDeviceAddress, @NonNull PersistableBundle parameters) {} /** * Invoked when data send to a remote device via {@link RangingSession#sendData(UwbAddress, * PersistableBundle, byte[])} fails. * * @param remoteDeviceAddress remote device's address * @param reason reason for the resumption failure * @param parameters protocol specific parameters for resumption failure */ default void onDataSendFailed(@NonNull UwbAddress remoteDeviceAddress, @DataFailureReason int reason, @NonNull PersistableBundle parameters) {} /** * Invoked when data is received successfully from a remote device. * The data is received piggybacked over RRM (initiator -> responder) or * RIM (responder -> initiator). *
This is only functional on a FIRA 2.0 compliant device. * * @param remoteDeviceAddress remote device's address * @param data Raw data received * @param parameters protocol specific parameters for the received data */ default void onDataReceived(@NonNull UwbAddress remoteDeviceAddress, @NonNull PersistableBundle parameters, @NonNull byte[] data) {} /** * Invoked when data receive from a remote device fails. * * @param remoteDeviceAddress remote device's address * @param reason reason for the reception failure * @param parameters protocol specific parameters for resumption failure */ default void onDataReceiveFailed(@NonNull UwbAddress remoteDeviceAddress, @DataFailureReason int reason, @NonNull PersistableBundle parameters) {} /** * Invoked when set data transfer phase config is called successfully * * @param parameters protocol specific parameters for set data transfer phase config success */ @FlaggedApi("com.android.uwb.flags.data_transfer_phase_config") default void onDataTransferPhaseConfigured(@NonNull PersistableBundle parameters) {} /** * Invoked when set data transfer phase config is failed * * @param parameters protocol specific parameters for set data transfer phase config failure */ @FlaggedApi("com.android.uwb.flags.data_transfer_phase_config") default void onDataTransferPhaseConfigFailed(@Reason int reason, @NonNull PersistableBundle parameters) {} /** * Invoked when service is discovered via OOB. *
* If this a one to many session, this can be invoked multiple times to indicate different * peers being discovered. *
* * @param parameters protocol specific params for discovered service. */ default void onServiceDiscovered(@NonNull PersistableBundle parameters) {} /** * Invoked when service is connected via OOB. ** If this a one to many session, this can be invoked multiple times to indicate different * peers being connected. *
* * @param parameters protocol specific params for connected service. */ default void onServiceConnected(@NonNull PersistableBundle parameters) {} /** * Invoked when a response/status is received for active ranging rounds update. * * @param parameters bundle of ranging rounds update status */ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) default void onRangingRoundsUpdateDtTagStatus(@NonNull PersistableBundle parameters) {} /** * Invoked when hybrid session controller is successfully configured. * * @param parameters protocol specific parameters sent for HUS session configuration */ @FlaggedApi("com.android.uwb.flags.hybrid_session_support") default void onHybridSessionControllerConfigured( @NonNull PersistableBundle parameters) {} /** * Invoked when hybrid session controller configuration fails. * * @param parameters protocol specific parameters for configuration failure */ @FlaggedApi("com.android.uwb.flags.hybrid_session_support") default void onHybridSessionControllerConfigurationFailed( @RangingChangeReason int reason, @NonNull PersistableBundle parameters) { } /** * Invoked when hybrid session controlee is successfully configured. * * @param parameters protocol specific parameters sent for HUS session configuration */ @FlaggedApi("com.android.uwb.flags.hybrid_session_support") default void onHybridSessionControleeConfigured( @NonNull PersistableBundle parameters) {} /** *Invoked when hybrid session controlee configuration fails. * * @param parameters protocol specific parameters for configuration failure */ @FlaggedApi("com.android.uwb.flags.hybrid_session_support") default void onHybridSessionControleeConfigurationFailed( @RangingChangeReason int reason, @NonNull PersistableBundle parameters) {} } /** * @hide */ public RangingSession(Executor executor, Callback callback, IUwbAdapter adapter, SessionHandle sessionHandle) { this(executor, callback, adapter, sessionHandle, /* chipId= */ null); } /** * @hide */ public RangingSession(Executor executor, Callback callback, IUwbAdapter adapter, SessionHandle sessionHandle, String chipId) { mState = State.INIT; mExecutor = executor; mCallback = callback; mAdapter = adapter; mSessionHandle = sessionHandle; mChipId = chipId; } /** * @hide */ public boolean isOpen() { return mState == State.IDLE || mState == State.ACTIVE; } /** * If the session uses custom profile, * Begins ranging for the session. *On successfully starting a ranging session, * {@link RangingSession.Callback#onStarted(PersistableBundle)} is invoked. *
On failure to start the session, * {@link RangingSession.Callback#onStartFailed(int, PersistableBundle)} * is invoked. * * If the session uses platform defined profile (like PACS), * Begins OOB discovery for the service. Once the service is discovered, * UWB session params are negotiated via OOB and a UWB session will be * started. *
On successfully discovering a service, * {@link RangingSession.Callback#onServiceDiscovered(PersistableBundle)} is invoked. *
On successfully connecting to a service, * {@link RangingSession.Callback#onServiceConnected(PersistableBundle)} is invoked. *
On successfully starting a ranging session, * {@link RangingSession.Callback#onStarted(PersistableBundle)} is invoked. *
On failure to start the session, * {@link RangingSession.Callback#onStartFailed(int, PersistableBundle)} * is invoked. * * @param params configuration parameters for starting the session */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public void start(@NonNull PersistableBundle params) { if (mState != State.IDLE) { throw new IllegalStateException(); } Log.v(mTag, "start - sessionHandle: " + mSessionHandle); try { mAdapter.startRanging(mSessionHandle, params); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Attempts to reconfigure the session with the given parameters *
This call may be made when the session is open. * *
On successfully reconfiguring the session * {@link RangingSession.Callback#onReconfigured(PersistableBundle)} is invoked. * *
On failure to reconfigure the session, * {@link RangingSession.Callback#onReconfigureFailed(int, PersistableBundle)} is invoked. * * @param params the parameters to reconfigure and their new values */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public void reconfigure(@NonNull PersistableBundle params) { if (mState != State.ACTIVE && mState != State.IDLE) { throw new IllegalStateException(); } Log.v(mTag, "reconfigure - sessionHandle: " + mSessionHandle); try { mAdapter.reconfigureRanging(mSessionHandle, params); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Stops actively ranging * *
A session that has been stopped may be resumed by calling * {@link RangingSession#start(PersistableBundle)} without the need to open a new session. * *
Stopping a {@link RangingSession} is useful when the lower layers should not discard * the parameters of the session, or when a session needs to be able to be resumed quickly. * *
If the {@link RangingSession} is no longer needed, use {@link RangingSession#close()} to * completely close the session and allow lower layers of the stack to perform necessarily * cleanup. * *
Stopped sessions may be closed by the system at any time. In such a case, * {@link RangingSession.Callback#onClosed(int, PersistableBundle)} is invoked. * *
On failure to stop the session, * {@link RangingSession.Callback#onStopFailed(int, PersistableBundle)} is invoked. */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public void stop() { if (mState != State.ACTIVE) { throw new IllegalStateException(); } Log.v(mTag, "stop - sessionHandle: " + mSessionHandle); try { mAdapter.stopRanging(mSessionHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Close the ranging session * *
After calling this function, in order resume ranging, a new {@link RangingSession} must * be opened by calling * {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}. * *
If this session is currently ranging, it will stop and close the session. *
If the session is in the process of being opened, it will attempt to stop the session from * being opened. *
If the session is already closed, the registered * {@link Callback#onClosed(int, PersistableBundle)} callback will still be invoked. * *
{@link Callback#onClosed(int, PersistableBundle)} will be invoked using the same callback * object given to {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)} * when the {@link RangingSession} was opened. The callback will be invoked after each call to * {@link #close()}, even if the {@link RangingSession} is already closed. */ @Override @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public void close() { if (mState == State.CLOSED) { mExecutor.execute(() -> mCallback.onClosed( Callback.REASON_LOCAL_REQUEST, new PersistableBundle())); return; } Log.v(mTag, "close - sessionHandle: " + mSessionHandle); try { mAdapter.closeRanging(mSessionHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Add a new controlee to an ongoing session. *
This call may be made when the session is open. * *
On successfully adding a new controlee to the session * {@link RangingSession.Callback#onControleeAdded(PersistableBundle)} is invoked. * *
On failure to add a new controlee to the session, * {@link RangingSession.Callback#onControleeAddFailed(int, PersistableBundle)} is invoked. * * @param params the parameters for the new controlee */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public void addControlee(@NonNull PersistableBundle params) { if (mState != State.ACTIVE && mState != State.IDLE) { throw new IllegalStateException(); } Log.v(mTag, "addControlee - sessionHandle: " + mSessionHandle); try { mAdapter.addControlee(mSessionHandle, params); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Remove an existing controlee from an ongoing session. *
This call may be made when the session is open. * *
On successfully removing an existing controlee from the session * {@link RangingSession.Callback#onControleeRemoved(PersistableBundle)} is invoked. * *
On failure to remove an existing controlee from the session, * {@link RangingSession.Callback#onControleeRemoveFailed(int, PersistableBundle)} is invoked. * * @param params the parameters for the existing controlee */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public void removeControlee(@NonNull PersistableBundle params) { if (mState != State.ACTIVE && mState != State.IDLE) { throw new IllegalStateException(); } Log.v(mTag, "removeControlee - sessionHandle: " + mSessionHandle); try { mAdapter.removeControlee(mSessionHandle, params); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Pauses an ongoing ranging session. * *
A session that has been pauseed may be resumed by calling * {@link RangingSession#resume(PersistableBundle)} without the need to open a new session. * *
Pauseing a {@link RangingSession} is useful when the lower layers should skip a few * ranging rounds for a session without stopping it. * *
If the {@link RangingSession} is no longer needed, use {@link RangingSession#stop()} or * {@link RangingSession#close()} to completely close the session. * *
On successfully pausing the session, * {@link RangingSession.Callback#onRangingPaused(PersistableBundle)} is invoked. * *
On failure to pause the session, * {@link RangingSession.Callback#onRangingPauseFailed(int, PersistableBundle)} is invoked. * * @param params protocol specific parameters for pausing the session */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public void pause(@NonNull PersistableBundle params) { if (mState != State.ACTIVE) { throw new IllegalStateException(); } Log.v(mTag, "pause - sessionHandle: " + mSessionHandle); try { mAdapter.pause(mSessionHandle, params); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Resumes a pauseed ranging session. * *
A session that has been previously pauseed using * {@link RangingSession#pause(PersistableBundle)} can be resumed by calling * {@link RangingSession#resume(PersistableBundle)}. * *
On successfully resuming the session, * {@link RangingSession.Callback#onRangingResumed(PersistableBundle)} is invoked. * *
On failure to resume the session, * {@link RangingSession.Callback#onRangingResumeFailed(int, PersistableBundle)} is invoked. * * @param params protocol specific parameters the resuming the session */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public void resume(@NonNull PersistableBundle params) { if (mState != State.ACTIVE) { throw new IllegalStateException(); } Log.v(mTag, "resume - sessionHandle: " + mSessionHandle); try { mAdapter.resume(mSessionHandle, params); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Send data to a remote device which is part of this ongoing session. * The data is sent by piggybacking the provided data over RRM (initiator -> responder) or * RIM (responder -> initiator). *
This is only functional on a FIRA 2.0 compliant device. * *
On successfully sending the data, * {@link RangingSession.Callback#onDataSent(UwbAddress, PersistableBundle)} is invoked. * *
On failure to send the data, * {@link RangingSession.Callback#onDataSendFailed(UwbAddress, int, PersistableBundle)} is * invoked. * * @param remoteDeviceAddress remote device's address * @param params protocol specific parameters the sending the data * @param data Raw data to be sent */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public void sendData(@NonNull UwbAddress remoteDeviceAddress, @NonNull PersistableBundle params, @NonNull byte[] data) { if (mState != State.ACTIVE) { throw new IllegalStateException(); } Log.v(mTag, "sendData - sessionHandle: " + mSessionHandle); try { mAdapter.sendData(mSessionHandle, remoteDeviceAddress, params, data); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set data transfer phase configuration during ranging as well as dedicated data transfer. *
This is only functional on a FIRA 2.0 compliant device. * *
On successfully sending the data transfer phase config, * {@link RangingSession.Callback#onDataTransferPhaseConfigured(PersistableBundle)} is * invoked. * *
On failure to send the data transfer phase config, * {@link RangingSession.Callback#onDataTransferPhaseConfigFailed(PersistableBundle)} is * invoked. * * @param params Protocol specific data transfer phase configuration parameters */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) @FlaggedApi("com.android.uwb.flags.data_transfer_phase_config") public void setDataTransferPhaseConfig(@NonNull PersistableBundle params) { if (!isOpen()) { throw new IllegalStateException(); } Log.v(mTag, "setDataTransferPhaseConfig - sessionHandle: " + mSessionHandle); try { mAdapter.setDataTransferPhaseConfig(mSessionHandle, params); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Update active ranging rounds for DT Tag. * *
On successfully sending the command, * {@link RangingSession.Callback#onRangingRoundsUpdateDtTagStatus(PersistableBundle)} * is invoked. * @param params Parameters to configure active ranging rounds */ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public void updateRangingRoundsDtTag(@NonNull PersistableBundle params) { if (mState != State.ACTIVE && mState != State.IDLE) { throw new IllegalStateException(); } Log.v(mTag, "onRangingRoundsUpdateDtTag - sessionHandle: " + mSessionHandle); try { mAdapter.updateRangingRoundsDtTag(mSessionHandle, params); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Query max application data size which can be sent by UWBS in one ranging round. * * @throws IllegalStateException, when the ranging session is not in the appropriate state for * this API to be called. * @return max application data size */ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public int queryMaxDataSizeBytes() { if (!isOpen()) { throw new IllegalStateException("Ranging session is not open"); } Log.v(mTag, "QueryMaxDataSizeBytes - sessionHandle: " + mSessionHandle); try { return mAdapter.queryMaxDataSizeBytes(mSessionHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Sets the Hybrid UWB Session Controller Configuration. * *
On successfully setting the hybrid controller configuration, * {@link RangingSession.Callback#onHybridSessionControllerConfigured(PersistableBundle)} * is invoked. * *
On failing to set the hybrid controller configuration, * {@link RangingSession.Callback#onHybridSessionControllerConfigurationFailed(int, * PersistableBundle)} is invoked. * * @param params protocol specific parameters to configure the hybrid session controller * @throws RemoteException if a remote error occurred */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) @FlaggedApi("com.android.uwb.flags.hybrid_session_support") public void setHybridSessionControllerConfiguration(@NonNull PersistableBundle params) { if (!isOpen()) { throw new IllegalStateException("Ranging session is not open"); } Log.v(mTag, "setHybridSessionControllerConfiguration - sessionHandle: " + mSessionHandle); try { mAdapter.setHybridSessionControllerConfiguration(mSessionHandle, params); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Sets the Hybrid UWB Session Controlee Configuration. * *
On successfully setting the hybrid Controlee configuration, * {@link RangingSession.Callback#onHybridSessionControleeConfigured(PersistableBundle)} * is invoked. * *
On failing to set the hybrid Controlee configuration, * {@link RangingSession.Callback#onHybridSessionControleeConfigurationFailed(int, * PersistableBundle)} is invoked. * * @param params protocol specific parameters to configure the hybrid session Controlee * @throws RemoteException if a remote error occurred */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) @FlaggedApi("com.android.uwb.flags.hybrid_session_support") public void setHybridSessionControleeConfiguration(@NonNull PersistableBundle params) { if (!isOpen()) { throw new IllegalStateException("Ranging session is not open"); } Log.v(mTag, "setHybridSessionControleeConfiguration - sessionHandle: " + mSessionHandle); try { mAdapter.setHybridSessionControleeConfiguration(mSessionHandle, params); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * @hide */ public void onRangingOpened() { if (mState == State.CLOSED) { Log.w(mTag, "onRangingOpened invoked for a closed session"); return; } Log.v(mTag, "onRangingOpened - sessionHandle: " + mSessionHandle); mState = State.IDLE; executeCallback(() -> mCallback.onOpened(this)); } /** * @hide */ public void onRangingOpenFailed(@Callback.Reason int reason, @NonNull PersistableBundle params) { if (mState == State.CLOSED) { Log.w(mTag, "onRangingOpenFailed invoked for a closed session"); return; } Log.v(mTag, "onRangingOpenFailed - sessionHandle: " + mSessionHandle); mState = State.CLOSED; executeCallback(() -> mCallback.onOpenFailed(reason, params)); } /** * @hide */ public void onRangingStarted(@NonNull PersistableBundle parameters) { if (mState == State.CLOSED) { Log.w(mTag, "onRangingStarted invoked for a closed session"); return; } Log.v(mTag, "onRangingStarted - sessionHandle: " + mSessionHandle); mState = State.ACTIVE; executeCallback(() -> mCallback.onStarted(parameters)); } /** * @hide */ public void onRangingStartFailed(@Callback.Reason int reason, @NonNull PersistableBundle params) { if (mState == State.CLOSED) { Log.w(mTag, "onRangingStartFailed invoked for a closed session"); return; } Log.v(mTag, "onRangingStartFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onStartFailed(reason, params)); } /** * @hide */ public void onRangingReconfigured(@NonNull PersistableBundle params) { if (mState == State.CLOSED) { Log.w(mTag, "onRangingReconfigured invoked for a closed session"); return; } Log.v(mTag, "onRangingReconfigured - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onReconfigured(params)); } /** * @hide */ public void onRangingReconfigureFailed(@Callback.Reason int reason, @NonNull PersistableBundle params) { if (mState == State.CLOSED) { Log.w(mTag, "onRangingReconfigureFailed invoked for a closed session"); return; } Log.v(mTag, "onRangingReconfigureFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onReconfigureFailed(reason, params)); } /** * @hide */ public void onRangingStopped(@Callback.Reason int reason, @NonNull PersistableBundle params) { if (mState == State.CLOSED) { Log.w(mTag, "onRangingStopped invoked for a closed session"); return; } Log.v(mTag, "onRangingStopped - sessionHandle: " + mSessionHandle); mState = State.IDLE; executeCallback(() -> mCallback.onStopped(reason, params)); } /** * @hide */ public void onRangingStopFailed(@Callback.Reason int reason, @NonNull PersistableBundle params) { if (mState == State.CLOSED) { Log.w(mTag, "onRangingStopFailed invoked for a closed session"); return; } Log.v(mTag, "onRangingStopFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onStopFailed(reason, params)); } /** * @hide */ public void onRangingClosed(@Callback.Reason int reason, @NonNull PersistableBundle parameters) { mState = State.CLOSED; Log.v(mTag, "onRangingClosed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onClosed(reason, parameters)); } /** * @hide */ public void onRangingResult(@NonNull RangingReport report) { if (!isOpen()) { Log.w(mTag, "onRangingResult invoked for non-open session"); return; } Log.v(mTag, "onRangingResult - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onReportReceived(report)); } /** * @hide */ public void onControleeAdded(@NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onControleeAdded invoked for non-open session"); return; } Log.v(mTag, "onControleeAdded - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onControleeAdded(params)); } /** * @hide */ public void onControleeAddFailed(@Callback.ControleeFailureReason int reason, @NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onControleeAddFailed invoked for non-open session"); return; } Log.v(mTag, "onControleeAddFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onControleeAddFailed(reason, params)); } /** * @hide */ public void onControleeRemoved(@NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onControleeRemoved invoked for non-open session"); return; } Log.v(mTag, "onControleeRemoved - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onControleeRemoved(params)); } /** * @hide */ public void onControleeRemoveFailed(@Callback.ControleeFailureReason int reason, @NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onControleeRemoveFailed invoked for non-open session"); return; } Log.v(mTag, "onControleeRemoveFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onControleeRemoveFailed(reason, params)); } /** * @hide */ public void onRangingPaused(@NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onRangingPaused invoked for non-open session"); return; } Log.v(mTag, "onRangingPaused - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onPaused(params)); } /** * @hide */ public void onRangingPauseFailed(@Callback.Reason int reason, @NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onRangingPauseFailed invoked for non-open session"); return; } Log.v(mTag, "onRangingPauseFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onPauseFailed(reason, params)); } /** * @hide */ public void onRangingResumed(@NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onRangingResumed invoked for non-open session"); return; } Log.v(mTag, "onRangingResumed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onResumed(params)); } /** * @hide */ public void onRangingResumeFailed(@Callback.Reason int reason, @NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onRangingResumeFailed invoked for non-open session"); return; } Log.v(mTag, "onRangingResumeFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onResumeFailed(reason, params)); } /** * @hide */ public void onDataSent(@NonNull UwbAddress remoteDeviceAddress, @NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onDataSent invoked for non-open session"); return; } Log.v(mTag, "onDataSent - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onDataSent(remoteDeviceAddress, params)); } /** * @hide */ public void onDataSendFailed(@NonNull UwbAddress remoteDeviceAddress, @Callback.DataFailureReason int reason, @NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onDataSendFailed invoked for non-open session"); return; } Log.v(mTag, "onDataSendFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onDataSendFailed(remoteDeviceAddress, reason, params)); } /** * @hide */ public void onDataReceived(@NonNull UwbAddress remoteDeviceAddress, @NonNull PersistableBundle params, @NonNull byte[] data) { if (!isOpen()) { Log.w(mTag, "onDataReceived invoked for non-open session"); return; } Log.v(mTag, "onDataReceived - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onDataReceived(remoteDeviceAddress, params, data)); } /** * @hide */ public void onDataReceiveFailed(@NonNull UwbAddress remoteDeviceAddress, @Callback.DataFailureReason int reason, @NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onDataReceiveFailed invoked for non-open session"); return; } Log.v(mTag, "onDataReceiveFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onDataReceiveFailed(remoteDeviceAddress, reason, params)); } /** * @hide */ public void onDataTransferPhaseConfigured(@NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onDataTransferPhaseConfigured invoked for non-open session"); return; } Log.v(mTag, "onDataTransferPhaseConfigured - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onDataTransferPhaseConfigured(params)); } /** * @hide */ public void onDataTransferPhaseConfigFailed(@Callback.Reason int reason, @NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onDataTransferPhaseConfigFailed invoked for non-open session"); return; } Log.v(mTag, "onDataTransferPhaseConfigFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onDataTransferPhaseConfigFailed(reason, params)); } /** * @hide */ public void onServiceDiscovered(@NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onServiceDiscovered invoked for non-open session"); return; } Log.v(mTag, "onServiceDiscovered - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onServiceDiscovered(params)); } /** * @hide */ public void onServiceConnected(@NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onServiceConnected invoked for non-open session"); return; } Log.v(mTag, "onServiceConnected - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onServiceConnected(params)); } /** * @hide */ public void onRangingRoundsUpdateDtTagStatus(@NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onDlTDoARangingRoundsUpdateStatus invoked for non-open session"); return; } Log.v(mTag, "onDlTDoARangingRoundsUpdateStatus - sessionHandle: " + mSessionHandle); if (SdkLevel.isAtLeastU()) { executeCallback(() -> mCallback.onRangingRoundsUpdateDtTagStatus(params)); } } /** * @hide */ public void onHybridSessionControllerConfigured(@NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onHybridSessionControllerConfigured invoked for non-open session"); return; } Log.v(mTag, "onHybridSessionControllerConfigured - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onHybridSessionControllerConfigured(params)); } /** * @hide */ public void onHybridSessionControllerConfigurationFailed(@Callback.Reason int reason, @NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onHybridSessionControllerConfigurationFailed invoked for non-open" + "session"); return; } Log.v(mTag, "onHybridSessionControllerConfigurationFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onHybridSessionControllerConfigurationFailed( reason, params)); } /** * @hide */ public void onHybridSessionControleeConfigured(@NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onHybridSessionControleeConfigured invoked for non-open session"); return; } Log.v(mTag, "onHybridSessionControleeConfigured - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onHybridSessionControleeConfigured(params)); } /** * @hide */ public void onHybridSessionControleeConfigurationFailed(@Callback.Reason int reason, @NonNull PersistableBundle params) { if (!isOpen()) { Log.w(mTag, "onHybridSessionControleeConfigurationFailed invoked for non-open" + "session"); return; } Log.v(mTag, "onHybridSessionControleeConfigurationFailed - sessionHandle: " + mSessionHandle); executeCallback(() -> mCallback.onHybridSessionControleeConfigurationFailed( reason, params)); } /** * @hide */ private void executeCallback(@NonNull Runnable runnable) { final long identity = Binder.clearCallingIdentity(); try { mExecutor.execute(runnable); } finally { Binder.restoreCallingIdentity(identity); } } /** * Updates the UWB filter engine's pose information. This requires that the call to * {@link UwbManager#openRangingSession} indicated an application pose source. * * @param parameters Parameters representing the session to update, and the pose information. */ @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) public void updatePose(@NonNull PersistableBundle parameters) { try { mAdapter.updatePose(mSessionHandle, parameters); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }