summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/uwb/IUwbAdapter.aidl84
-rw-r--r--core/java/android/uwb/IUwbRangingCallbacks.aidl67
-rw-r--r--core/java/android/uwb/RangingChangeReason.aidl (renamed from core/java/android/uwb/CloseReason.aidl)25
-rw-r--r--core/java/android/uwb/RangingManager.java154
-rw-r--r--core/java/android/uwb/RangingSession.java363
-rw-r--r--core/java/android/uwb/StartFailureReason.aidl52
-rw-r--r--core/java/android/uwb/UwbManager.java14
-rw-r--r--core/tests/uwbtests/src/android/uwb/RangingManagerTest.java166
-rw-r--r--core/tests/uwbtests/src/android/uwb/RangingSessionTest.java244
9 files changed, 861 insertions, 308 deletions
diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl
index 2c8b2e462510..b9c55081a103 100644
--- a/core/java/android/uwb/IUwbAdapter.aidl
+++ b/core/java/android/uwb/IUwbAdapter.aidl
@@ -119,42 +119,96 @@ interface IUwbAdapter {
PersistableBundle getSpecificationInfo();
/**
- * Request to start a new ranging session
+ * Request to open a new ranging session
*
- * This function must return before calling IUwbAdapterCallbacks
- * #onRangingStarted, #onRangingClosed, or #onRangingResult.
+ * This function must return before calling any functions in
+ * IUwbAdapterCallbacks.
*
- * A ranging session does not need to be started before returning.
+ * This function does not start the ranging session, but all necessary
+ * components must be initialized and ready to start a new ranging
+ * session prior to calling IUwbAdapterCallback#onRangingOpened.
*
- * IUwbAdapterCallbacks#onRangingStarted must be called within
- * RANGING_SESSION_START_THRESHOLD_MS milliseconds of #startRanging being called
- * if the ranging session is scheduled to start successfully.
+ * IUwbAdapterCallbacks#onRangingOpened must be called within
+ * RANGING_SESSION_OPEN_THRESHOLD_MS milliseconds of #openRanging being
+ * called if the ranging session is opened successfully.
*
- * IUwbAdapterCallbacks#onRangingStartFailed must be called within
- * RANGING_SESSION_START_THRESHOLD_MS milliseconds of #startRanging being called
- * if the ranging session fails to be scheduled to start successfully.
+ * IUwbAdapterCallbacks#onRangingOpenFailed must be called within
+ * RANGING_SESSION_OPEN_THRESHOLD_MS milliseconds of #openRanging being called
+ * if the ranging session fails to be opened.
*
* @param rangingCallbacks the callbacks used to deliver ranging information
* @param parameters the configuration to use for ranging
* @return a SessionHandle used to identify this ranging request
*/
- SessionHandle startRanging(in IUwbRangingCallbacks rangingCallbacks,
- in PersistableBundle parameters);
+ SessionHandle openRanging(in IUwbRangingCallbacks rangingCallbacks,
+ in PersistableBundle parameters);
+
+ /**
+ * Request to start ranging
+ *
+ * IUwbAdapterCallbacks#onRangingStarted must be called within
+ * RANGING_SESSION_START_THRESHOLD_MS milliseconds of #startRanging being
+ * called if the ranging session starts successfully.
+ *
+ * IUwbAdapterCallbacks#onRangingStartFailed must be called within
+ * RANGING_SESSION_START_THRESHOLD_MS milliseconds of #startRanging being
+ * called if the ranging session fails to be started.
+ *
+ * @param sessionHandle the session handle to start ranging for
+ * @param parameters additional configuration required to start ranging
+ */
+ void startRanging(in SessionHandle sessionHandle,
+ in PersistableBundle parameters);
+
+ /**
+ * Request to reconfigure ranging
+ *
+ * IUwbAdapterCallbacks#onRangingReconfigured must be called after
+ * successfully reconfiguring the session.
+ *
+ * IUwbAdapterCallbacks#onRangingReconfigureFailed must be called after
+ * failing to reconfigure the session.
+ *
+ * A session must not be modified by a failed call to #reconfigureRanging.
+ *
+ * @param sessionHandle the session handle to start ranging for
+ * @param parameters the parameters to reconfigure and their new values
+ */
+ void reconfigureRanging(in SessionHandle sessionHandle,
+ in PersistableBundle parameters);
+
+ /**
+ * Request to stop ranging
+ *
+ * IUwbAdapterCallbacks#onRangingStopped must be called after
+ * successfully stopping the session.
+ *
+ * IUwbAdapterCallbacks#onRangingStopFailed must be called after failing
+ * to stop the session.
+ *
+ * @param sessionHandle the session handle to stop ranging for
+ */
+ void stopRanging(in SessionHandle sessionHandle);
/**
- * Stop and close ranging for the session associated with the given handle
+ * Close ranging for the session associated with the given handle
*
* Calling with an invalid handle or a handle that has already been closed
* is a no-op.
*
* IUwbAdapterCallbacks#onRangingClosed must be called within
- * RANGING_SESSION_CLOSE_THRESHOLD_MS of #stopRanging being called.
+ * RANGING_SESSION_CLOSE_THRESHOLD_MS of #closeRanging being called.
*
- * @param sessionHandle the session handle to stop ranging for
+ * @param sessionHandle the session handle to close ranging for
*/
void closeRanging(in SessionHandle sessionHandle);
/**
+ * The maximum allowed time to open a ranging session.
+ */
+ const int RANGING_SESSION_OPEN_THRESHOLD_MS = 3000; // Value TBD
+
+ /**
* The maximum allowed time to start a ranging session.
*/
const int RANGING_SESSION_START_THRESHOLD_MS = 3000; // Value TBD
diff --git a/core/java/android/uwb/IUwbRangingCallbacks.aidl b/core/java/android/uwb/IUwbRangingCallbacks.aidl
index 1fc3bfd818c3..f71f3ff7ad44 100644
--- a/core/java/android/uwb/IUwbRangingCallbacks.aidl
+++ b/core/java/android/uwb/IUwbRangingCallbacks.aidl
@@ -17,16 +17,33 @@
package android.uwb;
import android.os.PersistableBundle;
-import android.uwb.CloseReason;
+import android.uwb.RangingChangeReason;
import android.uwb.RangingReport;
import android.uwb.SessionHandle;
-import android.uwb.StartFailureReason;
/**
* @hide
*/
interface IUwbRangingCallbacks {
/**
+ * Called when the ranging session has been opened
+ *
+ * @param sessionHandle the session the callback is being invoked for
+ */
+ void onRangingOpened(in SessionHandle sessionHandle);
+
+ /**
+ * Called when a ranging session fails to start
+ *
+ * @param sessionHandle the session the callback is being invoked for
+ * @param reason the reason the session failed to start
+ * @param parameters protocol specific parameters
+ */
+ void onRangingOpenFailed(in SessionHandle sessionHandle,
+ RangingChangeReason reason,
+ in PersistableBundle parameters);
+
+ /**
* Called when ranging has started
*
* May output parameters generated by the lower layers that must be sent to the
@@ -47,8 +64,49 @@ interface IUwbRangingCallbacks {
* @param reason the reason the session failed to start
* @param parameters protocol specific parameters
*/
- void onRangingStartFailed(in SessionHandle sessionHandle, StartFailureReason reason,
+ void onRangingStartFailed(in SessionHandle sessionHandle,
+ RangingChangeReason reason,
in PersistableBundle parameters);
+
+ /**
+ * Called when ranging has been reconfigured
+ *
+ * @param sessionHandle the session the callback is being invoked for
+ * @param parameters the updated ranging configuration
+ */
+ void onRangingReconfigured(in SessionHandle sessionHandle,
+ in PersistableBundle parameters);
+
+ /**
+ * Called when a ranging session fails to be reconfigured
+ *
+ * @param sessionHandle the session the callback is being invoked for
+ * @param reason the reason the session failed to reconfigure
+ * @param parameters protocol specific parameters
+ */
+ void onRangingReconfigureFailed(in SessionHandle sessionHandle,
+ RangingChangeReason reason,
+ in PersistableBundle parameters);
+
+ /**
+ * Called when the ranging session has been stopped
+ *
+ * @param sessionHandle the session the callback is being invoked for
+ */
+
+ void onRangingStopped(in SessionHandle sessionHandle);
+
+ /**
+ * Called when a ranging session fails to stop
+ *
+ * @param sessionHandle the session the callback is being invoked for
+ * @param reason the reason the session failed to stop
+ * @param parameters protocol specific parameters
+ */
+ void onRangingStopFailed(in SessionHandle sessionHandle,
+ RangingChangeReason reason,
+ in PersistableBundle parameters);
+
/**
* Called when a ranging session is closed
*
@@ -56,7 +114,8 @@ interface IUwbRangingCallbacks {
* @param reason the reason the session was closed
* @param parameters protocol specific parameters
*/
- void onRangingClosed(in SessionHandle sessionHandle, CloseReason reason,
+ void onRangingClosed(in SessionHandle sessionHandle,
+ RangingChangeReason reason,
in PersistableBundle parameters);
/**
diff --git a/core/java/android/uwb/CloseReason.aidl b/core/java/android/uwb/RangingChangeReason.aidl
index bef129e2c1c7..19d4b3949d07 100644
--- a/core/java/android/uwb/CloseReason.aidl
+++ b/core/java/android/uwb/RangingChangeReason.aidl
@@ -20,39 +20,44 @@ package android.uwb;
* @hide
*/
@Backing(type="int")
-enum CloseReason {
+enum RangingChangeReason {
/**
* Unknown reason
*/
UNKNOWN,
/**
- * A local API call triggered the close, such as a call to
- * IUwbAdapter.stopRanging.
+ * A local API call triggered the change, such as a call to
+ * IUwbAdapter.closeRanging.
*/
LOCAL_API,
/**
- * The maximum number of sessions has been reached. This error may be generated
- * for an active session if a higher priority session begins.
+ * The maximum number of sessions has been reached. This may be generated for
+ * an active session if a higher priority session begins.
*/
MAX_SESSIONS_REACHED,
/**
- * The system state has changed resulting in the session ending (e.g. the user
- * disables UWB, or the user's locale changes and an active channel is no longer
- * permitted to be used).
+ * The system state has changed resulting in the session changing (e.g. the
+ * user disables UWB, or the user's locale changes and an active channel is no
+ * longer permitted to be used).
*/
SYSTEM_POLICY,
/**
- * The remote device has requested to terminate the session
+ * The remote device has requested to change the session
*/
REMOTE_REQUEST,
/**
- * The session was closed for a protocol specific reason
+ * The session changed for a protocol specific reason
*/
PROTOCOL_SPECIFIC,
+
+ /**
+ * The provided parameters were invalid
+ */
+ BAD_PARAMETERS,
}
diff --git a/core/java/android/uwb/RangingManager.java b/core/java/android/uwb/RangingManager.java
index a9bf4abe566a..5ac95d49c1bb 100644
--- a/core/java/android/uwb/RangingManager.java
+++ b/core/java/android/uwb/RangingManager.java
@@ -50,7 +50,7 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
@NonNull RangingSession.Callback callbacks) {
SessionHandle sessionHandle;
try {
- sessionHandle = mAdapter.startRanging(this, params);
+ sessionHandle = mAdapter.openRanging(this, params);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -59,7 +59,7 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
if (hasSession(sessionHandle)) {
Log.w(TAG, "Newly created session unexpectedly reuses an active SessionHandle");
executor.execute(() -> callbacks.onClosed(
- RangingSession.Callback.CLOSE_REASON_LOCAL_GENERIC_ERROR,
+ RangingSession.Callback.REASON_GENERIC_ERROR,
new PersistableBundle()));
}
@@ -75,6 +75,67 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
}
@Override
+ public void onRangingOpened(SessionHandle sessionHandle) {
+ synchronized (this) {
+ if (!hasSession(sessionHandle)) {
+ Log.w(TAG,
+ "onRangingOpened - received unexpected SessionHandle: " + sessionHandle);
+ return;
+ }
+
+ RangingSession session = mRangingSessionTable.get(sessionHandle);
+ session.onRangingOpened();
+ }
+ }
+
+ @Override
+ public void onRangingOpenFailed(SessionHandle sessionHandle, @RangingChangeReason int reason,
+ PersistableBundle parameters) {
+ synchronized (this) {
+ if (!hasSession(sessionHandle)) {
+ Log.w(TAG,
+ "onRangingOpened - received unexpected SessionHandle: " + sessionHandle);
+ return;
+ }
+
+ RangingSession session = mRangingSessionTable.get(sessionHandle);
+ session.onRangingOpenFailed(convertToReason(reason), parameters);
+ mRangingSessionTable.remove(sessionHandle);
+ }
+ }
+
+ @Override
+ public void onRangingReconfigured(SessionHandle sessionHandle, PersistableBundle parameters) {
+ synchronized (this) {
+ if (!hasSession(sessionHandle)) {
+ Log.w(TAG,
+ "onRangingReconfigured - received unexpected SessionHandle: "
+ + sessionHandle);
+ return;
+ }
+
+ RangingSession session = mRangingSessionTable.get(sessionHandle);
+ session.onRangingReconfigured(parameters);
+ }
+ }
+
+ @Override
+ public void onRangingReconfigureFailed(SessionHandle sessionHandle,
+ @RangingChangeReason int reason, PersistableBundle params) {
+ synchronized (this) {
+ if (!hasSession(sessionHandle)) {
+ Log.w(TAG, "onRangingStartFailed - received unexpected SessionHandle: "
+ + sessionHandle);
+ return;
+ }
+
+ RangingSession session = mRangingSessionTable.get(sessionHandle);
+ session.onRangingReconfigureFailed(convertToReason(reason), params);
+ }
+ }
+
+
+ @Override
public void onRangingStarted(SessionHandle sessionHandle, PersistableBundle parameters) {
synchronized (this) {
if (!hasSession(sessionHandle)) {
@@ -89,7 +150,7 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
}
@Override
- public void onRangingStartFailed(SessionHandle sessionHandle, int reason,
+ public void onRangingStartFailed(SessionHandle sessionHandle, @RangingChangeReason int reason,
PersistableBundle params) {
synchronized (this) {
if (!hasSession(sessionHandle)) {
@@ -99,13 +160,42 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
}
RangingSession session = mRangingSessionTable.get(sessionHandle);
- session.onRangingClosed(convertStartFailureToCloseReason(reason), params);
- mRangingSessionTable.remove(sessionHandle);
+ session.onRangingStartFailed(convertToReason(reason), params);
+ }
+ }
+
+ @Override
+ public void onRangingStopped(SessionHandle sessionHandle) {
+ synchronized (this) {
+ if (!hasSession(sessionHandle)) {
+ Log.w(TAG, "onRangingStopped - received unexpected SessionHandle: "
+ + sessionHandle);
+ return;
+ }
+
+ RangingSession session = mRangingSessionTable.get(sessionHandle);
+ session.onRangingStopped();
}
}
@Override
- public void onRangingClosed(SessionHandle sessionHandle, int reason, PersistableBundle params) {
+ public void onRangingStopFailed(SessionHandle sessionHandle, @RangingChangeReason int reason,
+ PersistableBundle parameters) {
+ synchronized (this) {
+ if (!hasSession(sessionHandle)) {
+ Log.w(TAG, "onRangingStopFailed - received unexpected SessionHandle: "
+ + sessionHandle);
+ return;
+ }
+
+ RangingSession session = mRangingSessionTable.get(sessionHandle);
+ session.onRangingStopFailed(convertToReason(reason), parameters);
+ }
+ }
+
+ @Override
+ public void onRangingClosed(SessionHandle sessionHandle, @RangingChangeReason int reason,
+ PersistableBundle params) {
synchronized (this) {
if (!hasSession(sessionHandle)) {
Log.w(TAG, "onRangingClosed - received unexpected SessionHandle: " + sessionHandle);
@@ -113,7 +203,7 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
}
RangingSession session = mRangingSessionTable.get(sessionHandle);
- session.onRangingClosed(convertToCloseReason(reason), params);
+ session.onRangingClosed(convertToReason(reason), params);
mRangingSessionTable.remove(sessionHandle);
}
}
@@ -131,48 +221,30 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
}
}
- @RangingSession.Callback.CloseReason
- private static int convertToCloseReason(@CloseReason int reason) {
+ @RangingSession.Callback.Reason
+ private static int convertToReason(@RangingChangeReason int reason) {
switch (reason) {
- case CloseReason.LOCAL_API:
- return RangingSession.Callback.CLOSE_REASON_LOCAL_CLOSE_API;
-
- case CloseReason.MAX_SESSIONS_REACHED:
- return RangingSession.Callback.CLOSE_REASON_LOCAL_MAX_SESSIONS_REACHED;
-
- case CloseReason.SYSTEM_POLICY:
- return RangingSession.Callback.CLOSE_REASON_LOCAL_SYSTEM_POLICY;
+ case RangingChangeReason.LOCAL_API:
+ return RangingSession.Callback.REASON_LOCAL_REQUEST;
- case CloseReason.REMOTE_REQUEST:
- return RangingSession.Callback.CLOSE_REASON_REMOTE_REQUEST;
+ case RangingChangeReason.MAX_SESSIONS_REACHED:
+ return RangingSession.Callback.REASON_MAX_SESSIONS_REACHED;
- case CloseReason.PROTOCOL_SPECIFIC:
- return RangingSession.Callback.CLOSE_REASON_PROTOCOL_SPECIFIC;
-
- case CloseReason.UNKNOWN:
- default:
- return RangingSession.Callback.CLOSE_REASON_UNKNOWN;
- }
- }
-
- @RangingSession.Callback.CloseReason
- private static int convertStartFailureToCloseReason(@StartFailureReason int reason) {
- switch (reason) {
- case StartFailureReason.BAD_PARAMETERS:
- return RangingSession.Callback.CLOSE_REASON_LOCAL_BAD_PARAMETERS;
+ case RangingChangeReason.SYSTEM_POLICY:
+ return RangingSession.Callback.REASON_SYSTEM_POLICY;
- case StartFailureReason.MAX_SESSIONS_REACHED:
- return RangingSession.Callback.CLOSE_REASON_LOCAL_MAX_SESSIONS_REACHED;
+ case RangingChangeReason.REMOTE_REQUEST:
+ return RangingSession.Callback.REASON_REMOTE_REQUEST;
- case StartFailureReason.SYSTEM_POLICY:
- return RangingSession.Callback.CLOSE_REASON_LOCAL_SYSTEM_POLICY;
+ case RangingChangeReason.PROTOCOL_SPECIFIC:
+ return RangingSession.Callback.REASON_PROTOCOL_SPECIFIC_ERROR;
- case StartFailureReason.PROTOCOL_SPECIFIC:
- return RangingSession.Callback.CLOSE_REASON_PROTOCOL_SPECIFIC;
+ case RangingChangeReason.BAD_PARAMETERS:
+ return RangingSession.Callback.REASON_BAD_PARAMETERS;
- case StartFailureReason.UNKNOWN:
+ case RangingChangeReason.UNKNOWN:
default:
- return RangingSession.Callback.CLOSE_REASON_UNKNOWN;
+ return RangingSession.Callback.REASON_UNKNOWN;
}
}
}
diff --git a/core/java/android/uwb/RangingSession.java b/core/java/android/uwb/RangingSession.java
index b0dbd85c0812..0f87af415825 100644
--- a/core/java/android/uwb/RangingSession.java
+++ b/core/java/android/uwb/RangingSession.java
@@ -36,9 +36,9 @@ import java.util.concurrent.Executor;
* <p>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#onOpenSuccess(RangingSession, PersistableBundle)}. If opening a
- * session fails, the failure is reported through
- * {@link RangingSession.Callback#onClosed(int, PersistableBundle)} with the failure reason.
+ * {@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
*/
@@ -50,103 +50,162 @@ public final class RangingSession implements AutoCloseable {
private final Callback mCallback;
private enum State {
+ /**
+ * The state of the {@link RangingSession} until
+ * {@link RangingSession.Callback#onOpened(RangingSession)} is invoked
+ */
INIT,
- OPEN,
- CLOSED,
+
+ /**
+ * 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;
+ private State mState = State.INIT;
/**
* Interface for receiving {@link RangingSession} events
*/
public interface Callback {
/**
- * Invoked when {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}
- * is successful
- *
- * @param session the newly opened {@link RangingSession}
- * @param sessionInfo session specific parameters from lower layers
- */
- void onOpenSuccess(@NonNull RangingSession session, @NonNull PersistableBundle sessionInfo);
-
- /**
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
- CLOSE_REASON_UNKNOWN,
- CLOSE_REASON_LOCAL_CLOSE_API,
- CLOSE_REASON_LOCAL_BAD_PARAMETERS,
- CLOSE_REASON_LOCAL_GENERIC_ERROR,
- CLOSE_REASON_LOCAL_MAX_SESSIONS_REACHED,
- CLOSE_REASON_LOCAL_SYSTEM_POLICY,
- CLOSE_REASON_REMOTE_GENERIC_ERROR,
- CLOSE_REASON_REMOTE_REQUEST})
- @interface CloseReason {}
+ 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})
+ @interface Reason {}
/**
* Indicates that the session was closed or failed to open due to an unknown reason
*/
- int CLOSE_REASON_UNKNOWN = 0;
+ 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 CLOSE_REASON_LOCAL_CLOSE_API = 1;
+ int REASON_LOCAL_REQUEST = 1;
/**
- * Indicates that the session failed to open due to erroneous parameters passed
- * to {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}
+ * Indicates that the session was closed or failed to open due to an explicit request from
+ * the remote device.
*/
- int CLOSE_REASON_LOCAL_BAD_PARAMETERS = 2;
+ int REASON_REMOTE_REQUEST = 2;
/**
- * Indicates that the session was closed due to some local error on this device besides the
- * error code already listed
+ * Indicates that the session was closed or failed to open due to erroneous parameters
*/
- int CLOSE_REASON_LOCAL_GENERIC_ERROR = 3;
+ int REASON_BAD_PARAMETERS = 3;
/**
- * Indicates that the session failed to open because the number of currently open sessions
- * is equal to {@link UwbManager#getMaxSimultaneousSessions()}
+ * Indicates an error on this device besides the error code already listed
*/
- int CLOSE_REASON_LOCAL_MAX_SESSIONS_REACHED = 4;
+ int REASON_GENERIC_ERROR = 4;
/**
- * Indicates that the session was closed or failed to open due to local system policy, such
+ * Indicates that the number of currently open sessions is equal to
+ * {@link UwbManager#getMaxSimultaneousSessions()} 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 CLOSE_REASON_LOCAL_SYSTEM_POLICY = 5;
+ int REASON_SYSTEM_POLICY = 6;
/**
- * Indicates that the session was closed or failed to open due to an error with the remote
- * device besides error codes already listed.
+ * Indicates a protocol specific error. The associated {@link PersistableBundle} should be
+ * consulted for additional information.
*/
- int CLOSE_REASON_REMOTE_GENERIC_ERROR = 6;
+ int REASON_PROTOCOL_SPECIFIC_ERROR = 7;
/**
- * Indicates that the session was closed or failed to open due to an explicit request from
- * the remote device.
+ * 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 when {@link RangingSession#start(PersistableBundle)} is successful
+ * @param sessionInfo session specific parameters from the lower layers
+ */
+ void onStarted(@NonNull PersistableBundle sessionInfo);
+
+ /**
+ * Invoked when {@link RangingSession#start(PersistableBundle)} fails
+ *
+ * @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
*/
- int CLOSE_REASON_REMOTE_REQUEST = 7;
+ void onReconfigureFailed(@Reason int reason, @NonNull PersistableBundle params);
/**
- * Indicates that the session was closed for a protocol specific reason. The associated
- * {@link PersistableBundle} should be consulted for additional information.
+ * Invoked when a request to stop the session succeeds
*/
- int CLOSE_REASON_PROTOCOL_SPECIFIC = 8;
+ void onStopped();
/**
+ * 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()}, or when session failed
- * to open.
+ * {@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(@CloseReason int reason, @NonNull PersistableBundle parameters);
+ void onClosed(@Reason int reason, @NonNull PersistableBundle parameters);
/**
* Called once per ranging interval even when a ranging measurement fails
@@ -172,12 +231,95 @@ public final class RangingSession implements AutoCloseable {
* @hide
*/
public boolean isOpen() {
- return mState == State.OPEN;
+ return mState == State.IDLE || mState == State.ACTIVE;
+ }
+
+ /**
+ * Begins ranging for the session.
+ *
+ * <p>On successfully starting a ranging session,
+ * {@link RangingSession.Callback#onStarted(PersistableBundle)} is invoked.
+ *
+ * <p>On failure to start the session,
+ * {@link RangingSession.Callback#onStartFailed(int, PersistableBundle)} is invoked.
+ *
+ * @param params configuration parameters for starting the session
+ */
+ public void start(@NonNull PersistableBundle params) {
+ if (mState != State.IDLE) {
+ throw new IllegalStateException();
+ }
+
+ try {
+ mAdapter.startRanging(mSessionHandle, params);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Attempts to reconfigure the session with the given parameters
+ * <p>This call may be made when the session is open.
+ *
+ * <p>On successfully reconfiguring the session
+ * {@link RangingSession.Callback#onReconfigured(PersistableBundle)} is invoked.
+ *
+ * <p>On failure to reconfigure the session,
+ * {@link RangingSession.Callback#onReconfigureFailed(int, PersistableBundle)} is invoked.
+ *
+ * @param params the parameters to reconfigure and their new values
+ */
+ public void reconfigure(@NonNull PersistableBundle params) {
+ if (mState != State.ACTIVE && mState != State.IDLE) {
+ throw new IllegalStateException();
+ }
+
+ try {
+ mAdapter.reconfigureRanging(mSessionHandle, params);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Stops actively ranging
+ *
+ * <p>A session that has been stopped may be resumed by calling
+ * {@link RangingSession#start(PersistableBundle)} without the need to open a new session.
+ *
+ * <p>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.
+ *
+ * <p>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.
+ *
+ * <p>Stopped sessions may be closed by the system at any time. In such a case,
+ * {@link RangingSession.Callback#onClosed(int, PersistableBundle)} is invoked.
+ *
+ * <p>On failure to stop the session,
+ * {@link RangingSession.Callback#onStopFailed(int, PersistableBundle)} is invoked.
+ */
+ public void stop() {
+ if (mState != State.ACTIVE) {
+ throw new IllegalStateException();
+ }
+
+ try {
+ mAdapter.stopRanging(mSessionHandle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
* Close the ranging session
- * <p>If this session is currently open, it will close and stop the session.
+ *
+ * <p>After calling this function, in order resume ranging, a new {@link RangingSession} must
+ * be opened by calling
+ * {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}.
+ *
+ * <p>If this session is currently ranging, it will stop and close the session.
* <p>If the session is in the process of being opened, it will attempt to stop the session from
* being opened.
* <p>If the session is already closed, the registered
@@ -192,7 +334,7 @@ public final class RangingSession implements AutoCloseable {
public void close() {
if (mState == State.CLOSED) {
mExecutor.execute(() -> mCallback.onClosed(
- Callback.CLOSE_REASON_LOCAL_CLOSE_API, new PersistableBundle()));
+ Callback.REASON_LOCAL_REQUEST, new PersistableBundle()));
return;
}
@@ -206,32 +348,114 @@ public final class RangingSession implements AutoCloseable {
/**
* @hide
*/
+ public void onRangingOpened() {
+ if (mState == State.CLOSED) {
+ Log.w(TAG, "onRangingOpened invoked for a closed session");
+ return;
+ }
+
+ mState = State.IDLE;
+ executeCallback(() -> mCallback.onOpened(this));
+ }
+
+ /**
+ * @hide
+ */
+ public void onRangingOpenFailed(@Callback.Reason int reason,
+ @NonNull PersistableBundle params) {
+ if (mState == State.CLOSED) {
+ Log.w(TAG, "onRangingOpenFailed invoked for a closed session");
+ return;
+ }
+
+ mState = State.CLOSED;
+ executeCallback(() -> mCallback.onOpenFailed(reason, params));
+ }
+
+ /**
+ * @hide
+ */
public void onRangingStarted(@NonNull PersistableBundle parameters) {
if (mState == State.CLOSED) {
Log.w(TAG, "onRangingStarted invoked for a closed session");
return;
}
- mState = State.OPEN;
- final long identity = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onOpenSuccess(this, parameters));
- } finally {
- Binder.restoreCallingIdentity(identity);
+ mState = State.ACTIVE;
+ executeCallback(() -> mCallback.onStarted(parameters));
+ }
+
+ /**
+ * @hide
+ */
+ public void onRangingStartFailed(@Callback.Reason int reason,
+ @NonNull PersistableBundle params) {
+ if (mState == State.CLOSED) {
+ Log.w(TAG, "onRangingStartFailed invoked for a closed session");
+ return;
}
+
+ executeCallback(() -> mCallback.onStartFailed(reason, params));
}
/**
* @hide
*/
- public void onRangingClosed(@Callback.CloseReason int reason, PersistableBundle parameters) {
- mState = State.CLOSED;
- final long identity = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onClosed(reason, parameters));
- } finally {
- Binder.restoreCallingIdentity(identity);
+ public void onRangingReconfigured(@NonNull PersistableBundle params) {
+ if (mState == State.CLOSED) {
+ Log.w(TAG, "onRangingReconfigured invoked for a closed session");
+ return;
+ }
+
+ executeCallback(() -> mCallback.onReconfigured(params));
+ }
+
+ /**
+ * @hide
+ */
+ public void onRangingReconfigureFailed(@Callback.Reason int reason,
+ @NonNull PersistableBundle params) {
+ if (mState == State.CLOSED) {
+ Log.w(TAG, "onRangingReconfigureFailed invoked for a closed session");
+ return;
+ }
+
+ executeCallback(() -> mCallback.onReconfigureFailed(reason, params));
+ }
+
+ /**
+ * @hide
+ */
+ public void onRangingStopped() {
+ if (mState == State.CLOSED) {
+ Log.w(TAG, "onRangingStopped invoked for a closed session");
+ return;
}
+
+ mState = State.IDLE;
+ executeCallback(() -> mCallback.onStopped());
+ }
+
+ /**
+ * @hide
+ */
+ public void onRangingStopFailed(@Callback.Reason int reason,
+ @NonNull PersistableBundle params) {
+ if (mState == State.CLOSED) {
+ Log.w(TAG, "onRangingStopFailed invoked for a closed session");
+ return;
+ }
+
+ executeCallback(() -> mCallback.onStopFailed(reason, params));
+ }
+
+ /**
+ * @hide
+ */
+ public void onRangingClosed(@Callback.Reason int reason,
+ @NonNull PersistableBundle parameters) {
+ mState = State.CLOSED;
+ executeCallback(() -> mCallback.onClosed(reason, parameters));
}
/**
@@ -243,9 +467,16 @@ public final class RangingSession implements AutoCloseable {
return;
}
+ executeCallback(() -> mCallback.onReportReceived(report));
+ }
+
+ /**
+ * @hide
+ */
+ private void executeCallback(@NonNull Runnable runnable) {
final long identity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() -> mCallback.onReportReceived(report));
+ mExecutor.execute(runnable);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/core/java/android/uwb/StartFailureReason.aidl b/core/java/android/uwb/StartFailureReason.aidl
deleted file mode 100644
index 4d9c962f529b..000000000000
--- a/core/java/android/uwb/StartFailureReason.aidl
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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;
-
-/**
- * @hide
- */
-@Backing(type="int")
-enum StartFailureReason {
- /**
- * Unknown start failure reason
- */
- UNKNOWN,
-
- /**
- * The provided parameters were invalid and ranging could not start
- */
- BAD_PARAMETERS,
-
- /**
- * The maximum number of sessions has been reached. This error may be generated
- * for an active session if a higher priority session begins.
- */
- MAX_SESSIONS_REACHED,
-
- /**
- * The system state has changed resulting in the session ending (e.g. the user
- * disables UWB, or the user's locale changes and an active channel is no longer
- * permitted to be used).
- */
- SYSTEM_POLICY,
-
- /**
- * The session could not start because of a protocol specific reason.
- */
- PROTOCOL_SPECIFIC,
-}
-
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index f4d801868e18..15ee5b5f22eb 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -369,13 +369,13 @@ public final class UwbManager {
/**
* Open a {@link RangingSession} with the given parameters
- * <p>This function is asynchronous and will return before ranging begins. The
- * {@link RangingSession.Callback#onOpenSuccess(RangingSession, PersistableBundle)} function is
- * called with a {@link RangingSession} object used to control ranging when the session is
- * successfully opened.
+ * <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.
*
- * <p>If a session cannot be opened, then {@link RangingSession.Callback#onClosed(int)} will be
- * invoked with the appropriate {@link RangingSession.Callback.CloseReason}.
+ * <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.
@@ -391,7 +391,7 @@ public final class UwbManager {
* @return an {@link AutoCloseable} that is able to be used to close or 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#onOpenSuccess}.
+ * {@link RangingSession.Callback#onOpened(RangingSession)}.
*/
@NonNull
public AutoCloseable openRangingSession(@NonNull PersistableBundle parameters,
diff --git a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
index 6df1c3ed220f..c01bb75c32aa 100644
--- a/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
+++ b/core/tests/uwbtests/src/android/uwb/RangingManagerTest.java
@@ -45,14 +45,14 @@ public class RangingManagerTest {
private static final IUwbAdapter ADAPTER = mock(IUwbAdapter.class);
private static final Executor EXECUTOR = UwbTestUtils.getExecutor();
private static final PersistableBundle PARAMS = new PersistableBundle();
- private static final @CloseReason int CLOSE_REASON = CloseReason.UNKNOWN;
+ private static final @RangingChangeReason int REASON = RangingChangeReason.UNKNOWN;
@Test
- public void testOpenSession_StartRangingInvoked() throws RemoteException {
+ public void testOpenSession_OpenRangingInvoked() throws RemoteException {
RangingManager rangingManager = new RangingManager(ADAPTER);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
rangingManager.openSession(PARAMS, EXECUTOR, callback);
- verify(ADAPTER, times(1)).startRanging(eq(rangingManager), eq(PARAMS));
+ verify(ADAPTER, times(1)).openRanging(eq(rangingManager), eq(PARAMS));
}
@Test
@@ -60,7 +60,7 @@ public class RangingManagerTest {
RangingManager rangingManager = new RangingManager(ADAPTER);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.startRanging(any(), any())).thenReturn(handle);
+ when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
rangingManager.openSession(PARAMS, EXECUTOR, callback);
@@ -73,34 +73,34 @@ public class RangingManagerTest {
}
@Test
- public void testOnRangingStarted_ValidSessionHandle() throws RemoteException {
+ public void testOnRangingOpened_ValidSessionHandle() throws RemoteException {
RangingManager rangingManager = new RangingManager(ADAPTER);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.startRanging(any(), any())).thenReturn(handle);
+ when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
rangingManager.openSession(PARAMS, EXECUTOR, callback);
- rangingManager.onRangingStarted(handle, PARAMS);
- verify(callback, times(1)).onOpenSuccess(any(), any());
+ rangingManager.onRangingOpened(handle);
+ verify(callback, times(1)).onOpened(any());
}
@Test
- public void testOnRangingStarted_InvalidSessionHandle() throws RemoteException {
+ public void testOnRangingOpened_InvalidSessionHandle() throws RemoteException {
RangingManager rangingManager = new RangingManager(ADAPTER);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- rangingManager.onRangingStarted(new SessionHandle(2), PARAMS);
- verify(callback, times(0)).onOpenSuccess(any(), any());
+ rangingManager.onRangingOpened(new SessionHandle(2));
+ verify(callback, times(0)).onOpened(any());
}
@Test
- public void testOnRangingStarted_MultipleSessionsRegistered() throws RemoteException {
+ public void testOnRangingOpened_MultipleSessionsRegistered() throws RemoteException {
SessionHandle sessionHandle1 = new SessionHandle(1);
SessionHandle sessionHandle2 = new SessionHandle(2);
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
- when(ADAPTER.startRanging(any(), any()))
+ when(ADAPTER.openRanging(any(), any()))
.thenReturn(sessionHandle1)
.thenReturn(sessionHandle2);
@@ -108,25 +108,50 @@ public class RangingManagerTest {
rangingManager.openSession(PARAMS, EXECUTOR, callback1);
rangingManager.openSession(PARAMS, EXECUTOR, callback2);
- rangingManager.onRangingStarted(sessionHandle1, PARAMS);
- verify(callback1, times(1)).onOpenSuccess(any(), any());
- verify(callback2, times(0)).onOpenSuccess(any(), any());
+ rangingManager.onRangingOpened(sessionHandle1);
+ verify(callback1, times(1)).onOpened(any());
+ verify(callback2, times(0)).onOpened(any());
- rangingManager.onRangingStarted(sessionHandle2, PARAMS);
- verify(callback1, times(1)).onOpenSuccess(any(), any());
- verify(callback2, times(1)).onOpenSuccess(any(), any());
+ rangingManager.onRangingOpened(sessionHandle2);
+ verify(callback1, times(1)).onOpened(any());
+ verify(callback2, times(1)).onOpened(any());
}
@Test
- public void testOnRangingClosed_OnRangingClosedCalled() throws RemoteException {
+ public void testCorrectCallbackInvoked() throws RemoteException {
RangingManager rangingManager = new RangingManager(ADAPTER);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.startRanging(any(), any())).thenReturn(handle);
+ when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
+
rangingManager.openSession(PARAMS, EXECUTOR, callback);
+ rangingManager.onRangingOpened(handle);
+ verify(callback, times(1)).onOpened(any());
+
+ rangingManager.onRangingStarted(handle, PARAMS);
+ verify(callback, times(1)).onStarted(eq(PARAMS));
+
+ rangingManager.onRangingStartFailed(handle, REASON, PARAMS);
+ verify(callback, times(1)).onStartFailed(eq(REASON), eq(PARAMS));
+
+ RangingReport report = UwbTestUtils.getRangingReports(1);
+ rangingManager.onRangingResult(handle, report);
+ verify(callback, times(1)).onReportReceived(eq(report));
- rangingManager.onRangingClosed(handle, CLOSE_REASON, PARAMS);
- verify(callback, times(1)).onClosed(anyInt(), any());
+ rangingManager.onRangingReconfigured(handle, PARAMS);
+ verify(callback, times(1)).onReconfigured(eq(PARAMS));
+
+ rangingManager.onRangingReconfigureFailed(handle, REASON, PARAMS);
+ verify(callback, times(1)).onReconfigureFailed(eq(REASON), eq(PARAMS));
+
+ rangingManager.onRangingStopped(handle);
+ verify(callback, times(1)).onStopped();
+
+ rangingManager.onRangingStopFailed(handle, REASON, PARAMS);
+ verify(callback, times(1)).onStopFailed(eq(REASON), eq(PARAMS));
+
+ rangingManager.onRangingClosed(handle, REASON, PARAMS);
+ verify(callback, times(1)).onClosed(eq(REASON), eq(PARAMS));
}
@Test
@@ -138,7 +163,7 @@ public class RangingManagerTest {
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
- when(ADAPTER.startRanging(any(), any()))
+ when(ADAPTER.openRanging(any(), any()))
.thenReturn(sessionHandle1)
.thenReturn(sessionHandle2);
@@ -146,37 +171,23 @@ public class RangingManagerTest {
rangingManager.openSession(PARAMS, EXECUTOR, callback1);
rangingManager.openSession(PARAMS, EXECUTOR, callback2);
- rangingManager.onRangingClosed(sessionHandle1, CLOSE_REASON, PARAMS);
+ rangingManager.onRangingClosed(sessionHandle1, REASON, PARAMS);
verify(callback1, times(1)).onClosed(anyInt(), any());
verify(callback2, times(0)).onClosed(anyInt(), any());
- rangingManager.onRangingClosed(sessionHandle2, CLOSE_REASON, PARAMS);
+ rangingManager.onRangingClosed(sessionHandle2, REASON, PARAMS);
verify(callback1, times(1)).onClosed(anyInt(), any());
verify(callback2, times(1)).onClosed(anyInt(), any());
}
@Test
- public void testOnRangingReport_OnReportReceived() throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.startRanging(any(), any())).thenReturn(handle);
- rangingManager.openSession(PARAMS, EXECUTOR, callback);
- rangingManager.onRangingStarted(handle, PARAMS);
-
- RangingReport report = UwbTestUtils.getRangingReports(1);
- rangingManager.onRangingResult(handle, report);
- verify(callback, times(1)).onReportReceived(eq(report));
- }
-
- @Test
public void testOnRangingReport_MultipleSessionsRegistered() throws RemoteException {
SessionHandle sessionHandle1 = new SessionHandle(1);
SessionHandle sessionHandle2 = new SessionHandle(2);
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
- when(ADAPTER.startRanging(any(), any()))
+ when(ADAPTER.openRanging(any(), any()))
.thenReturn(sessionHandle1)
.thenReturn(sessionHandle2);
@@ -196,65 +207,54 @@ public class RangingManagerTest {
}
@Test
- public void testOnClose_Reasons() throws RemoteException {
- runOnClose_Reason(CloseReason.LOCAL_API,
- RangingSession.Callback.CLOSE_REASON_LOCAL_CLOSE_API);
+ public void testReasons() throws RemoteException {
+ runReason(RangingChangeReason.LOCAL_API,
+ RangingSession.Callback.REASON_LOCAL_REQUEST);
+
+ runReason(RangingChangeReason.MAX_SESSIONS_REACHED,
+ RangingSession.Callback.REASON_MAX_SESSIONS_REACHED);
- runOnClose_Reason(CloseReason.MAX_SESSIONS_REACHED,
- RangingSession.Callback.CLOSE_REASON_LOCAL_MAX_SESSIONS_REACHED);
+ runReason(RangingChangeReason.PROTOCOL_SPECIFIC,
+ RangingSession.Callback.REASON_PROTOCOL_SPECIFIC_ERROR);
- runOnClose_Reason(CloseReason.PROTOCOL_SPECIFIC,
- RangingSession.Callback.CLOSE_REASON_PROTOCOL_SPECIFIC);
+ runReason(RangingChangeReason.REMOTE_REQUEST,
+ RangingSession.Callback.REASON_REMOTE_REQUEST);
- runOnClose_Reason(CloseReason.REMOTE_REQUEST,
- RangingSession.Callback.CLOSE_REASON_REMOTE_REQUEST);
+ runReason(RangingChangeReason.SYSTEM_POLICY,
+ RangingSession.Callback.REASON_SYSTEM_POLICY);
- runOnClose_Reason(CloseReason.SYSTEM_POLICY,
- RangingSession.Callback.CLOSE_REASON_LOCAL_SYSTEM_POLICY);
+ runReason(RangingChangeReason.BAD_PARAMETERS,
+ RangingSession.Callback.REASON_BAD_PARAMETERS);
- runOnClose_Reason(CloseReason.UNKNOWN,
- RangingSession.Callback.CLOSE_REASON_UNKNOWN);
+ runReason(RangingChangeReason.UNKNOWN,
+ RangingSession.Callback.REASON_UNKNOWN);
}
- private void runOnClose_Reason(@CloseReason int reasonIn,
- @RangingSession.Callback.CloseReason int reasonOut) throws RemoteException {
+ private void runReason(@RangingChangeReason int reasonIn,
+ @RangingSession.Callback.Reason int reasonOut) throws RemoteException {
RangingManager rangingManager = new RangingManager(ADAPTER);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.startRanging(any(), any())).thenReturn(handle);
+ when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
rangingManager.openSession(PARAMS, EXECUTOR, callback);
- rangingManager.onRangingClosed(handle, reasonIn, PARAMS);
- verify(callback, times(1)).onClosed(eq(reasonOut), eq(PARAMS));
- }
-
- @Test
- public void testStartFailureReasons() throws RemoteException {
- runOnRangingStartFailed_Reason(StartFailureReason.BAD_PARAMETERS,
- RangingSession.Callback.CLOSE_REASON_LOCAL_BAD_PARAMETERS);
+ rangingManager.onRangingOpenFailed(handle, reasonIn, PARAMS);
+ verify(callback, times(1)).onOpenFailed(eq(reasonOut), eq(PARAMS));
- runOnRangingStartFailed_Reason(StartFailureReason.MAX_SESSIONS_REACHED,
- RangingSession.Callback.CLOSE_REASON_LOCAL_MAX_SESSIONS_REACHED);
+ // Open a new session
+ rangingManager.openSession(PARAMS, EXECUTOR, callback);
+ rangingManager.onRangingOpened(handle);
- runOnRangingStartFailed_Reason(StartFailureReason.PROTOCOL_SPECIFIC,
- RangingSession.Callback.CLOSE_REASON_PROTOCOL_SPECIFIC);
+ rangingManager.onRangingStartFailed(handle, reasonIn, PARAMS);
+ verify(callback, times(1)).onStartFailed(eq(reasonOut), eq(PARAMS));
- runOnRangingStartFailed_Reason(StartFailureReason.SYSTEM_POLICY,
- RangingSession.Callback.CLOSE_REASON_LOCAL_SYSTEM_POLICY);
+ rangingManager.onRangingReconfigureFailed(handle, reasonIn, PARAMS);
+ verify(callback, times(1)).onReconfigureFailed(eq(reasonOut), eq(PARAMS));
- runOnRangingStartFailed_Reason(StartFailureReason.UNKNOWN,
- RangingSession.Callback.CLOSE_REASON_UNKNOWN);
- }
-
- private void runOnRangingStartFailed_Reason(@StartFailureReason int reasonIn,
- @RangingSession.Callback.CloseReason int reasonOut) throws RemoteException {
- RangingManager rangingManager = new RangingManager(ADAPTER);
- RangingSession.Callback callback = mock(RangingSession.Callback.class);
- SessionHandle handle = new SessionHandle(1);
- when(ADAPTER.startRanging(any(), any())).thenReturn(handle);
- rangingManager.openSession(PARAMS, EXECUTOR, callback);
+ rangingManager.onRangingStopFailed(handle, reasonIn, PARAMS);
+ verify(callback, times(1)).onStopFailed(eq(reasonOut), eq(PARAMS));
- rangingManager.onRangingStartFailed(handle, reasonIn, PARAMS);
+ rangingManager.onRangingClosed(handle, reasonIn, PARAMS);
verify(callback, times(1)).onClosed(eq(reasonOut), eq(PARAMS));
}
}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingSessionTest.java b/core/tests/uwbtests/src/android/uwb/RangingSessionTest.java
index 702c68ebc9de..e5eea26f5d11 100644
--- a/core/tests/uwbtests/src/android/uwb/RangingSessionTest.java
+++ b/core/tests/uwbtests/src/android/uwb/RangingSessionTest.java
@@ -19,9 +19,11 @@ package android.uwb;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -34,6 +36,8 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.util.concurrent.Executor;
@@ -43,47 +47,48 @@ import java.util.concurrent.Executor;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class RangingSessionTest {
- private static final IUwbAdapter ADAPTER = mock(IUwbAdapter.class);
private static final Executor EXECUTOR = UwbTestUtils.getExecutor();
private static final PersistableBundle PARAMS = new PersistableBundle();
- private static final @RangingSession.Callback.CloseReason int CLOSE_REASON =
- RangingSession.Callback.CLOSE_REASON_LOCAL_GENERIC_ERROR;
+ private static final @RangingSession.Callback.Reason int REASON =
+ RangingSession.Callback.REASON_GENERIC_ERROR;
@Test
- public void testOnRangingStarted_OnOpenSuccessCalled() {
+ public void testOnRangingOpened_OnOpenSuccessCalled() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, ADAPTER, handle);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
verifyOpenState(session, false);
- session.onRangingStarted(PARAMS);
+ session.onRangingOpened();
verifyOpenState(session, true);
// Verify that the onOpenSuccess callback was invoked
- verify(callback, times(1)).onOpenSuccess(eq(session), any());
+ verify(callback, times(1)).onOpened(eq(session));
verify(callback, times(0)).onClosed(anyInt(), any());
}
@Test
- public void testOnRangingStarted_CannotOpenClosedSession() {
+ public void testOnRangingOpened_CannotOpenClosedSession() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, ADAPTER, handle);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
- session.onRangingStarted(PARAMS);
+ session.onRangingOpened();
verifyOpenState(session, true);
- verify(callback, times(1)).onOpenSuccess(eq(session), any());
+ verify(callback, times(1)).onOpened(eq(session));
verify(callback, times(0)).onClosed(anyInt(), any());
- session.onRangingClosed(CLOSE_REASON, PARAMS);
+ session.onRangingClosed(REASON, PARAMS);
verifyOpenState(session, false);
- verify(callback, times(1)).onOpenSuccess(eq(session), any());
+ verify(callback, times(1)).onOpened(eq(session));
verify(callback, times(1)).onClosed(anyInt(), any());
// Now invoke the ranging started callback and ensure the session remains closed
- session.onRangingStarted(PARAMS);
+ session.onRangingOpened();
verifyOpenState(session, false);
- verify(callback, times(1)).onOpenSuccess(eq(session), any());
+ verify(callback, times(1)).onOpened(eq(session));
verify(callback, times(1)).onClosed(anyInt(), any());
}
@@ -91,27 +96,30 @@ public class RangingSessionTest {
public void testOnRangingClosed_OnClosedCalledWhenSessionNotOpen() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, ADAPTER, handle);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
verifyOpenState(session, false);
- session.onRangingClosed(CLOSE_REASON, PARAMS);
+ session.onRangingClosed(REASON, PARAMS);
verifyOpenState(session, false);
// Verify that the onOpenSuccess callback was invoked
- verify(callback, times(0)).onOpenSuccess(eq(session), any());
+ verify(callback, times(0)).onOpened(eq(session));
verify(callback, times(1)).onClosed(anyInt(), any());
}
- @Test public void testOnRangingClosed_OnClosedCalled() {
+ @Test
+ public void testOnRangingClosed_OnClosedCalled() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, ADAPTER, handle);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
session.onRangingStarted(PARAMS);
- session.onRangingClosed(CLOSE_REASON, PARAMS);
+ session.onRangingClosed(REASON, PARAMS);
verify(callback, times(1)).onClosed(anyInt(), any());
verifyOpenState(session, false);
- session.onRangingClosed(CLOSE_REASON, PARAMS);
+ session.onRangingClosed(REASON, PARAMS);
verify(callback, times(2)).onClosed(anyInt(), any());
}
@@ -119,7 +127,8 @@ public class RangingSessionTest {
public void testOnRangingResult_OnReportReceivedCalled() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, ADAPTER, handle);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
verifyOpenState(session, false);
session.onRangingStarted(PARAMS);
@@ -131,11 +140,83 @@ public class RangingSessionTest {
}
@Test
- public void testClose() throws RemoteException {
+ public void testStart_CannotStartIfAlreadyStarted() throws RemoteException {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, ADAPTER, handle);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
+ doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
+ session.onRangingOpened();
+
+ session.start(PARAMS);
+ verify(callback, times(1)).onStarted(any());
+
+ // Calling start again should throw an illegal state
+ verifyThrowIllegalState(() -> session.start(PARAMS));
+ verify(callback, times(1)).onStarted(any());
+ }
+
+ @Test
+ public void testStop_CannotStopIfAlreadyStopped() throws RemoteException {
+ SessionHandle handle = new SessionHandle(123);
+ RangingSession.Callback callback = mock(RangingSession.Callback.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
+ doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
+ doAnswer(new StopAnswer(session)).when(adapter).stopRanging(any());
+ session.onRangingOpened();
+ session.start(PARAMS);
+
+ verifyNoThrowIllegalState(session::stop);
+ verify(callback, times(1)).onStopped();
+
+ // Calling stop again should throw an illegal state
+ verifyThrowIllegalState(session::stop);
+ verify(callback, times(1)).onStopped();
+ }
+
+ @Test
+ public void testReconfigure_OnlyWhenOpened() throws RemoteException {
+ SessionHandle handle = new SessionHandle(123);
+ RangingSession.Callback callback = mock(RangingSession.Callback.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
+ doAnswer(new StartAnswer(session)).when(adapter).startRanging(any(), any());
+ doAnswer(new ReconfigureAnswer(session)).when(adapter).reconfigureRanging(any(), any());
+
+ verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
+ verify(callback, times(0)).onReconfigured(any());
+ verifyOpenState(session, false);
+
+ session.onRangingOpened();
+ verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
+ verify(callback, times(1)).onReconfigured(any());
+ verifyOpenState(session, true);
+
session.onRangingStarted(PARAMS);
+ verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
+ verify(callback, times(2)).onReconfigured(any());
+ verifyOpenState(session, true);
+
+ session.onRangingStopped();
+ verifyNoThrowIllegalState(() -> session.reconfigure(PARAMS));
+ verify(callback, times(3)).onReconfigured(any());
+ verifyOpenState(session, true);
+
+
+ session.onRangingClosed(REASON, PARAMS);
+ verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
+ verify(callback, times(3)).onReconfigured(any());
+ verifyOpenState(session, false);
+ }
+
+ @Test
+ public void testClose_NoCallbackUntilInvoked() throws RemoteException {
+ SessionHandle handle = new SessionHandle(123);
+ RangingSession.Callback callback = mock(RangingSession.Callback.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
+ session.onRangingOpened();
// Calling close multiple times should invoke closeRanging until the session receives
// the onClosed callback.
@@ -143,7 +224,7 @@ public class RangingSessionTest {
for (int i = 1; i <= totalCallsBeforeOnRangingClosed; i++) {
session.close();
verifyOpenState(session, true);
- verify(ADAPTER, times(i)).closeRanging(handle);
+ verify(adapter, times(i)).closeRanging(handle);
verify(callback, times(0)).onClosed(anyInt(), any());
}
@@ -151,18 +232,47 @@ public class RangingSessionTest {
// the session's close.
final int totalCallsAfterOnRangingClosed = 2;
for (int i = 1; i <= totalCallsAfterOnRangingClosed; i++) {
- session.onRangingClosed(CLOSE_REASON, PARAMS);
+ session.onRangingClosed(REASON, PARAMS);
verifyOpenState(session, false);
- verify(ADAPTER, times(totalCallsBeforeOnRangingClosed)).closeRanging(handle);
+ verify(adapter, times(totalCallsBeforeOnRangingClosed)).closeRanging(handle);
verify(callback, times(i)).onClosed(anyInt(), any());
}
}
@Test
+ public void testClose_OnClosedCalled() throws RemoteException {
+ SessionHandle handle = new SessionHandle(123);
+ RangingSession.Callback callback = mock(RangingSession.Callback.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
+ doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
+ session.onRangingOpened();
+
+ session.close();
+ verify(callback, times(1)).onClosed(anyInt(), any());
+ }
+
+ @Test
+ public void testClose_CannotInteractFurther() throws RemoteException {
+ SessionHandle handle = new SessionHandle(123);
+ RangingSession.Callback callback = mock(RangingSession.Callback.class);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
+ doAnswer(new CloseAnswer(session)).when(adapter).closeRanging(any());
+ session.close();
+
+ verifyThrowIllegalState(() -> session.start(PARAMS));
+ verifyThrowIllegalState(() -> session.reconfigure(PARAMS));
+ verifyThrowIllegalState(() -> session.stop());
+ verifyNoThrowIllegalState(() -> session.close());
+ }
+
+ @Test
public void testOnRangingResult_OnReportReceivedCalledWhenOpen() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, ADAPTER, handle);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
assertFalse(session.isOpen());
session.onRangingStarted(PARAMS);
@@ -178,7 +288,8 @@ public class RangingSessionTest {
public void testOnRangingResult_OnReportReceivedNotCalledWhenNotOpen() {
SessionHandle handle = new SessionHandle(123);
RangingSession.Callback callback = mock(RangingSession.Callback.class);
- RangingSession session = new RangingSession(EXECUTOR, callback, ADAPTER, handle);
+ IUwbAdapter adapter = mock(IUwbAdapter.class);
+ RangingSession session = new RangingSession(EXECUTOR, callback, adapter, handle);
assertFalse(session.isOpen());
@@ -191,4 +302,77 @@ public class RangingSessionTest {
private void verifyOpenState(RangingSession session, boolean expected) {
assertEquals(expected, session.isOpen());
}
+
+ private void verifyThrowIllegalState(Runnable runnable) {
+ try {
+ runnable.run();
+ fail();
+ } catch (IllegalStateException e) {
+ // Pass
+ }
+ }
+
+ private void verifyNoThrowIllegalState(Runnable runnable) {
+ try {
+ runnable.run();
+ } catch (IllegalStateException e) {
+ fail();
+ }
+ }
+
+ abstract class AdapterAnswer implements Answer {
+ protected RangingSession mSession;
+
+ protected AdapterAnswer(RangingSession session) {
+ mSession = session;
+ }
+ }
+
+ class StartAnswer extends AdapterAnswer {
+ StartAnswer(RangingSession session) {
+ super(session);
+ }
+
+ @Override
+ public Object answer(InvocationOnMock invocation) {
+ mSession.onRangingStarted(PARAMS);
+ return null;
+ }
+ }
+
+ class ReconfigureAnswer extends AdapterAnswer {
+ ReconfigureAnswer(RangingSession session) {
+ super(session);
+ }
+
+ @Override
+ public Object answer(InvocationOnMock invocation) {
+ mSession.onRangingReconfigured(PARAMS);
+ return null;
+ }
+ }
+
+ class StopAnswer extends AdapterAnswer {
+ StopAnswer(RangingSession session) {
+ super(session);
+ }
+
+ @Override
+ public Object answer(InvocationOnMock invocation) {
+ mSession.onRangingStopped();
+ return null;
+ }
+ }
+
+ class CloseAnswer extends AdapterAnswer {
+ CloseAnswer(RangingSession session) {
+ super(session);
+ }
+
+ @Override
+ public Object answer(InvocationOnMock invocation) {
+ mSession.onRangingClosed(REASON, PARAMS);
+ return null;
+ }
+ }
}