[remoteauth] Implement RangingManager

* Add basic functionalities to RangingManager and related data classes.

Test: atest RemoteAuthUnitTests
Bug: 292549287, 290675814
Change-Id: I2ebd5c7afbfc04499ef8e8f830e4a44b52332d69
This commit is contained in:
Jin Chen 2023-08-07 15:58:20 -07:00
commit be08f54a25
7 changed files with 282 additions and 6 deletions

View file

@ -47,6 +47,7 @@ java_library {
"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+

View file

@ -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 class RangingCapabilities {
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 @@ public class RangingCapabilities {
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 @@ public class RangingCapabilities {
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);
}
}
}

View file

@ -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 @@ import android.content.Context;
* 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 @@ public class RangingManager {
* 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");
}
}

View file

@ -41,6 +41,16 @@ public class SessionInfo {
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 = "";

View file

@ -35,13 +35,20 @@ android_test {
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",

View file

@ -28,16 +28,25 @@ import org.junit.runner.RunWith;
/** 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);
}
}

View file

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