Merge changes Ic9fbf2f9,I1eb54c07 into main
* changes:
[remoteauth] Add RangingManager interfaces
[remoteauth] Add RangingSession interfaces
diff --git a/remoteauth/service/Android.bp b/remoteauth/service/Android.bp
index c3a9fb3..3486d8c 100644
--- a/remoteauth/service/Android.bp
+++ b/remoteauth/service/Android.bp
@@ -27,7 +27,7 @@
srcs: [":remoteauth-service-srcs"],
defaults: [
- "framework-system-server-module-defaults"
+ "framework-system-server-module-defaults",
],
libs: [
"androidx.annotation_annotation",
@@ -39,6 +39,7 @@
"framework-statsd",
],
static_libs: [
+ "guava",
"libprotobuf-java-lite",
"fast-pair-lite-protos",
"modules-utils-build",
@@ -69,7 +70,7 @@
name: "statslog-remoteauth-java-gen",
tools: ["stats-log-api-gen"],
cmd: "$(location stats-log-api-gen) --java $(out) --module remoteauth " +
- " --javaPackage com.android.server.remoteauth.proto --javaClass RemoteAuthStatsLog" +
- " --minApiLevel 33",
+ " --javaPackage com.android.server.remoteauth.proto --javaClass RemoteAuthStatsLog" +
+ " --minApiLevel 33",
out: ["com/android/server/remoteauth/proto/RemoteAuthStatsLog.java"],
}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/README.md b/remoteauth/service/java/com/android/server/remoteauth/README.md
index 2f8b096..b2b5aab 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/README.md
+++ b/remoteauth/service/java/com/android/server/remoteauth/README.md
@@ -1,4 +1,8 @@
This is the source root for the RemoteAuthService
-## Remote connectivity manager
+## Connectivity
Provides the connectivity manager to manage connections with the peer device.
+
+## Ranging
+Provides the ranging manager to perform ranging with the peer devices.
+
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingCapabilities.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingCapabilities.java
new file mode 100644
index 0000000..2b5efff
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingCapabilities.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.remoteauth.ranging;
+
+import androidx.annotation.IntDef;
+
+import com.google.common.collect.ImmutableList;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/** The ranging capabilities of the device. */
+public class RangingCapabilities {
+
+ /** Possible ranging methods */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ value = {
+ RANGING_METHOD_UNKNOWN,
+ RANGING_METHOD_UWB,
+ })
+ public @interface RangingMethod {}
+
+ /** Unknown ranging method. */
+ public static final int RANGING_METHOD_UNKNOWN = 0x0;
+
+ /** Ultra-wideband ranging. */
+ public static final int RANGING_METHOD_UWB = 0x1;
+
+ private final ImmutableList<Integer> mSupportedRangingMethods;
+
+ /**
+ * Gets the list of supported ranging methods of the device.
+ *
+ * @return list of {@link RangingMethod}
+ */
+ public ImmutableList<Integer> getSupportedRangingMethods() {
+ return mSupportedRangingMethods;
+ }
+
+ private RangingCapabilities(List<Integer> supportedRangingMethods) {
+ mSupportedRangingMethods = ImmutableList.copyOf(supportedRangingMethods);
+ }
+
+ /** Builder class for {@link RangingCapabilities}. */
+ public static final class Builder {
+ private List<Integer> mSupportedRangingMethods = new ArrayList<>();
+
+ /** Adds a supported {@link RangingMethod} */
+ public Builder addSupportedRangingMethods(@RangingMethod int rangingMethod) {
+ mSupportedRangingMethods.add(rangingMethod);
+ return this;
+ }
+
+ /** Builds {@link RangingCapabilities}. */
+ public RangingCapabilities build() {
+ return new RangingCapabilities(mSupportedRangingMethods);
+ }
+ }
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingManager.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingManager.java
new file mode 100644
index 0000000..989b5ed
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingManager.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.remoteauth.ranging;
+
+import android.content.Context;
+
+/**
+ * Manages the creation of generic device to device ranging session and obtaining device's ranging
+ * capabilities.
+ *
+ * <p>Out-of-band channel for ranging capabilities/parameters exchange is assumed being handled
+ * outside of this class.
+ */
+public class RangingManager {
+
+ public RangingManager(Context context) {}
+
+ /**
+ * Gets the {@link RangingCapabilities} of this device.
+ *
+ * @return RangingCapabilities.
+ */
+ public RangingCapabilities getRangingCapabilities() {
+ return null;
+ }
+
+ /**
+ * Creates a {@link RangingSession} based on the given {@link SessionParameters}, which shall be
+ * provided based on the rangingCapabilities of the device.
+ *
+ * @param sessionParameters parameters used to setup the session.
+ * @return the created RangingSession.
+ */
+ public RangingSession createSession(SessionParameters sessionParameters) {
+ return null;
+ }
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingParameters.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingParameters.java
new file mode 100644
index 0000000..923730c
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingParameters.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.remoteauth.ranging;
+
+/** The set of parameters to start ranging. */
+public class RangingParameters {}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingReport.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingReport.java
new file mode 100644
index 0000000..5e582b1
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingReport.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.remoteauth.ranging;
+
+import androidx.annotation.IntDef;
+
+/** Holds ranging report data. */
+public class RangingReport {
+
+ /**
+ * State of the proximity based on detected distance compared against specified near and far
+ * boundaries.
+ */
+ @IntDef(
+ value = {
+ PROXIMITY_STATE_UNKNOWN,
+ PROXIMITY_STATE_INSIDE,
+ PROXIMITY_STATE_OUTSIDE,
+ })
+ public @interface ProximityState {}
+
+ /** Unknown proximity state. */
+ public static final int PROXIMITY_STATE_UNKNOWN = 0x0;
+
+ /**
+ * Proximity is inside the lower and upper proximity boundary. lowerProximityBoundaryM <=
+ * proximity <= upperProximityBoundaryM
+ */
+ public static final int PROXIMITY_STATE_INSIDE = 0x1;
+
+ /**
+ * Proximity is outside the lower and upper proximity boundary. proximity <
+ * lowerProximityBoundaryM OR upperProximityBoundaryM < proximity
+ */
+ public static final int PROXIMITY_STATE_OUTSIDE = 0x2;
+
+ private final float mDistanceM;
+ @ProximityState private final int mProximityState;
+
+ /**
+ * Gets the distance measurement in meters.
+ *
+ * <p>Value may be negative for devices in very close proximity.
+ *
+ * @return distance in meters
+ */
+ public float getDistanceM() {
+ return mDistanceM;
+ }
+
+ /**
+ * Gets the {@link ProximityState}.
+ *
+ * <p>The state is computed based on {@link #getDistanceM} and proximity related session
+ * parameters.
+ *
+ * @return proximity state
+ */
+ @ProximityState
+ public int getProximityState() {
+ return mProximityState;
+ }
+
+ private RangingReport(float distanceM, @ProximityState int proximityState) {
+ mDistanceM = distanceM;
+ mProximityState = proximityState;
+ }
+
+ /** Builder class for {@link RangingReport}. */
+ public static final class Builder {
+ private float mDistanceM;
+ @ProximityState private int mProximityState;
+
+ /** Sets the distance in meters. */
+ public Builder setDistanceM(float distanceM) {
+ mDistanceM = distanceM;
+ return this;
+ }
+
+ /** Sets the proximity state. */
+ public Builder setProximityState(@ProximityState int proximityState) {
+ mProximityState = proximityState;
+ return this;
+ }
+
+ /** Builds {@link RangingReport}. */
+ public RangingReport build() {
+ return new RangingReport(mDistanceM, mProximityState);
+ }
+ }
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingSession.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingSession.java
new file mode 100644
index 0000000..9ef6bda
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingSession.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.remoteauth.ranging;
+
+import android.annotation.NonNull;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
+/**
+ * The controller for starting and stopping ranging during which callers receive callbacks with
+ * {@link RangingReport}s and {@link RangingError}s."
+ *
+ * <p>A session can be started and stopped multiple times. After starting, updates ({@link
+ * RangingReport}, {@link RangingError}, etc) will be reported via the provided {@link
+ * RangingCallback}. BaseKey and SyncData are used for auto derivation of supported ranging
+ * parameters, which will be implementation specific.
+ *
+ * <p>Ranging method specific implementation shall be implemented in the extended class.
+ */
+public abstract class RangingSession {
+
+ /** Types of ranging error. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ value = {
+ RANGING_ERROR_UNKNOWN,
+ })
+ public @interface RangingError {}
+
+ /** Unknown ranging error type. */
+ public static final int RANGING_ERROR_UNKNOWN = 0x0;
+
+ /** Interface for ranging update callbacks. */
+ public interface RangingCallback {
+ /**
+ * Call upon new {@link RangingReport}.
+ *
+ * @param sessionInfo info about this ranging session.
+ * @param rangingReport new ranging report
+ */
+ void onRangingReport(SessionInfo sessionInfo, RangingReport rangingReport);
+
+ /**
+ * Call upon any ranging error events.
+ *
+ * @param sessionInfo info about this ranging session.
+ * @param rangingError error type
+ */
+ void onError(SessionInfo sessionInfo, @RangingError int rangingError);
+ }
+
+ /**
+ * Starts ranging based on the given {@link RangingParameters}.
+ *
+ * <p>Start can be called again after {@link #stop()} has been called, else it will result in a
+ * no-op.
+ *
+ * @param rangingParameters parameters to start the ranging.
+ * @param executor Executor to run the rangingCallback.
+ * @param rangingCallback callback to notify of ranging events.
+ */
+ public abstract void start(
+ @NonNull RangingParameters rangingParameters,
+ @NonNull Executor executor,
+ @NonNull RangingCallback rangingCallback);
+
+ /**
+ * Stops ranging.
+ *
+ * <p>Calling stop without first calling {@link #start()} will result in a no-op.
+ */
+ public abstract void stop();
+
+ /**
+ * Resets the base key that's used to derive all possible ranging parameters. The baseKey shall
+ * be reset whenever there is a risk that it may no longer be valid and secured. For example,
+ * the secure connection between the devices is lost.
+ *
+ * @param baseKey new baseKey must be 16 or 32 bytes.
+ */
+ public void resetBaseKey(byte[] baseKey) {}
+
+ /**
+ * Resets the synchronization by giving a new syncData used for ranging parameters derivation.
+ * Resetting the syncData is not required before each {@link #start}, but the more time the
+ * derivations are done before resetting syncData, the higher the risk the derivation will be
+ * out of sync between the devices. Therefore, syncData shall be refreshed in a best effort
+ * manner.
+ *
+ * @param syncData new syncData must be 16 bytes.
+ */
+ public void resetSyncData(byte[] syncData) {}
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionInfo.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionInfo.java
new file mode 100644
index 0000000..5e4fc48
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionInfo.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UNKNOWN;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.remoteauth.ranging.RangingCapabilities.RangingMethod;
+
+/** Information about the {@link RangingSession}. */
+public class SessionInfo {
+
+ private final String mDeviceId;
+ @RangingMethod private final int mRangingMethod;
+
+ public String getDeviceId() {
+ return mDeviceId;
+ }
+
+ @RangingMethod
+ public int getRangingMethod() {
+ return mRangingMethod;
+ }
+
+ private SessionInfo(String deviceId, @RangingMethod int rangingMethod) {
+ mDeviceId = deviceId;
+ mRangingMethod = rangingMethod;
+ }
+
+ /** Builder class for {@link SessionInfo}. */
+ public static final class Builder {
+ private String mDeviceId = "";
+ @RangingMethod private int mRangingMethod = RANGING_METHOD_UNKNOWN;
+
+ /** Sets the device id. */
+ public Builder setDeviceId(String deviceId) {
+ mDeviceId = deviceId;
+ return this;
+ }
+
+ /** Sets the ranging method. */
+ public Builder setRangingMethod(@RangingMethod int rangingMethod) {
+ mRangingMethod = rangingMethod;
+ return this;
+ }
+
+ /** Builds {@link SessionInfo}. */
+ public SessionInfo build() {
+ Preconditions.checkArgument(!mDeviceId.isEmpty(), "deviceId must not be empty.");
+ Preconditions.checkArgument(
+ mRangingMethod != RANGING_METHOD_UNKNOWN, "Unknown rangingMethod");
+ return new SessionInfo(mDeviceId, mRangingMethod);
+ }
+ }
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionParameters.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionParameters.java
new file mode 100644
index 0000000..33c3203
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionParameters.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UNKNOWN;
+
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.remoteauth.ranging.RangingCapabilities.RangingMethod;
+
+/**
+ * The set of parameters to create a ranging session.
+ *
+ * <p>Required parameters must be provided, else {@link Builder} will throw an exception. The
+ * optional parameters only need to be provided if the functionality is necessary to the session,
+ * see the setter functions of the {@link Builder} for detailed info of each parameter.
+ */
+public class SessionParameters {
+
+ /* Required parameters */
+ private final String mDeviceId;
+ @RangingMethod private final int mRangingMethod;
+
+ /* Optional parameters */
+ private final float mLowerProximityBoundaryM;
+ private final float mUpperProximityBoundaryM;
+ private final boolean mAutoDeriveParams;
+ private final byte[] mBaseKey;
+ private final byte[] mSyncData;
+
+ public String getDeviceId() {
+ return mDeviceId;
+ }
+
+ @RangingMethod
+ public int getRangingMethod() {
+ return mRangingMethod;
+ }
+
+ public float getLowerProximityBoundaryM() {
+ return mLowerProximityBoundaryM;
+ }
+
+ public float getUpperProximityBoundaryM() {
+ return mUpperProximityBoundaryM;
+ }
+
+ public boolean getAutoDeriveParams() {
+ return mAutoDeriveParams;
+ }
+
+ public byte[] getBaseKey() {
+ return mBaseKey;
+ }
+
+ public byte[] getSyncData() {
+ return mSyncData;
+ }
+
+ private SessionParameters(
+ String deviceId,
+ @RangingMethod int rangingMethod,
+ float lowerProximityBoundaryM,
+ float upperProximityBoundaryM,
+ boolean autoDeriveParams,
+ byte[] baseKey,
+ byte[] syncData) {
+ mDeviceId = deviceId;
+ mRangingMethod = rangingMethod;
+ mLowerProximityBoundaryM = lowerProximityBoundaryM;
+ mUpperProximityBoundaryM = upperProximityBoundaryM;
+ mAutoDeriveParams = autoDeriveParams;
+ mBaseKey = baseKey;
+ mSyncData = syncData;
+ }
+
+ /** Builder class for {@link SessionParameters}. */
+ public static final class Builder {
+ private String mDeviceId = new String("");
+ @RangingMethod private int mRangingMethod = RANGING_METHOD_UNKNOWN;
+ private float mLowerProximityBoundaryM;
+ private float mUpperProximityBoundaryM;
+ private boolean mAutoDeriveParams = false;
+ private byte[] mBaseKey = new byte[] {};
+ private byte[] mSyncData = new byte[] {};
+
+ /**
+ * Sets the device id.
+ *
+ * <p>This is used as the identity included in the {@link SessionInfo} for all {@link
+ * RangingCallback}s.
+ */
+ public Builder setDeviceId(@NonNull String deviceId) {
+ mDeviceId = deviceId;
+ return this;
+ }
+
+ /**
+ * Sets the {@link RangingMethod} to be used for the {@link RangingSession}.
+ *
+ * <p>Note: The ranging method should be ones in the list return by {@link
+ * RangingCapabilities#getSupportedRangingMethods};
+ */
+ public Builder setRangingMethod(@RangingMethod int rangingMethod) {
+ mRangingMethod = rangingMethod;
+ return this;
+ }
+
+ /**
+ * Sets the lower proximity boundary in meters, must be greater than or equals to zero.
+ *
+ * <p>This value is used to compute the {@link ProximityState} = {@link
+ * PROXIMITY_STATE_INSIDE} if lowerProximityBoundaryM <= proximity <=
+ * upperProximityBoundaryM, else {@link PROXIMITY_STATE_OUTSIDE}.
+ */
+ public Builder setLowerProximityBoundaryM(float lowerProximityBoundaryM) {
+ mLowerProximityBoundaryM = lowerProximityBoundaryM;
+ return this;
+ }
+
+ /**
+ * Sets the upper proximity boundary in meters, must be greater than or equals to
+ * lowerProximityBoundaryM.
+ *
+ * <p>This value is used to compute the {@link ProximityState} = {@link
+ * PROXIMITY_STATE_INSIDE} if lowerProximityBoundaryM <= proximity <=
+ * upperProximityBoundaryM, else {@link PROXIMITY_STATE_OUTSIDE}.
+ */
+ public Builder setUpperProximityBoundaryM(float upperProximityBoundaryM) {
+ mUpperProximityBoundaryM = upperProximityBoundaryM;
+ return this;
+ }
+
+ /**
+ * Sets the auto derive ranging parameters flag. Defaults to false.
+ *
+ * <p>This enables the {@link RangingSession} to automatically derive all possible {@link
+ * RangingParameters} at each {@link RangingSession#start} using the provided {@link
+ * #setBaseKey} and {@link #setSyncData}, which shall be securely shared between the ranging
+ * devices out of band.
+ */
+ public Builder setAutoDeriveParams(boolean autoDeriveParams) {
+ mAutoDeriveParams = autoDeriveParams;
+ return this;
+ }
+
+ /**
+ * Sets the base key. Only required if {@link #setAutoDeriveParams} is set to true.
+ *
+ * @param baseKey baseKey must be 16 or 32 bytes.
+ * @throws NullPointerException if baseKey is null
+ */
+ public Builder setBaseKey(@NonNull byte[] baseKey) {
+ Preconditions.checkNotNull(baseKey);
+ mBaseKey = baseKey;
+ return this;
+ }
+
+ /**
+ * Sets the sync data. Only required if {@link #setAutoDeriveParams} is set to true.
+ *
+ * @param syncData syncData must be 16 bytes.
+ * @throws NullPointerException if syncData is null
+ */
+ public Builder setSyncData(@NonNull byte[] syncData) {
+ Preconditions.checkNotNull(syncData);
+ mSyncData = syncData;
+ return this;
+ }
+
+ /**
+ * Builds {@link SessionParameters}.
+ *
+ * @throws IllegalArgumentException if any parameter is invalid.
+ */
+ public SessionParameters build() {
+ Preconditions.checkArgument(!mDeviceId.isEmpty(), "deviceId must not be empty.");
+ Preconditions.checkArgument(
+ mRangingMethod != RANGING_METHOD_UNKNOWN, "Unknown rangingMethod");
+ Preconditions.checkArgument(
+ mLowerProximityBoundaryM >= 0,
+ "Negative lowerProximityBoundaryM: " + mLowerProximityBoundaryM);
+ Preconditions.checkArgument(
+ mLowerProximityBoundaryM <= mUpperProximityBoundaryM,
+ "lowerProximityBoundaryM is greater than upperProximityBoundaryM: "
+ + mLowerProximityBoundaryM
+ + " > "
+ + mUpperProximityBoundaryM);
+ // If mAutoDeriveParams is false, mBaseKey and mSyncData will not be used.
+ if (mAutoDeriveParams) {
+ Preconditions.checkArgument(
+ mBaseKey.length == 16 || mBaseKey.length == 32,
+ "Invalid baseKey length: " + mBaseKey.length);
+ Preconditions.checkArgument(
+ mSyncData.length == 16, "Invalid syncData length: " + mSyncData.length);
+ }
+
+ return new SessionParameters(
+ mDeviceId,
+ mRangingMethod,
+ mLowerProximityBoundaryM,
+ mUpperProximityBoundaryM,
+ mAutoDeriveParams,
+ mBaseKey,
+ mSyncData);
+ }
+ }
+}
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingCapabilitiesTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingCapabilitiesTest.java
new file mode 100644
index 0000000..e6b6e3b
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingCapabilitiesTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UWB;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit test for {@link RangingCapabilities}. */
+@RunWith(AndroidJUnit4.class)
+public class RangingCapabilitiesTest {
+
+ @Test
+ public void testBuildingRangingCapabilities_success() {
+ final RangingCapabilities rangingCapabilities =
+ new RangingCapabilities.Builder()
+ .addSupportedRangingMethods(RANGING_METHOD_UWB)
+ .build();
+
+ assertEquals(rangingCapabilities.getSupportedRangingMethods().size(), 1);
+ assertEquals(
+ (int) rangingCapabilities.getSupportedRangingMethods().get(0), RANGING_METHOD_UWB);
+ }
+}
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingReportTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingReportTest.java
new file mode 100644
index 0000000..6ac56ea
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingReportTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingReport.PROXIMITY_STATE_INSIDE;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.server.remoteauth.ranging.RangingReport.ProximityState;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit test for {@link RangingReport}. */
+@RunWith(AndroidJUnit4.class)
+public class RangingReportTest {
+
+ private static final float TEST_DISTANCE_M = 1.5f;
+ @ProximityState private static final int TEST_PROXIMITY_STATE = PROXIMITY_STATE_INSIDE;
+
+ @Test
+ public void testBuildingRangingReport_success() {
+ final RangingReport rangingReport =
+ new RangingReport.Builder()
+ .setDistanceM(TEST_DISTANCE_M)
+ .setProximityState(TEST_PROXIMITY_STATE)
+ .build();
+
+ assertEquals(rangingReport.getDistanceM(), TEST_DISTANCE_M, 0.0f);
+ assertEquals(rangingReport.getProximityState(), TEST_PROXIMITY_STATE);
+ }
+}
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionInfoTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionInfoTest.java
new file mode 100644
index 0000000..9364092
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionInfoTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UWB;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.server.remoteauth.ranging.RangingCapabilities.RangingMethod;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit test for {@link SessionInfo}. */
+@RunWith(AndroidJUnit4.class)
+public class SessionInfoTest {
+
+ private static final String TEST_DEVICE_ID = new String("test_device_id");
+ private static final @RangingMethod int TEST_RANGING_METHOD = RANGING_METHOD_UWB;
+
+ @Test
+ public void testBuildingSessionInfo_success() {
+ final SessionInfo sessionInfo =
+ new SessionInfo.Builder()
+ .setDeviceId(TEST_DEVICE_ID)
+ .setRangingMethod(TEST_RANGING_METHOD)
+ .build();
+
+ assertEquals(sessionInfo.getDeviceId(), TEST_DEVICE_ID);
+ assertEquals(sessionInfo.getRangingMethod(), TEST_RANGING_METHOD);
+ }
+
+ @Test
+ public void testBuildingSessionInfo_invalidDeviceId() {
+ final SessionInfo.Builder builder =
+ new SessionInfo.Builder().setRangingMethod(TEST_RANGING_METHOD);
+
+ assertThrows(IllegalArgumentException.class, () -> builder.build());
+ }
+
+ @Test
+ public void testBuildingSessionInfo_invalidRangingMethod() {
+ final SessionInfo.Builder builder = new SessionInfo.Builder().setDeviceId(TEST_DEVICE_ID);
+
+ assertThrows(IllegalArgumentException.class, () -> builder.build());
+ }
+}
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionParametersTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionParametersTest.java
new file mode 100644
index 0000000..357fdf9
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/SessionParametersTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2023 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 com.android.server.remoteauth.ranging;
+
+import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UWB;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.server.remoteauth.ranging.RangingCapabilities.RangingMethod;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link SessionParameters}. */
+@RunWith(AndroidJUnit4.class)
+public class SessionParametersTest {
+
+ private static final String TEST_DEVICE_ID = "test_device_id";
+ @RangingMethod private static final int TEST_RANGING_METHOD = RANGING_METHOD_UWB;
+ private static final float TEST_LOWER_PROXIMITY_BOUNDARY_M = 1.0f;
+ private static final float TEST_UPPER_PROXIMITY_BOUNDARY_M = 2.5f;
+ private static final boolean TEST_AUTO_DERIVE_PARAMS = true;
+ private static final byte[] TEST_BASE_KEY =
+ new byte[] {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+ 0x0e, 0x0f
+ };
+ private static final byte[] TEST_SYNC_DATA =
+ new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x00
+ };
+
+ @Test
+ public void testBuildingSessionParameters_success() {
+ final SessionParameters sessionParameters =
+ new SessionParameters.Builder()
+ .setDeviceId(TEST_DEVICE_ID)
+ .setRangingMethod(TEST_RANGING_METHOD)
+ .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+ .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+ .setAutoDeriveParams(TEST_AUTO_DERIVE_PARAMS)
+ .setBaseKey(TEST_BASE_KEY)
+ .setSyncData(TEST_SYNC_DATA)
+ .build();
+
+ assertEquals(sessionParameters.getDeviceId(), TEST_DEVICE_ID);
+ assertEquals(sessionParameters.getRangingMethod(), TEST_RANGING_METHOD);
+ assertEquals(
+ sessionParameters.getLowerProximityBoundaryM(),
+ TEST_LOWER_PROXIMITY_BOUNDARY_M,
+ 0.0f);
+ assertEquals(
+ sessionParameters.getUpperProximityBoundaryM(),
+ TEST_UPPER_PROXIMITY_BOUNDARY_M,
+ 0.0f);
+ assertEquals(sessionParameters.getAutoDeriveParams(), TEST_AUTO_DERIVE_PARAMS);
+ assertArrayEquals(sessionParameters.getBaseKey(), TEST_BASE_KEY);
+ assertArrayEquals(sessionParameters.getSyncData(), TEST_SYNC_DATA);
+ }
+
+ @Test
+ public void testBuildingSessionParameters_invalidDeviceId() {
+ final SessionParameters.Builder builder =
+ new SessionParameters.Builder()
+ .setRangingMethod(TEST_RANGING_METHOD)
+ .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+ .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+ .setBaseKey(TEST_BASE_KEY)
+ .setSyncData(TEST_SYNC_DATA);
+
+ assertThrows(IllegalArgumentException.class, () -> builder.build());
+ }
+
+ @Test
+ public void testBuildingSessionParameters_invalidRangingMethod() {
+ final SessionParameters.Builder builder =
+ new SessionParameters.Builder()
+ .setDeviceId(TEST_DEVICE_ID)
+ .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+ .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+ .setBaseKey(TEST_BASE_KEY)
+ .setSyncData(TEST_SYNC_DATA);
+
+ assertThrows(IllegalArgumentException.class, () -> builder.build());
+ }
+
+ @Test
+ public void testBuildingSessionParameters_invalidLowerProximityBoundaryM() {
+ final SessionParameters.Builder builder =
+ new SessionParameters.Builder()
+ .setDeviceId(TEST_DEVICE_ID)
+ .setRangingMethod(TEST_RANGING_METHOD)
+ .setLowerProximityBoundaryM(-1.0f)
+ .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+ .setBaseKey(TEST_BASE_KEY)
+ .setSyncData(TEST_SYNC_DATA);
+
+ assertThrows(IllegalArgumentException.class, () -> builder.build());
+ }
+
+ @Test
+ public void testBuildingSessionParameters_invalidUpperProximityBoundaryM() {
+ final SessionParameters.Builder builder =
+ new SessionParameters.Builder()
+ .setDeviceId(TEST_DEVICE_ID)
+ .setRangingMethod(TEST_RANGING_METHOD)
+ .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+ .setUpperProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M - 0.1f)
+ .setBaseKey(TEST_BASE_KEY)
+ .setSyncData(TEST_SYNC_DATA);
+
+ assertThrows(IllegalArgumentException.class, () -> builder.build());
+ }
+
+ @Test
+ public void testBuildingSessionParameters_disableAutoDeriveParams() {
+ final boolean autoDeriveParams = false;
+ final SessionParameters sessionParameters =
+ new SessionParameters.Builder()
+ .setDeviceId(TEST_DEVICE_ID)
+ .setRangingMethod(TEST_RANGING_METHOD)
+ .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+ .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+ .setAutoDeriveParams(autoDeriveParams)
+ .build();
+
+ assertEquals(sessionParameters.getAutoDeriveParams(), autoDeriveParams);
+ assertArrayEquals(sessionParameters.getBaseKey(), new byte[] {});
+ assertArrayEquals(sessionParameters.getSyncData(), new byte[] {});
+ }
+
+ @Test
+ public void testBuildingSessionParameters_emptyBaseKey() {
+ final SessionParameters.Builder builder =
+ new SessionParameters.Builder()
+ .setDeviceId(TEST_DEVICE_ID)
+ .setRangingMethod(TEST_RANGING_METHOD)
+ .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+ .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+ .setAutoDeriveParams(TEST_AUTO_DERIVE_PARAMS)
+ .setSyncData(TEST_SYNC_DATA);
+
+ assertThrows(IllegalArgumentException.class, () -> builder.build());
+ }
+
+ @Test
+ public void testBuildingSessionParameters_invalidBaseKey() {
+ final SessionParameters.Builder builder =
+ new SessionParameters.Builder()
+ .setDeviceId(TEST_DEVICE_ID)
+ .setRangingMethod(TEST_RANGING_METHOD)
+ .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+ .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+ .setAutoDeriveParams(TEST_AUTO_DERIVE_PARAMS)
+ .setBaseKey(new byte[] {0x00, 0x01, 0x02, 0x13})
+ .setSyncData(TEST_SYNC_DATA);
+
+ assertThrows(IllegalArgumentException.class, () -> builder.build());
+ }
+
+ @Test
+ public void testBuildingSessionParameters_emptySyncData() {
+ final SessionParameters.Builder builder =
+ new SessionParameters.Builder()
+ .setDeviceId(TEST_DEVICE_ID)
+ .setRangingMethod(TEST_RANGING_METHOD)
+ .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+ .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+ .setAutoDeriveParams(TEST_AUTO_DERIVE_PARAMS)
+ .setBaseKey(TEST_BASE_KEY);
+
+ assertThrows(IllegalArgumentException.class, () -> builder.build());
+ }
+
+ @Test
+ public void testBuildingSessionParameters_invalidSyncData() {
+ final SessionParameters.Builder builder =
+ new SessionParameters.Builder()
+ .setDeviceId(TEST_DEVICE_ID)
+ .setRangingMethod(TEST_RANGING_METHOD)
+ .setLowerProximityBoundaryM(TEST_LOWER_PROXIMITY_BOUNDARY_M)
+ .setUpperProximityBoundaryM(TEST_UPPER_PROXIMITY_BOUNDARY_M)
+ .setAutoDeriveParams(TEST_AUTO_DERIVE_PARAMS)
+ .setBaseKey(TEST_BASE_KEY)
+ .setSyncData(new byte[] {0x00, 0x01, 0x02, 0x13});
+
+ assertThrows(IllegalArgumentException.class, () -> builder.build());
+ }
+}