diff --git a/core/java/android/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java index 7ef145cfe470e..c3e2ecc9e0f31 100644 --- a/core/java/android/uwb/AngleMeasurement.java +++ b/core/java/android/uwb/AngleMeasurement.java @@ -27,6 +27,16 @@ import android.annotation.FloatRange; * @hide */ public final class AngleMeasurement { + private final double mRadians; + private final double mErrorRadians; + private final double mConfidenceLevel; + + private AngleMeasurement(double radians, double errorRadians, double confidenceLevel) { + mRadians = radians; + mErrorRadians = errorRadians; + mConfidenceLevel = confidenceLevel; + } + /** * Angle measurement in radians * @@ -34,7 +44,7 @@ public final class AngleMeasurement { */ @FloatRange(from = -Math.PI, to = +Math.PI) public double getRadians() { - throw new UnsupportedOperationException(); + return mRadians; } /** @@ -46,7 +56,7 @@ public final class AngleMeasurement { */ @FloatRange(from = 0.0, to = +Math.PI) public double getErrorRadians() { - throw new UnsupportedOperationException(); + return mErrorRadians; } /** @@ -60,6 +70,80 @@ public final class AngleMeasurement { */ @FloatRange(from = 0.0, to = 1.0) public double getConfidenceLevel() { - throw new UnsupportedOperationException(); + return mConfidenceLevel; + } + + /** + * Builder class for {@link AngleMeasurement}. + */ + public static final class Builder { + private double mRadians = Double.NaN; + private double mErrorRadians = Double.NaN; + private double mConfidenceLevel = Double.NaN; + + /** + * Set the angle in radians + * + * @param radians angle in radians + * @throws IllegalArgumentException if angle exceeds allowed limits of [-Math.PI, +Math.PI] + */ + public Builder setRadians(double radians) { + if (radians < -Math.PI || radians > Math.PI) { + throw new IllegalArgumentException("Invalid radians: " + radians); + } + mRadians = radians; + return this; + } + + /** + * Set the angle error in radians + * + * @param errorRadians error of the angle in radians + * @throws IllegalArgumentException if the error exceeds the allowed limits of [0, +Math.PI] + */ + public Builder setErrorRadians(double errorRadians) { + if (errorRadians < 0.0 || errorRadians > Math.PI) { + throw new IllegalArgumentException( + "Invalid error radians: " + errorRadians); + } + mErrorRadians = errorRadians; + return this; + } + + /** + * Set the angle confidence level + * + * @param confidenceLevel level of confidence of the angle measurement + * @throws IllegalArgumentException if the error exceeds the allowed limits of [0.0, 1.0] + */ + public Builder setConfidenceLevel(double confidenceLevel) { + if (confidenceLevel < 0.0 || confidenceLevel > 1.0) { + throw new IllegalArgumentException( + "Invalid confidence level: " + confidenceLevel); + } + mConfidenceLevel = confidenceLevel; + return this; + } + + /** + * Build the {@link AngleMeasurement} object + * + * @throws IllegalStateException if angle, error, or confidence values are missing + */ + public AngleMeasurement build() { + if (Double.isNaN(mRadians)) { + throw new IllegalStateException("Angle is not set"); + } + + if (Double.isNaN(mErrorRadians)) { + throw new IllegalStateException("Angle error is not set"); + } + + if (Double.isNaN(mConfidenceLevel)) { + throw new IllegalStateException("Angle confidence level is not set"); + } + + return new AngleMeasurement(mRadians, mErrorRadians, mConfidenceLevel); + } } } diff --git a/core/java/android/uwb/AngleOfArrivalMeasurement.java b/core/java/android/uwb/AngleOfArrivalMeasurement.java index 030d5299d53b1..a7b5eae728cbf 100644 --- a/core/java/android/uwb/AngleOfArrivalMeasurement.java +++ b/core/java/android/uwb/AngleOfArrivalMeasurement.java @@ -25,6 +25,15 @@ import android.annotation.Nullable; * @hide */ public final class AngleOfArrivalMeasurement { + private final AngleMeasurement mAzimuthAngleMeasurement; + private final AngleMeasurement mAltitudeAngleMeasurement; + + private AngleOfArrivalMeasurement(@NonNull AngleMeasurement azimuthAngleMeasurement, + @Nullable AngleMeasurement altitudeAngleMeasurement) { + mAzimuthAngleMeasurement = azimuthAngleMeasurement; + mAltitudeAngleMeasurement = altitudeAngleMeasurement; + } + /** * Azimuth angle measurement *
Azimuth {@link AngleMeasurement} of remote device in horizontal coordinate system, this is
@@ -41,7 +50,7 @@ public final class AngleOfArrivalMeasurement {
*/
@NonNull
public AngleMeasurement getAzimuth() {
- throw new UnsupportedOperationException();
+ return mAzimuthAngleMeasurement;
}
/**
@@ -58,6 +67,48 @@ public final class AngleOfArrivalMeasurement {
*/
@Nullable
public AngleMeasurement getAltitude() {
- throw new UnsupportedOperationException();
+ return mAltitudeAngleMeasurement;
+ }
+
+ /**
+ * Builder class for {@link AngleOfArrivalMeasurement}.
+ */
+ public static final class Builder {
+ private AngleMeasurement mAzimuthAngleMeasurement = null;
+ private AngleMeasurement mAltitudeAngleMeasurement = null;
+
+ /**
+ * Set the azimuth angle
+ *
+ * @param azimuthAngle azimuth angle
+ */
+ public Builder setAzimuthAngleMeasurement(@NonNull AngleMeasurement azimuthAngle) {
+ mAzimuthAngleMeasurement = azimuthAngle;
+ return this;
+ }
+
+ /**
+ * Set the altitude angle
+ *
+ * @param altitudeAngle altitude angle
+ */
+ public Builder setAltitudeAngleMeasurement(@NonNull AngleMeasurement altitudeAngle) {
+ mAltitudeAngleMeasurement = altitudeAngle;
+ return this;
+ }
+
+ /**
+ * Build the {@link AngleOfArrivalMeasurement} object
+ *
+ * @throws IllegalStateException if the required azimuth angle is not provided
+ */
+ public AngleOfArrivalMeasurement build() {
+ if (mAzimuthAngleMeasurement == null) {
+ throw new IllegalStateException("Azimuth angle measurement is not set");
+ }
+
+ return new AngleOfArrivalMeasurement(mAzimuthAngleMeasurement,
+ mAltitudeAngleMeasurement);
+ }
}
}
diff --git a/core/java/android/uwb/DistanceMeasurement.java b/core/java/android/uwb/DistanceMeasurement.java
index f4e6d3ed644b8..4cd5d83f4efc7 100644
--- a/core/java/android/uwb/DistanceMeasurement.java
+++ b/core/java/android/uwb/DistanceMeasurement.java
@@ -27,13 +27,23 @@ import android.annotation.FloatRange;
* @hide
*/
public final class DistanceMeasurement {
+ private final double mMeters;
+ private final double mErrorMeters;
+ private final double mConfidenceLevel;
+
+ private DistanceMeasurement(double meters, double errorMeters, double confidenceLevel) {
+ mMeters = meters;
+ mErrorMeters = errorMeters;
+ mConfidenceLevel = confidenceLevel;
+ }
+
/**
* Distance measurement in meters
*
* @return distance in meters
*/
public double getMeters() {
- throw new UnsupportedOperationException();
+ return mMeters;
}
/**
@@ -43,7 +53,7 @@ public final class DistanceMeasurement {
* @return error of distance measurement in meters
*/
public double getErrorMeters() {
- throw new UnsupportedOperationException();
+ return mErrorMeters;
}
/**
@@ -56,6 +66,80 @@ public final class DistanceMeasurement {
*/
@FloatRange(from = 0.0, to = 1.0)
public double getConfidenceLevel() {
- throw new UnsupportedOperationException();
+ return mConfidenceLevel;
+ }
+
+ /**
+ * Builder to get a {@link DistanceMeasurement} object.
+ */
+ public static final class Builder {
+ private double mMeters = Double.NaN;
+ private double mErrorMeters = Double.NaN;
+ private double mConfidenceLevel = Double.NaN;
+
+ /**
+ * Set the distance measurement in meters
+ *
+ * @param meters distance in meters
+ * @throws IllegalArgumentException if meters is NaN
+ */
+ public Builder setMeters(double meters) {
+ if (Double.isNaN(meters)) {
+ throw new IllegalArgumentException("meters cannot be NaN");
+ }
+ mMeters = meters;
+ return this;
+ }
+
+ /**
+ * Set the distance error in meters
+ *
+ * @param errorMeters distance error in meters
+ * @throws IllegalArgumentException if error is negative or NaN
+ */
+ public Builder setErrorMeters(double errorMeters) {
+ if (Double.isNaN(errorMeters) || errorMeters < 0.0) {
+ throw new IllegalArgumentException(
+ "errorMeters must be >= 0.0 and not NaN: " + errorMeters);
+ }
+ mErrorMeters = errorMeters;
+ return this;
+ }
+
+ /**
+ * Set the confidence level
+ *
+ * @param confidenceLevel the confidence level in the distance measurement
+ * @throws IllegalArgumentException if confidence level is not in the range of [0.0, 1.0]
+ */
+ public Builder setConfidenceLevel(double confidenceLevel) {
+ if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
+ throw new IllegalArgumentException(
+ "confidenceLevel must be in the range [0.0, 1.0]: " + confidenceLevel);
+ }
+ mConfidenceLevel = confidenceLevel;
+ return this;
+ }
+
+ /**
+ * Builds the {@link DistanceMeasurement} object
+ *
+ * @throws IllegalStateException if meters, error, or confidence are not set
+ */
+ public DistanceMeasurement build() {
+ if (Double.isNaN(mMeters)) {
+ throw new IllegalStateException("Meters cannot be NaN");
+ }
+
+ if (Double.isNaN(mErrorMeters)) {
+ throw new IllegalStateException("Error meters cannot be NaN");
+ }
+
+ if (Double.isNaN(mConfidenceLevel)) {
+ throw new IllegalStateException("Confidence level cannot be NaN");
+ }
+
+ return new DistanceMeasurement(mMeters, mErrorMeters, mConfidenceLevel);
+ }
}
}
diff --git a/core/java/android/uwb/RangingMeasurement.java b/core/java/android/uwb/RangingMeasurement.java
index a249802366e08..33a34e3954c2a 100644
--- a/core/java/android/uwb/RangingMeasurement.java
+++ b/core/java/android/uwb/RangingMeasurement.java
@@ -31,6 +31,22 @@ import java.lang.annotation.RetentionPolicy;
* @hide
*/
public final class RangingMeasurement {
+ private final UwbAddress mRemoteDeviceAddress;
+ private final @Status int mStatus;
+ private final long mElapsedRealtimeNanos;
+ private final DistanceMeasurement mDistanceMeasurement;
+ private final AngleOfArrivalMeasurement mAngleOfArrivalMeasurement;
+
+ private RangingMeasurement(@NonNull UwbAddress remoteDeviceAddress, @Status int status,
+ long elapsedRealtimeNanos, @Nullable DistanceMeasurement distanceMeasurement,
+ @Nullable AngleOfArrivalMeasurement angleOfArrivalMeasurement) {
+ mRemoteDeviceAddress = remoteDeviceAddress;
+ mStatus = status;
+ mElapsedRealtimeNanos = elapsedRealtimeNanos;
+ mDistanceMeasurement = distanceMeasurement;
+ mAngleOfArrivalMeasurement = angleOfArrivalMeasurement;
+ }
+
/**
* Get the remote device's {@link UwbAddress}
*
@@ -38,7 +54,7 @@ public final class RangingMeasurement {
*/
@NonNull
public UwbAddress getRemoteDeviceAddress() {
- throw new UnsupportedOperationException();
+ return mRemoteDeviceAddress;
}
@Retention(RetentionPolicy.SOURCE)
@@ -75,7 +91,7 @@ public final class RangingMeasurement {
*/
@Status
public int getStatus() {
- throw new UnsupportedOperationException();
+ return mStatus;
}
/**
@@ -86,7 +102,7 @@ public final class RangingMeasurement {
*/
@SuppressLint("MethodNameUnits")
public long getElapsedRealtimeNanos() {
- throw new UnsupportedOperationException();
+ return mElapsedRealtimeNanos;
}
/**
@@ -97,7 +113,7 @@ public final class RangingMeasurement {
*/
@Nullable
public DistanceMeasurement getDistance() {
- throw new UnsupportedOperationException();
+ return mDistanceMeasurement;
}
/**
@@ -108,6 +124,106 @@ public final class RangingMeasurement {
*/
@Nullable
public AngleOfArrivalMeasurement getAngleOfArrival() {
- throw new UnsupportedOperationException();
+ return mAngleOfArrivalMeasurement;
+ }
+
+ /**
+ * Builder for a {@link RangingMeasurement} object.
+ */
+ public static final class Builder {
+ private UwbAddress mRemoteDeviceAddress = null;
+ private @Status int mStatus = RANGING_STATUS_FAILURE_UNKNOWN_ERROR;
+ private long mElapsedRealtimeNanos = -1L;
+ private DistanceMeasurement mDistanceMeasurement = null;
+ private AngleOfArrivalMeasurement mAngleOfArrivalMeasurement = null;
+
+ /**
+ * Set the remote device address that this measurement is for
+ *
+ * @param remoteDeviceAddress remote device's address
+ */
+ public Builder setRemoteDeviceAddress(@NonNull UwbAddress remoteDeviceAddress) {
+ mRemoteDeviceAddress = remoteDeviceAddress;
+ return this;
+ }
+
+ /**
+ * Set the status of ranging measurement
+ *
+ * @param status the status of the ranging measurement
+ */
+ public Builder setStatus(@Status int status) {
+ mStatus = status;
+ return this;
+ }
+
+ /**
+ * Set the elapsed realtime in nanoseconds when the ranging measurement occurred
+ *
+ * @param elapsedRealtimeNanos time the ranging measurement occurred
+ */
+ public Builder setElapsedRealtimeNanos(long elapsedRealtimeNanos) {
+ if (elapsedRealtimeNanos < 0) {
+ throw new IllegalArgumentException("elapsedRealtimeNanos must be >= 0");
+ }
+ mElapsedRealtimeNanos = elapsedRealtimeNanos;
+ return this;
+ }
+
+ /**
+ * Set the {@link DistanceMeasurement}
+ *
+ * @param distanceMeasurement the distance measurement for this ranging measurement
+ */
+ public Builder setDistanceMeasurement(@NonNull DistanceMeasurement distanceMeasurement) {
+ mDistanceMeasurement = distanceMeasurement;
+ return this;
+ }
+
+ /**
+ * Set the {@link AngleOfArrivalMeasurement}
+ *
+ * @param angleOfArrivalMeasurement the angle of arrival measurement for this ranging
+ * measurement
+ */
+ public Builder setAngleOfArrivalMeasurement(
+ @NonNull AngleOfArrivalMeasurement angleOfArrivalMeasurement) {
+ mAngleOfArrivalMeasurement = angleOfArrivalMeasurement;
+ return this;
+ }
+
+ /**
+ * Build the {@link RangingMeasurement} object
+ *
+ * @throws IllegalStateException if a distance or angle of arrival measurement is provided
+ * but the measurement was not successful, if the
+ * elapsedRealtimeNanos of the measurement is invalid, or
+ * if no remote device address is set
+ */
+ public RangingMeasurement build() {
+ if (mStatus != RANGING_STATUS_SUCCESS) {
+ if (mDistanceMeasurement != null) {
+ throw new IllegalStateException(
+ "Distance Measurement must be null if ranging is not successful");
+ }
+
+ if (mAngleOfArrivalMeasurement != null) {
+ throw new IllegalStateException(
+ "Angle of Arrival must be null if ranging is not successful");
+ }
+ }
+
+ if (mRemoteDeviceAddress == null) {
+ throw new IllegalStateException("No remote device address was set");
+ }
+
+ if (mElapsedRealtimeNanos < 0) {
+ throw new IllegalStateException(
+ "elapsedRealtimeNanos must be >=0: " + mElapsedRealtimeNanos);
+ }
+
+ return new RangingMeasurement(mRemoteDeviceAddress, mStatus, mElapsedRealtimeNanos,
+ mDistanceMeasurement, mAngleOfArrivalMeasurement);
+ }
}
}
diff --git a/core/java/android/uwb/RangingParams.java b/core/java/android/uwb/RangingParams.java
index 9727696f03911..a50de3e614256 100644
--- a/core/java/android/uwb/RangingParams.java
+++ b/core/java/android/uwb/RangingParams.java
@@ -24,7 +24,11 @@ import android.util.Duration;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* An object used when requesting to open a new {@link RangingSession}.
@@ -33,11 +37,33 @@ import java.util.List;
* @hide
*/
public final class RangingParams {
- /**
- * Standard builder interface as the class is not modifiable
- */
- public static class Builder {
- // TODO implement
+ private final boolean mIsInitiator;
+ private final boolean mIsController;
+ private final Duration mSamplePeriod;
+ private final UwbAddress mLocalDeviceAddress;
+ private final List Android reserves the '^android.*' namespace
*
- * @return a {@link PersistableBundle} of protocol specific parameters
+ * @return a {@link PersistableBundle} copy of protocol specific parameters
*/
public @Nullable PersistableBundle getSpecificationParameters() {
- throw new UnsupportedOperationException();
+ return new PersistableBundle(mSpecificationParameters);
+ }
+
+ /**
+ * Builder class for {@link RangingParams}.
+ */
+ public static final class Builder {
+ private boolean mIsInitiator = false;
+ private boolean mIsController = false;
+ private Duration mSamplePeriod = null;
+ private UwbAddress mLocalDeviceAddress = null;
+ private List Valid values are in the range [-1, 15]
+ *
+ * @param channelNumber the channel to use for the {@link RangingSession}
+ * @throws IllegalArgumentException if {@code channelNumber} is invalid.
+ */
+ public Builder setChannelNumber(int channelNumber) {
+ if (channelNumber < -1 || channelNumber > 15) {
+ throw new IllegalArgumentException("Invalid channel number");
+ }
+ mChannelNumber = channelNumber;
+ return this;
+ }
+
+ private static final Set Valid values are in the ranges: [0], [13-16], [21-32]
+ *
+ * @param transmitPreambleCodeIndex preamble code index to use for transmitting
+ * @throws IllegalArgumentException if {@code transmitPreambleCodeIndex} is invalid.
+ */
+ public Builder setTransmitPreambleCodeIndex(int transmitPreambleCodeIndex) {
+ if (!VALID_TX_PREAMBLE_CODES.contains(transmitPreambleCodeIndex)) {
+ throw new IllegalArgumentException(
+ "Invalid transmit preamble: " + transmitPreambleCodeIndex);
+ }
+ mTransmitPreambleCodeIndex = transmitPreambleCodeIndex;
+ return this;
+ }
+
+ private static final Set Creates a copy of the parameters
+ *
+ * @param parameters specification parameters built from support library
+ */
+ public Builder setSpecificationParameters(@NonNull PersistableBundle parameters) {
+ mSpecificationParameters = new PersistableBundle(parameters);
+ return this;
+ }
+
+ /**
+ * Build the {@link RangingParams} object.
+ *
+ * @throws IllegalStateException if required parameters are missing
+ */
+ public RangingParams build() {
+ if (mSamplePeriod == null) {
+ throw new IllegalStateException("No sample period provided");
+ }
+
+ if (mLocalDeviceAddress == null) {
+ throw new IllegalStateException("Local device address not provided");
+ }
+
+ if (mRemoteDeviceAddresses.size() == 0) {
+ throw new IllegalStateException("No remote device address(es) provided");
+ }
+
+ return new RangingParams(mIsInitiator, mIsController, mSamplePeriod,
+ mLocalDeviceAddress, mRemoteDeviceAddresses, mChannelNumber,
+ mTransmitPreambleCodeIndex, mReceivePreambleCodeIndex, mStsPhyPacketType,
+ mSpecificationParameters);
+ }
}
}
diff --git a/core/java/android/uwb/RangingReport.java b/core/java/android/uwb/RangingReport.java
index 037bdfd5f2244..5aca12aaf2cf0 100644
--- a/core/java/android/uwb/RangingReport.java
+++ b/core/java/android/uwb/RangingReport.java
@@ -18,6 +18,7 @@ package android.uwb;
import android.annotation.NonNull;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -26,6 +27,12 @@ import java.util.List;
* @hide
*/
public final class RangingReport {
+ private final List The underlying UWB adapter may choose to do multiple measurements in each ranging
@@ -38,7 +45,57 @@ public final class RangingReport {
*/
@NonNull
public List It also defines the required {@link RangingSession.Callback} that must be implemented
+ * in order to be notified of UWB ranging results and status events related to the
+ * {@link RangingSession}.
+ *
+ * To get an instance of {@link RangingSession}, first use
+ * {@link UwbManager#openRangingSession(RangingParams, 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)} with
+ * the failure reason.
+ *
+ * @hide
+ */
+public final class RangingSession implements AutoCloseable {
+ /**
+ * Interface for receiving {@link RangingSession} events
+ */
+ public interface Callback {
+ /**
+ * Invoked when {@link UwbManager#openRangingSession(RangingParams, Executor, Callback)}
+ * is successful
+ *
+ * @param session the newly opened {@link RangingSession}
+ * @param sessionInfo session specific parameters from lower layers
+ */
+ void onOpenSuccess(RangingSession session, PersistableBundle sessionInfo);
+
+ @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 {}
+
+ /**
+ * Indicates that the session was closed or failed to open due to an unknown reason
+ */
+ int CLOSE_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(RangingParams, 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;
+
+ /**
+ * 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;
+
+ /**
+ * 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.
+ *
+ * @param reason reason for the session closure
+ */
+ void onClosed(@CloseReason int reason);
+
+ /**
+ * Called once per ranging interval even when a ranging measurement fails
+ *
+ * @param rangingReport ranging report for this interval's measurements
+ */
+ void onReportReceived(RangingReport rangingReport);
+ }
+
+ /**
+ * Close the ranging session
+ * If this session is currently open, it will close and stop the session.
+ * If the session is in the process of being opened, it will attempt to stop the session from
+ * being opened.
+ * If the session is already closed, the registered {@link Callback#onClosed(int)} callback
+ * will still be invoked.
+ *
+ * {@link Callback#onClosed(int)} will be invoked using the same callback
+ * object given to {@link UwbManager#openRangingSession(RangingParams, Executor, Callback)} when
+ * the {@link RangingSession} was opened. The callback will be invoked after each call to
+ * {@link #close()}, even if the {@link RangingSession} is already closed.
+ */
+ @Override
+ public void close() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 8097dc6dca11d..d58d5bfd8de3a 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -266,4 +266,33 @@ public final class UwbManager {
public int getMaxRemoteDevicesPerResponderSession() {
throw new UnsupportedOperationException();
}
+
+ /**
+ * Open a {@link RangingSession} with the given parameters
+ * 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.
+ *
+ * If a session cannot be opened, then {@link RangingSession.Callback#onClosed(int)} will be
+ * invoked with the appropriate {@link RangingSession.Callback.CloseReason}.
+ *
+ * An open {@link RangingSession} will be automatically closed if client application process
+ * dies.
+ *
+ * @param params {@link RangingParams} used to initialize this {@link RangingSession}
+ * @param executor {@link Executor} to run callbacks
+ * @param callbacks {@link RangingSession.Callback} to associate with the
+ * {@link RangingSession} that is being opened.
+ *
+ * @return an {@link 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}.
+ */
+ @NonNull
+ public AutoCloseable openRangingSession(@NonNull RangingParams params,
+ @NonNull Executor executor, @NonNull RangingSession.Callback callbacks) {
+ throw new UnsupportedOperationException();
+ }
}