[remoteauth] Implement RangingManager
* Add basic functionalities to RangingManager and related data classes.
Test: atest RemoteAuthUnitTests
Bug: 292549287, 290675814
Change-Id: I2ebd5c7afbfc04499ef8e8f830e4a44b52332d69
diff --git a/remoteauth/service/Android.bp b/remoteauth/service/Android.bp
index 3486d8c..c7e5419 100644
--- a/remoteauth/service/Android.bp
+++ b/remoteauth/service/Android.bp
@@ -47,6 +47,7 @@
"modules-utils-preconditions",
"modules-utils-backgroundthread",
"presence-lite-protos",
+ "uwb_androidx_backend",
],
sdk_version: "system_server_current",
// This is included in service-connectivity which is 30+
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingCapabilities.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingCapabilities.java
index 2b5efff..36aa585 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingCapabilities.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingCapabilities.java
@@ -15,6 +15,9 @@
*/
package com.android.server.remoteauth.ranging;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
import androidx.annotation.IntDef;
import com.google.common.collect.ImmutableList;
@@ -43,6 +46,8 @@
public static final int RANGING_METHOD_UWB = 0x1;
private final ImmutableList<Integer> mSupportedRangingMethods;
+ private final androidx.core.uwb.backend.impl.internal.RangingCapabilities
+ mUwbRangingCapabilities;
/**
* Gets the list of supported ranging methods of the device.
@@ -53,13 +58,28 @@
return mSupportedRangingMethods;
}
- private RangingCapabilities(List<Integer> supportedRangingMethods) {
+ /**
+ * Gets the UWB ranging capabilities of the device.
+ *
+ * @return UWB ranging capabilities, null if UWB is not a supported {@link RangingMethod} in
+ * {@link #getSupportedRangingMethods}.
+ */
+ @Nullable
+ public androidx.core.uwb.backend.impl.internal.RangingCapabilities getUwbRangingCapabilities() {
+ return mUwbRangingCapabilities;
+ }
+
+ private RangingCapabilities(
+ List<Integer> supportedRangingMethods,
+ androidx.core.uwb.backend.impl.internal.RangingCapabilities uwbRangingCapabilities) {
mSupportedRangingMethods = ImmutableList.copyOf(supportedRangingMethods);
+ mUwbRangingCapabilities = uwbRangingCapabilities;
}
/** Builder class for {@link RangingCapabilities}. */
public static final class Builder {
private List<Integer> mSupportedRangingMethods = new ArrayList<>();
+ private androidx.core.uwb.backend.impl.internal.RangingCapabilities mUwbRangingCapabilities;
/** Adds a supported {@link RangingMethod} */
public Builder addSupportedRangingMethods(@RangingMethod int rangingMethod) {
@@ -67,9 +87,18 @@
return this;
}
+ /** Sets the uwb ranging capabilities. */
+ public Builder setUwbRangingCapabilities(
+ @NonNull
+ androidx.core.uwb.backend.impl.internal.RangingCapabilities
+ uwbRangingCapabilities) {
+ mUwbRangingCapabilities = uwbRangingCapabilities;
+ return this;
+ }
+
/** Builds {@link RangingCapabilities}. */
public RangingCapabilities build() {
- return new RangingCapabilities(mSupportedRangingMethods);
+ return new RangingCapabilities(mSupportedRangingMethods, mUwbRangingCapabilities);
}
}
}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingManager.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingManager.java
index 989b5ed..5a41aac 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingManager.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/RangingManager.java
@@ -15,7 +15,18 @@
*/
package com.android.server.remoteauth.ranging;
+import static android.content.pm.PackageManager.FEATURE_UWB;
+
+import static com.android.server.remoteauth.ranging.RangingCapabilities.RANGING_METHOD_UWB;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
+import android.os.Build;
+import android.util.Log;
+
+import androidx.core.uwb.backend.impl.internal.UwbFeatureFlags;
+import androidx.core.uwb.backend.impl.internal.UwbServiceImpl;
/**
* Manages the creation of generic device to device ranging session and obtaining device's ranging
@@ -25,16 +36,46 @@
* outside of this class.
*/
public class RangingManager {
+ private static final String TAG = "RangingManager";
- public RangingManager(Context context) {}
+ private Context mContext;
+ @NonNull private RangingCapabilities mCachedRangingCapabilities;
+ @NonNull private UwbServiceImpl mUwbServiceImpl;
+
+ public RangingManager(@NonNull Context context) {
+ mContext = context;
+ if (mContext.getPackageManager().hasSystemFeature(FEATURE_UWB)) {
+ initiateUwb();
+ }
+ }
+
+ /**
+ * Shutdown and stop all listeners and tasks. After shutdown, RangingManager shall not be used
+ * anymore.
+ */
+ public void shutdown() {
+ if (mUwbServiceImpl != null) {
+ mUwbServiceImpl.shutdown();
+ }
+ Log.i(TAG, "shutdown");
+ }
/**
* Gets the {@link RangingCapabilities} of this device.
*
* @return RangingCapabilities.
*/
+ @NonNull
public RangingCapabilities getRangingCapabilities() {
- return null;
+ if (mCachedRangingCapabilities == null) {
+ RangingCapabilities.Builder builder = new RangingCapabilities.Builder();
+ if (mUwbServiceImpl != null) {
+ builder.addSupportedRangingMethods(RANGING_METHOD_UWB);
+ builder.setUwbRangingCapabilities(mUwbServiceImpl.getRangingCapabilities());
+ }
+ mCachedRangingCapabilities = builder.build();
+ }
+ return mCachedRangingCapabilities;
}
/**
@@ -42,9 +83,23 @@
* provided based on the rangingCapabilities of the device.
*
* @param sessionParameters parameters used to setup the session.
- * @return the created RangingSession.
+ * @return the created RangingSession. Null if session creation failed.
*/
- public RangingSession createSession(SessionParameters sessionParameters) {
+ @Nullable
+ public RangingSession createSession(@NonNull SessionParameters sessionParameters) {
return null;
}
+
+ /** Initiation required for ranging with UWB. */
+ private void initiateUwb() {
+ UwbFeatureFlags uwbFeatureFlags =
+ new UwbFeatureFlags.Builder()
+ .setSkipRangingCapabilitiesCheck(
+ Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2)
+ .setReversedByteOrderFiraParams(
+ Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU)
+ .build();
+ mUwbServiceImpl = new UwbServiceImpl(mContext, uwbFeatureFlags);
+ Log.i(TAG, "RangingManager initiateUwb complete");
+ }
}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionInfo.java b/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionInfo.java
index 5e4fc48..0ec640c 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionInfo.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/ranging/SessionInfo.java
@@ -41,6 +41,16 @@
mRangingMethod = rangingMethod;
}
+ @Override
+ public String toString() {
+ return "SessionInfo { "
+ + "DeviceId = "
+ + mDeviceId
+ + "RangingMethod = "
+ + mRangingMethod
+ + " }";
+ }
+
/** Builder class for {@link SessionInfo}. */
public static final class Builder {
private String mDeviceId = "";
diff --git a/remoteauth/tests/unit/Android.bp b/remoteauth/tests/unit/Android.bp
index 4b92d84..629d360 100644
--- a/remoteauth/tests/unit/Android.bp
+++ b/remoteauth/tests/unit/Android.bp
@@ -35,13 +35,20 @@
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
+ "com.uwb.support.generic",
"framework-remoteauth-static",
"junit",
"libprotobuf-java-lite",
+ "mockito-target-extended-minus-junit4",
"platform-test-annotations",
"service-remoteauth-pre-jarjar",
"truth-prebuilt",
],
+ // these are needed for Extended Mockito
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
test_suites: [
"general-tests",
"mts-tethering",
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
index e6b6e3b..8135b4f 100644
--- a/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingCapabilitiesTest.java
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingCapabilitiesTest.java
@@ -28,16 +28,25 @@
/** Unit test for {@link RangingCapabilities}. */
@RunWith(AndroidJUnit4.class)
public class RangingCapabilitiesTest {
+ private static final androidx.core.uwb.backend.impl.internal.RangingCapabilities
+ TEST_UWB_RANGING_CAPABILITIES =
+ new androidx.core.uwb.backend.impl.internal.RangingCapabilities(
+ /* supportsDistance= */ true,
+ /* supportsAzimuthalAngle= */ true,
+ /* supportsElevationAngle= */ true);
@Test
public void testBuildingRangingCapabilities_success() {
final RangingCapabilities rangingCapabilities =
new RangingCapabilities.Builder()
.addSupportedRangingMethods(RANGING_METHOD_UWB)
+ .setUwbRangingCapabilities(TEST_UWB_RANGING_CAPABILITIES)
.build();
assertEquals(rangingCapabilities.getSupportedRangingMethods().size(), 1);
assertEquals(
(int) rangingCapabilities.getSupportedRangingMethods().get(0), RANGING_METHOD_UWB);
+ assertEquals(
+ rangingCapabilities.getUwbRangingCapabilities(), TEST_UWB_RANGING_CAPABILITIES);
}
}
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingManagerTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingManagerTest.java
new file mode 100644
index 0000000..609809f
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/ranging/RangingManagerTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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 android.content.pm.PackageManager.FEATURE_UWB;
+import static android.uwb.UwbManager.AdapterStateCallback.STATE_ENABLED_INACTIVE;
+
+import static androidx.core.uwb.backend.impl.internal.RangingCapabilities.FIRA_DEFAULT_SUPPORTED_CONFIG_IDS;
+import static androidx.core.uwb.backend.impl.internal.Utils.CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR;
+import static androidx.core.uwb.backend.impl.internal.Utils.CONFIG_PROVISIONED_MULTICAST_DS_TWR;
+import static androidx.core.uwb.backend.impl.internal.Utils.CONFIG_PROVISIONED_UNICAST_DS_TWR;
+import static androidx.core.uwb.backend.impl.internal.Utils.CONFIG_PROVISIONED_UNICAST_DS_TWR_NO_AOA;
+
+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.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.uwb.UwbManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.google.uwb.support.fira.FiraParams;
+import com.google.uwb.support.fira.FiraSpecificationParams;
+import com.google.uwb.support.generic.GenericSpecificationParams;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+/** Unit test for {@link RangingManager}. */
+@RunWith(AndroidJUnit4.class)
+public class RangingManagerTest {
+ private static final List<Integer> TEST_UWB_SUPPORTED_CHANNELS = List.of(8, 9);
+ private static final FiraSpecificationParams TEST_FIRA_SPEC =
+ new FiraSpecificationParams.Builder()
+ .setSupportedChannels(TEST_UWB_SUPPORTED_CHANNELS)
+ .setStsCapabilities(EnumSet.allOf(FiraParams.StsCapabilityFlag.class))
+ .build();
+ private static final GenericSpecificationParams TEST_GENERIC_SPEC =
+ new GenericSpecificationParams.Builder()
+ .setFiraSpecificationParams(TEST_FIRA_SPEC)
+ .build();
+
+ @Mock private Context mContext;
+ @Mock private PackageManager mPackageManager;
+ @Mock private UwbManager mUwbManager;
+
+ private RangingManager mRangingManager;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mContext.getSystemService(UwbManager.class)).thenReturn(mUwbManager);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.hasSystemFeature(FEATURE_UWB)).thenReturn(false);
+ when(mUwbManager.getAdapterState()).thenReturn(STATE_ENABLED_INACTIVE);
+ when(mUwbManager.getSpecificationInfo()).thenReturn(TEST_GENERIC_SPEC.toBundle());
+ }
+
+ @Test
+ public void testConstruction() {
+ mRangingManager = new RangingManager(mContext);
+ verifyZeroInteractions(mUwbManager);
+ }
+
+ @Test
+ public void testConstruction_withUwbEnabled() {
+ when(mPackageManager.hasSystemFeature(FEATURE_UWB)).thenReturn(true);
+
+ mRangingManager = new RangingManager(mContext);
+
+ verify(mUwbManager).getAdapterState();
+ verify(mUwbManager).registerAdapterStateCallback(any(), any());
+ }
+
+ @Test
+ public void testShutdown_withUwbEnabled() {
+ when(mPackageManager.hasSystemFeature(FEATURE_UWB)).thenReturn(true);
+
+ mRangingManager = new RangingManager(mContext);
+ mRangingManager.shutdown();
+
+ verify(mUwbManager).registerAdapterStateCallback(any(), any());
+ verify(mUwbManager).unregisterAdapterStateCallback(any());
+ }
+
+ @Test
+ public void testGetRangingCapabilities() {
+ mRangingManager = new RangingManager(mContext);
+ RangingCapabilities capabilities = mRangingManager.getRangingCapabilities();
+
+ assertEquals(capabilities.getSupportedRangingMethods().size(), 0);
+ assertEquals(capabilities.getUwbRangingCapabilities(), null);
+ }
+
+ @Test
+ public void testGetRangingCapabilities_withUwbEnabled() {
+ when(mPackageManager.hasSystemFeature(FEATURE_UWB)).thenReturn(true);
+
+ mRangingManager = new RangingManager(mContext);
+ RangingCapabilities capabilities = mRangingManager.getRangingCapabilities();
+
+ List<Integer> supportedConfigIds = new ArrayList<>(FIRA_DEFAULT_SUPPORTED_CONFIG_IDS);
+ supportedConfigIds.add(CONFIG_PROVISIONED_UNICAST_DS_TWR);
+ supportedConfigIds.add(CONFIG_PROVISIONED_MULTICAST_DS_TWR);
+ supportedConfigIds.add(CONFIG_PROVISIONED_UNICAST_DS_TWR_NO_AOA);
+ supportedConfigIds.add(CONFIG_PROVISIONED_INDIVIDUAL_MULTICAST_DS_TWR);
+
+ verify(mUwbManager, times(1)).getSpecificationInfo();
+ assertEquals(capabilities.getSupportedRangingMethods().size(), 1);
+ assertEquals((int) capabilities.getSupportedRangingMethods().get(0), RANGING_METHOD_UWB);
+ androidx.core.uwb.backend.impl.internal.RangingCapabilities uwbCapabilities =
+ capabilities.getUwbRangingCapabilities();
+ assertNotNull(uwbCapabilities);
+ assertArrayEquals(
+ uwbCapabilities.getSupportedChannels().toArray(),
+ TEST_UWB_SUPPORTED_CHANNELS.toArray());
+ assertArrayEquals(
+ uwbCapabilities.getSupportedConfigIds().toArray(), supportedConfigIds.toArray());
+ }
+
+ @Test
+ public void testGetRangingCapabilities_multipleCalls() {
+ when(mPackageManager.hasSystemFeature(FEATURE_UWB)).thenReturn(true);
+
+ mRangingManager = new RangingManager(mContext);
+ RangingCapabilities capabilities1 = mRangingManager.getRangingCapabilities();
+ RangingCapabilities capabilities2 = mRangingManager.getRangingCapabilities();
+ RangingCapabilities capabilities3 = mRangingManager.getRangingCapabilities();
+
+ verify(mUwbManager, times(1)).getSpecificationInfo();
+ assertEquals(capabilities1, capabilities2);
+ assertEquals(capabilities2, capabilities3);
+ }
+}