Merge "Add control functions to RangingSession" am: 022ba65d34 am: 641a52f952

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1532667

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ic545a34484140a9e90b6d14c3208769c6c351883
This commit is contained in:
Treehugger Robot
2021-01-08 22:20:02 +00:00
committed by Automerger Merge Worker
9 changed files with 882 additions and 329 deletions

View File

@@ -119,41 +119,95 @@ 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);
/**
* Stop and close ranging for the session associated with the given handle
* 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);
/**
* 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.
*/

View File

@@ -17,15 +17,32 @@
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
*
@@ -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);
/**

View File

@@ -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,
}

View File

@@ -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()));
}
@@ -74,6 +74,67 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
return mRangingSessionTable.containsKey(sessionHandle);
}
@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) {
@@ -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 onRangingClosed(SessionHandle sessionHandle, int reason, PersistableBundle params) {
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 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 RangingChangeReason.LOCAL_API:
return RangingSession.Callback.REASON_LOCAL_REQUEST;
case CloseReason.MAX_SESSIONS_REACHED:
return RangingSession.Callback.CLOSE_REASON_LOCAL_MAX_SESSIONS_REACHED;
case RangingChangeReason.MAX_SESSIONS_REACHED:
return RangingSession.Callback.REASON_MAX_SESSIONS_REACHED;
case CloseReason.SYSTEM_POLICY:
return RangingSession.Callback.CLOSE_REASON_LOCAL_SYSTEM_POLICY;
case RangingChangeReason.SYSTEM_POLICY:
return RangingSession.Callback.REASON_SYSTEM_POLICY;
case CloseReason.REMOTE_REQUEST:
return RangingSession.Callback.CLOSE_REASON_REMOTE_REQUEST;
case RangingChangeReason.REMOTE_REQUEST:
return RangingSession.Callback.REASON_REMOTE_REQUEST;
case CloseReason.PROTOCOL_SPECIFIC:
return RangingSession.Callback.CLOSE_REASON_PROTOCOL_SPECIFIC;
case RangingChangeReason.PROTOCOL_SPECIFIC:
return RangingSession.Callback.REASON_PROTOCOL_SPECIFIC_ERROR;
case CloseReason.UNKNOWN:
case RangingChangeReason.BAD_PARAMETERS:
return RangingSession.Callback.REASON_BAD_PARAMETERS;
case RangingChangeReason.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 StartFailureReason.MAX_SESSIONS_REACHED:
return RangingSession.Callback.CLOSE_REASON_LOCAL_MAX_SESSIONS_REACHED;
case StartFailureReason.SYSTEM_POLICY:
return RangingSession.Callback.CLOSE_REASON_LOCAL_SYSTEM_POLICY;
case StartFailureReason.PROTOCOL_SPECIFIC:
return RangingSession.Callback.CLOSE_REASON_PROTOCOL_SPECIFIC;
case StartFailureReason.UNKNOWN:
default:
return RangingSession.Callback.CLOSE_REASON_UNKNOWN;
return RangingSession.Callback.REASON_UNKNOWN;
}
}
}

View File

@@ -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;
/**
* Indicates that the session failed to open due to erroneous parameters passed
* to {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}
*/
int CLOSE_REASON_LOCAL_BAD_PARAMETERS = 2;
/**
* Indicates that the session was closed due to some local error on this device besides the
* error code already listed
*/
int CLOSE_REASON_LOCAL_GENERIC_ERROR = 3;
/**
* Indicates that the session failed to open because the number of currently open sessions
* is equal to {@link UwbManager#getMaxSimultaneousSessions()}
*/
int CLOSE_REASON_LOCAL_MAX_SESSIONS_REACHED = 4;
/**
* Indicates that the session was closed or failed to open due to local system policy, such
* as privacy policy, power management policy, permissions, and more.
*/
int CLOSE_REASON_LOCAL_SYSTEM_POLICY = 5;
/**
* Indicates that the session was closed or failed to open due to an error with the remote
* device besides error codes already listed.
*/
int CLOSE_REASON_REMOTE_GENERIC_ERROR = 6;
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 CLOSE_REASON_REMOTE_REQUEST = 7;
int REASON_REMOTE_REQUEST = 2;
/**
* Indicates that the session was closed for a protocol specific reason. The associated
* {@link PersistableBundle} should be consulted for additional information.
* Indicates that the session was closed or failed to open due to erroneous parameters
*/
int CLOSE_REASON_PROTOCOL_SPECIFIC = 8;
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 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 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;
/**
* 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
*/
void onReconfigureFailed(@Reason int reason, @NonNull PersistableBundle params);
/**
* Invoked when a request to stop the session succeeds
*/
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;
}
@@ -203,6 +345,33 @@ 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
*/
@@ -212,26 +381,81 @@ public final class RangingSession implements AutoCloseable {
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 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 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 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);
}

View File

@@ -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,
}

View File

@@ -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,

View File

@@ -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);
rangingManager.openSession(PARAMS, EXECUTOR, callback);
when(ADAPTER.openRanging(any(), any())).thenReturn(handle);
rangingManager.onRangingClosed(handle, CLOSE_REASON, PARAMS);
verify(callback, times(1)).onClosed(anyInt(), any());
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.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,29 +171,15 @@ 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);
@@ -176,7 +187,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);
@@ -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);
runOnClose_Reason(CloseReason.MAX_SESSIONS_REACHED,
RangingSession.Callback.CLOSE_REASON_LOCAL_MAX_SESSIONS_REACHED);
runReason(RangingChangeReason.MAX_SESSIONS_REACHED,
RangingSession.Callback.REASON_MAX_SESSIONS_REACHED);
runOnClose_Reason(CloseReason.PROTOCOL_SPECIFIC,
RangingSession.Callback.CLOSE_REASON_PROTOCOL_SPECIFIC);
runReason(RangingChangeReason.PROTOCOL_SPECIFIC,
RangingSession.Callback.REASON_PROTOCOL_SPECIFIC_ERROR);
runOnClose_Reason(CloseReason.REMOTE_REQUEST,
RangingSession.Callback.CLOSE_REASON_REMOTE_REQUEST);
runReason(RangingChangeReason.REMOTE_REQUEST,
RangingSession.Callback.REASON_REMOTE_REQUEST);
runOnClose_Reason(CloseReason.SYSTEM_POLICY,
RangingSession.Callback.CLOSE_REASON_LOCAL_SYSTEM_POLICY);
runReason(RangingChangeReason.SYSTEM_POLICY,
RangingSession.Callback.REASON_SYSTEM_POLICY);
runOnClose_Reason(CloseReason.UNKNOWN,
RangingSession.Callback.CLOSE_REASON_UNKNOWN);
runReason(RangingChangeReason.BAD_PARAMETERS,
RangingSession.Callback.REASON_BAD_PARAMETERS);
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.onRangingOpenFailed(handle, reasonIn, PARAMS);
verify(callback, times(1)).onOpenFailed(eq(reasonOut), eq(PARAMS));
// Open a new session
rangingManager.openSession(PARAMS, EXECUTOR, callback);
rangingManager.onRangingOpened(handle);
rangingManager.onRangingStartFailed(handle, reasonIn, PARAMS);
verify(callback, times(1)).onStartFailed(eq(reasonOut), eq(PARAMS));
rangingManager.onRangingReconfigureFailed(handle, reasonIn, PARAMS);
verify(callback, times(1)).onReconfigureFailed(eq(reasonOut), eq(PARAMS));
rangingManager.onRangingStopFailed(handle, reasonIn, PARAMS);
verify(callback, times(1)).onStopFailed(eq(reasonOut), eq(PARAMS));
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);
runOnRangingStartFailed_Reason(StartFailureReason.MAX_SESSIONS_REACHED,
RangingSession.Callback.CLOSE_REASON_LOCAL_MAX_SESSIONS_REACHED);
runOnRangingStartFailed_Reason(StartFailureReason.PROTOCOL_SPECIFIC,
RangingSession.Callback.CLOSE_REASON_PROTOCOL_SPECIFIC);
runOnRangingStartFailed_Reason(StartFailureReason.SYSTEM_POLICY,
RangingSession.Callback.CLOSE_REASON_LOCAL_SYSTEM_POLICY);
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.onRangingStartFailed(handle, reasonIn, PARAMS);
verify(callback, times(1)).onClosed(eq(reasonOut), eq(PARAMS));
}
}

View File

@@ -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;
}
}
}