[remoteauth] Add RangingSession interfaces

* Initial commit to define interfaces and data structures for ranging
  session.

Test: atest RemoteAuthUnitTests
Bug: 290675597
Change-Id: I1eb54c079a212e8d3599b156899d0c46c6b6d636
diff --git a/remoteauth/service/Android.bp b/remoteauth/service/Android.bp
index c3a9fb3..737fa32 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",
@@ -69,7 +69,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..d61ca37
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingCapabilities.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/** The ranging capabilities of the device. */
+public class RangingCapabilities {
+
+    /** Possible ranging methods */
+    @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;
+}
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..d42ef51
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingSession.java
@@ -0,0 +1,107 @@
+/*
+ * 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.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. */
+    @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/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());
+    }
+}