Merge changes I732f0e78,I7a8f668c,I1f439621,I55122a7b,I83c43497, ... am: d318d93dd5 am: bad1cba5f0

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

Change-Id: I5c8819a4061c0c7746ecb1d3a19c806aa50cd5fe
This commit is contained in:
Treehugger Robot
2020-10-21 02:01:31 +00:00
committed by Automerger Merge Worker
8 changed files with 805 additions and 30 deletions

View File

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

View File

@@ -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
* <p>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);
}
}
}

View File

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

View File

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

View File

@@ -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<UwbAddress> mRemoteDeviceAddresses;
private final int mChannelNumber;
private final int mTransmitPreambleCodeIndex;
private final int mReceivePreambleCodeIndex;
private final int mStsPhyPacketType;
private final PersistableBundle mSpecificationParameters;
private RangingParams(boolean isInitiator, boolean isController,
@NonNull Duration samplingPeriod, @NonNull UwbAddress localDeviceAddress,
@NonNull List<UwbAddress> remoteDeviceAddresses, int channelNumber,
int transmitPreambleCodeIndex, int receivePreambleCodeIndex,
@StsPhyPacketType int stsPhyPacketType,
@NonNull PersistableBundle specificationParameters) {
mIsInitiator = isInitiator;
mIsController = isController;
mSamplePeriod = samplingPeriod;
mLocalDeviceAddress = localDeviceAddress;
mRemoteDeviceAddresses = remoteDeviceAddresses;
mChannelNumber = channelNumber;
mTransmitPreambleCodeIndex = transmitPreambleCodeIndex;
mReceivePreambleCodeIndex = receivePreambleCodeIndex;
mStsPhyPacketType = stsPhyPacketType;
mSpecificationParameters = specificationParameters;
}
/**
@@ -46,7 +72,7 @@ public final class RangingParams {
* @return true if the device is the initiator
*/
public boolean isInitiator() {
throw new UnsupportedOperationException();
return mIsInitiator;
}
/**
@@ -55,7 +81,7 @@ public final class RangingParams {
* @return true if the device is the controller
*/
public boolean isController() {
throw new UnsupportedOperationException();
return mIsController;
}
/**
@@ -65,7 +91,7 @@ public final class RangingParams {
*/
@NonNull
public Duration getSamplingPeriod() {
throw new UnsupportedOperationException();
return mSamplePeriod;
}
/**
@@ -78,7 +104,7 @@ public final class RangingParams {
*/
@NonNull
public UwbAddress getLocalDeviceAddress() {
throw new UnsupportedOperationException();
return mLocalDeviceAddress;
}
/**
@@ -88,7 +114,7 @@ public final class RangingParams {
*/
@NonNull
public List<UwbAddress> getRemoteDeviceAddresses() {
throw new UnsupportedOperationException();
return mRemoteDeviceAddresses;
}
/**
@@ -99,7 +125,7 @@ public final class RangingParams {
* @return the channel to use
*/
public int getChannelNumber() {
throw new UnsupportedOperationException();
return mChannelNumber;
}
/**
@@ -110,7 +136,7 @@ public final class RangingParams {
* @return the preamble index to use for transmitting
*/
public int getTxPreambleIndex() {
throw new UnsupportedOperationException();
return mTransmitPreambleCodeIndex;
}
/**
@@ -121,7 +147,7 @@ public final class RangingParams {
* @return the preamble index to use for receiving
*/
public int getRxPreambleIndex() {
throw new UnsupportedOperationException();
return mReceivePreambleCodeIndex;
}
@Retention(RetentionPolicy.SOURCE)
@@ -159,7 +185,7 @@ public final class RangingParams {
*/
@StsPhyPacketType
public int getStsPhyPacketType() {
throw new UnsupportedOperationException();
return mStsPhyPacketType;
}
/**
@@ -167,9 +193,189 @@ public final class RangingParams {
*
* <p>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<UwbAddress> mRemoteDeviceAddresses = new ArrayList<>();
private int mChannelNumber = 0;
private int mTransmitPreambleCodeIndex = 0;
private int mReceivePreambleCodeIndex = 0;
private int mStsPhyPacketType = STS_PHY_PACKET_TYPE_SP0;
private PersistableBundle mSpecificationParameters = new PersistableBundle();
/**
* Set whether the device is the initiator or responder as defined by IEEE 802.15.4z
*
* @param isInitiator whether the device is the initiator (true) or responder (false)
*/
public Builder setIsInitiator(boolean isInitiator) {
mIsInitiator = isInitiator;
return this;
}
/**
* Set whether the local device is the controller or controlee as defined by IEEE 802.15.4z
*
* @param isController whether the device is the controller (true) or controlee (false)
*/
public Builder setIsController(boolean isController) {
mIsController = isController;
return this;
}
/**
* Set the time between ranging samples
*
* @param samplePeriod the time between ranging samples
*/
public Builder setSamplePeriod(@NonNull Duration samplePeriod) {
mSamplePeriod = samplePeriod;
return this;
}
/**
* Set the local device address
*
* @param localDeviceAddress the local device's address for the {@link RangingSession}
*/
public Builder setLocalDeviceAddress(@NonNull UwbAddress localDeviceAddress) {
mLocalDeviceAddress = localDeviceAddress;
return this;
}
/**
* Add a remote device's address to the ranging session
*
* @param remoteDeviceAddress a remote device's address for the {@link RangingSession}
* @throws IllegalArgumentException if {@code remoteDeviceAddress} is already present.
*/
public Builder addRemoteDeviceAddress(@NonNull UwbAddress remoteDeviceAddress) {
if (mRemoteDeviceAddresses.contains(remoteDeviceAddress)) {
throw new IllegalArgumentException(
"Remote device address already added: " + remoteDeviceAddress.toString());
}
mRemoteDeviceAddresses.add(remoteDeviceAddress);
return this;
}
/**
* Set the IEEE 802.15.4z channel to use for the {@link RangingSession}
* <p>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<Integer> VALID_TX_PREAMBLE_CODES = new HashSet<Integer>(
Arrays.asList(0, 13, 14, 15, 16, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32));
/**
* Set the IEEE 802.15.4z preamble code index to use when transmitting
*
* <p>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<Integer> VALID_RX_PREAMBLE_CODES = new HashSet<Integer>(
Arrays.asList(0, 16, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32));
/**
* Set the IEEE 802.15.4z preamble code index to use when receiving
*
* Valid values are in the ranges: [0], [16-32]
*
* @param receivePreambleCodeIndex preamble code index to use for receiving
* @throws IllegalArgumentException if {@code receivePreambleCodeIndex} is invalid.
*/
public Builder setReceivePreambleCodeIndex(int receivePreambleCodeIndex) {
if (!VALID_RX_PREAMBLE_CODES.contains(receivePreambleCodeIndex)) {
throw new IllegalArgumentException(
"Invalid receive preamble: " + receivePreambleCodeIndex);
}
mReceivePreambleCodeIndex = receivePreambleCodeIndex;
return this;
}
/**
* Set the IEEE 802.15.4z PHY packet type when STS is used
*
* @param stsPhyPacketType PHY packet type when STS is used
* @throws IllegalArgumentException if {@code stsPhyPacketType} is invalid.
*/
public Builder setStsPhPacketType(@StsPhyPacketType int stsPhyPacketType) {
if (stsPhyPacketType != STS_PHY_PACKET_TYPE_SP0
&& stsPhyPacketType != STS_PHY_PACKET_TYPE_SP1
&& stsPhyPacketType != STS_PHY_PACKET_TYPE_SP2
&& stsPhyPacketType != STS_PHY_PACKET_TYPE_SP3) {
throw new IllegalArgumentException("unknown StsPhyPacketType: " + stsPhyPacketType);
}
mStsPhyPacketType = stsPhyPacketType;
return this;
}
/**
* Set the specification parameters
*
* <p>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);
}
}
}

View File

@@ -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<RangingMeasurement> mRangingMeasurements;
private RangingReport(@NonNull List<RangingMeasurement> rangingMeasurements) {
mRangingMeasurements = rangingMeasurements;
}
/**
* Get a {@link List} of {@link RangingMeasurement} objects in the last measurement interval
* <p>The underlying UWB adapter may choose to do multiple measurements in each ranging
@@ -38,7 +45,57 @@ public final class RangingReport {
*/
@NonNull
public List<RangingMeasurement> getMeasurements() {
throw new UnsupportedOperationException();
return mRangingMeasurements;
}
/**
* Builder for {@link RangingReport} object
*/
public static final class Builder {
List<RangingMeasurement> mMeasurements = new ArrayList<>();
/**
* Add a single {@link RangingMeasurement}
*
* @param rangingMeasurement a ranging measurement
*/
public Builder addMeasurement(@NonNull RangingMeasurement rangingMeasurement) {
mMeasurements.add(rangingMeasurement);
return this;
}
/**
* Add a {@link List} of {@link RangingMeasurement}s
*
* @param rangingMeasurements {@link List} of {@link RangingMeasurement}s to add
*/
public Builder addMeasurements(@NonNull List<RangingMeasurement> rangingMeasurements) {
mMeasurements.addAll(rangingMeasurements);
return this;
}
/**
* Build the {@link RangingReport} object
*
* @throws IllegalStateException if measurements are not in monotonically increasing order
*/
public RangingReport build() {
// Verify that all measurement timestamps are monotonically increasing
RangingMeasurement prevMeasurement = null;
for (int curIndex = 0; curIndex < mMeasurements.size(); curIndex++) {
RangingMeasurement curMeasurement = mMeasurements.get(curIndex);
if (prevMeasurement != null
&& (prevMeasurement.getElapsedRealtimeNanos()
> curMeasurement.getElapsedRealtimeNanos())) {
throw new IllegalStateException(
"Timestamp (" + curMeasurement.getElapsedRealtimeNanos()
+ ") at index " + curIndex + " is less than previous timestamp ("
+ prevMeasurement.getElapsedRealtimeNanos() + ")");
}
prevMeasurement = curMeasurement;
}
return new RangingReport(mMeasurements);
}
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.uwb;
import android.annotation.IntDef;
import android.os.PersistableBundle;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
/**
* This class provides a way to control an active UWB ranging session.
* <p>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}.
*
* <p>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
* <p>If this session is currently open, it will close and stop 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 {@link Callback#onClosed(int)} callback
* will still be invoked.
*
* <p>{@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();
}
}

View File

@@ -266,4 +266,33 @@ public final class UwbManager {
public int getMaxRemoteDevicesPerResponderSession() {
throw new UnsupportedOperationException();
}
/**
* 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>If a session cannot be opened, then {@link RangingSession.Callback#onClosed(int)} will be
* invoked with the appropriate {@link RangingSession.Callback.CloseReason}.
*
* <p>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();
}
}