getAllAssociations() {
+ if (mCompanionDeviceManager == null) {
+ try {
+ mCompanionDeviceManager = mContext.getSystemService(CompanionDeviceManager.class);
+ } catch (NullPointerException e) {
+ Log.e(TAG, "CompanionDeviceManager service does not exist: " + e);
+ return null;
+ }
+ }
+
+ try {
+ return mCompanionDeviceManager.getAllAssociations();
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to get CompanionDeviceManager associations: " + e.getMessage());
+ }
+ return null;
+ }
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/connectivity/Connection.java b/remoteauth/service/java/com/android/server/remoteauth/connectivity/Connection.java
index eb5458d315..dca8b9ff36 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/connectivity/Connection.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/connectivity/Connection.java
@@ -25,7 +25,6 @@ import java.lang.annotation.RetentionPolicy;
* A connection with the peer device.
*
* Connections are used to exchange data with the peer device.
- *
*/
public interface Connection {
/** Unknown error. */
diff --git a/remoteauth/service/java/com/android/server/remoteauth/connectivity/ConnectionInfo.java b/remoteauth/service/java/com/android/server/remoteauth/connectivity/ConnectionInfo.java
index 39bfa8d81c..6e0edb4b90 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/connectivity/ConnectionInfo.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/connectivity/ConnectionInfo.java
@@ -28,9 +28,10 @@ import java.util.Objects;
*
Connection information captures the details of underlying connection such as connection id,
* type of connection and peer device mac address.
*
+ * @param connection params per connection type.
*/
// TODO(b/295407748) Change to use @DataClass.
-public abstract class ConnectionInfo implements Parcelable {
+public abstract class ConnectionInfo implements Parcelable {
int mConnectionId;
public ConnectionInfo(int connectionId) {
@@ -85,4 +86,9 @@ public abstract class ConnectionInfo implements Parcelable {
public int hashCode() {
return Objects.hash(mConnectionId);
}
+
+ /**
+ * Returns connection related parameters.
+ */
+ public abstract T getConnectionParams();
}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/connectivity/ConnectivityManager.java b/remoteauth/service/java/com/android/server/remoteauth/connectivity/ConnectivityManager.java
index bc0d77e830..7b3028596d 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/connectivity/ConnectivityManager.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/connectivity/ConnectivityManager.java
@@ -23,9 +23,7 @@ import android.annotation.Nullable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-/**
- * Performs discovery and triggers a connection to an associated device.
- */
+/** Performs discovery and triggers a connection to an associated device. */
public interface ConnectivityManager {
/**
* Starts device discovery.
@@ -63,8 +61,12 @@ public interface ConnectivityManager {
/** Reason codes for connect failure. */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({ERROR_REASON_UNKNOWN, ERROR_CONNECTION_TIMED_OUT, ERROR_CONNECTION_REFUSED,
- ERROR_DEVICE_UNAVAILABLE})
+ @IntDef({
+ ERROR_REASON_UNKNOWN,
+ ERROR_CONNECTION_TIMED_OUT,
+ ERROR_CONNECTION_REFUSED,
+ ERROR_DEVICE_UNAVAILABLE
+ })
@interface ReasonCode {}
/**
diff --git a/remoteauth/service/java/com/android/server/remoteauth/connectivity/ConnectivityManagerFactory.java b/remoteauth/service/java/com/android/server/remoteauth/connectivity/ConnectivityManagerFactory.java
new file mode 100644
index 0000000000..3407fca779
--- /dev/null
+++ b/remoteauth/service/java/com/android/server/remoteauth/connectivity/ConnectivityManagerFactory.java
@@ -0,0 +1,51 @@
+/*
+ * 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.connectivity;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Factory class to create different types of connectivity managers based on the underlying
+ * network transports (for example CompanionDeviceManager).
+ */
+public final class ConnectivityManagerFactory {
+ private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();
+
+ /**
+ * Creates and returns a ConnectivityManager object depending on connection type.
+ *
+ * @param context of the caller.
+ * @return ConnectivityManager object.
+ */
+ public static ConnectivityManager getConnectivityManager(@NonNull Context context) {
+ Preconditions.checkNotNull(context);
+
+ // For now, we only have one case, but ideally this should create a new type based on some
+ // feature flag.
+ return new CdmConnectivityManager(EXECUTOR, new CompanionDeviceManagerWrapper(
+ new WeakReference<>(context.getApplicationContext()).get()));
+ }
+
+ private ConnectivityManagerFactory() {}
+}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/connectivity/DiscoveredDevice.java b/remoteauth/service/java/com/android/server/remoteauth/connectivity/DiscoveredDevice.java
index a3e1e589f1..8cad3eb387 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/connectivity/DiscoveredDevice.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/connectivity/DiscoveredDevice.java
@@ -25,8 +25,7 @@ public final class DiscoveredDevice {
private @NonNull ConnectionInfo mConnectionInfo;
private @Nullable String mDisplayName;
- public DiscoveredDevice(
- @NonNull ConnectionInfo connectionInfo, @Nullable String displayName) {
+ public DiscoveredDevice(@NonNull ConnectionInfo connectionInfo, @Nullable String displayName) {
this.mConnectionInfo = connectionInfo;
this.mDisplayName = displayName;
}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/connectivity/DiscoveryFilter.java b/remoteauth/service/java/com/android/server/remoteauth/connectivity/DiscoveryFilter.java
index 36c4b60a71..3590f2056a 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/connectivity/DiscoveryFilter.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/connectivity/DiscoveryFilter.java
@@ -31,7 +31,6 @@ import java.lang.annotation.RetentionPolicy;
* the filter criteria (device type, name or peer address).
*/
public final class DiscoveryFilter {
-
/** Device type WATCH. */
public static final int WATCH = 0;
@@ -86,7 +85,7 @@ public final class DiscoveryFilter {
private Builder() {}
/** Static method to create a new builder */
- public static Builder newInstance() {
+ public static Builder builder() {
return new Builder();
}
diff --git a/remoteauth/service/java/com/android/server/remoteauth/connectivity/EventListener.java b/remoteauth/service/java/com/android/server/remoteauth/connectivity/EventListener.java
index 8ec851a096..eaf57e0d3a 100644
--- a/remoteauth/service/java/com/android/server/remoteauth/connectivity/EventListener.java
+++ b/remoteauth/service/java/com/android/server/remoteauth/connectivity/EventListener.java
@@ -18,9 +18,7 @@ package com.android.server.remoteauth.connectivity;
import android.annotation.NonNull;
-/**
- * Listens to the events from underlying transport.
- */
+/** Listens to the events from underlying transport. */
public interface EventListener {
/** Called when remote device is disconnected from the underlying transport. */
void onDisconnect(@NonNull ConnectionInfo connectionInfo);
diff --git a/remoteauth/tests/unit/Android.bp b/remoteauth/tests/unit/Android.bp
index a21c0338d2..77e6f19368 100644
--- a/remoteauth/tests/unit/Android.bp
+++ b/remoteauth/tests/unit/Android.bp
@@ -32,17 +32,20 @@ android_test {
"android.test.base",
"android.test.mock",
"android.test.runner",
+ "framework-annotations-lib",
],
compile_multilib: "both",
static_libs: [
"androidx.test.ext.junit",
+ "androidx.test.ext.truth",
"androidx.test.rules",
"com.uwb.support.generic",
"framework-remoteauth-static",
"junit",
"libprotobuf-java-lite",
"mockito-target-extended-minus-junit4",
+ "mockito-target-minus-junit4",
"platform-test-annotations",
"service-remoteauth-pre-jarjar",
"truth",
diff --git a/remoteauth/tests/unit/AndroidManifest.xml b/remoteauth/tests/unit/AndroidManifest.xml
index 0449409119..a5294c878b 100644
--- a/remoteauth/tests/unit/AndroidManifest.xml
+++ b/remoteauth/tests/unit/AndroidManifest.xml
@@ -31,5 +31,6 @@
+ android:label="RemoteAuth Mainline Module Tests"
+ android:directBootAware="true"/>
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/connectivity/CdmConnectivityManagerTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/connectivity/CdmConnectivityManagerTest.java
new file mode 100644
index 0000000000..824344ace1
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/connectivity/CdmConnectivityManagerTest.java
@@ -0,0 +1,304 @@
+/*
+ * 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.connectivity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.companion.AssociationInfo;
+import android.companion.AssociationRequest;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/** Unit tests for {@link CdmConnectivityManager}. */
+@RunWith(AndroidJUnit4.class)
+public class CdmConnectivityManagerTest {
+ @Rule public final MockitoRule mocks = MockitoJUnit.rule();
+
+ @Mock CompanionDeviceManagerWrapper mCompanionDeviceManagerWrapper;
+
+ private CdmConnectivityManager mCdmConnectivityManager;
+ private ExecutorService mTestExecutor = Executors.newSingleThreadExecutor();
+
+ @Before
+ public void setUp() {
+ mCdmConnectivityManager =
+ new CdmConnectivityManager(mTestExecutor, mCompanionDeviceManagerWrapper);
+ }
+
+ @After
+ public void tearDown() {
+ mTestExecutor.shutdown();
+ }
+
+ @Test
+ public void testStartDiscovery_callsGetAllAssociationsOnce() throws InterruptedException {
+ mCdmConnectivityManager.startDiscovery(
+ Utils.getFakeDiscoveryFilter(), Utils.getFakeDiscoveredDeviceReceiver());
+
+ mTestExecutor.awaitTermination(1, TimeUnit.SECONDS);
+
+ verify(mCompanionDeviceManagerWrapper, times(1)).getAllAssociations();
+ }
+
+ @Test
+ public void testStartDiscovery_fetchesNoAssociations() {
+ SettableFuture future = SettableFuture.create();
+
+ when(mCompanionDeviceManagerWrapper.getAllAssociations())
+ .thenReturn(Utils.getFakeAssociationInfoList(0));
+
+ DiscoveredDeviceReceiver discoveredDeviceReceiver =
+ new DiscoveredDeviceReceiver() {
+ @Override
+ public void onDiscovered(DiscoveredDevice unused) {
+ future.set(true);
+ }
+
+ @Override
+ public void onLost(DiscoveredDevice unused) {
+ future.set(true);
+ }
+ };
+
+ mCdmConnectivityManager.startDiscovery(
+ Utils.getFakeDiscoveryFilter(), discoveredDeviceReceiver);
+
+ assertThat(future.isDone()).isFalse();
+ }
+
+ @Test
+ public void testStartDiscovery_DoesNotReturnNonWatchAssociations() throws InterruptedException {
+ SettableFuture future = SettableFuture.create();
+ DiscoveredDeviceReceiver discoveredDeviceReceiver =
+ new DiscoveredDeviceReceiver() {
+ @Override
+ public void onDiscovered(DiscoveredDevice unused) {
+ future.set(true);
+ }
+
+ @Override
+ public void onLost(DiscoveredDevice unused) {
+ future.set(true);
+ }
+ };
+
+ when(mCompanionDeviceManagerWrapper.getDeviceProfile(any(AssociationInfo.class)))
+ .thenReturn(Utils.FAKE_DEVICE_PROFILE);
+
+ mCdmConnectivityManager.startDiscovery(
+ Utils.getFakeDiscoveryFilter(), discoveredDeviceReceiver);
+
+ mTestExecutor.awaitTermination(1, TimeUnit.SECONDS);
+
+ verify(mCompanionDeviceManagerWrapper, times(1)).getAllAssociations();
+ verify(mCompanionDeviceManagerWrapper, times(0))
+ .getDeviceProfile(any(AssociationInfo.class));
+ assertThat(future.isDone()).isFalse();
+ }
+
+ @Test
+ public void testStartDiscovery_returnsOneWatchAssociation() throws InterruptedException {
+ SettableFuture future = SettableFuture.create();
+ DiscoveredDeviceReceiver discoveredDeviceReceiver =
+ new DiscoveredDeviceReceiver() {
+ @Override
+ public void onDiscovered(DiscoveredDevice unused) {
+ future.set(true);
+ }
+ };
+
+ when(mCompanionDeviceManagerWrapper.getAllAssociations())
+ .thenReturn(Utils.getFakeAssociationInfoList(1));
+ when(mCompanionDeviceManagerWrapper.getDeviceProfile(any(AssociationInfo.class)))
+ .thenReturn(AssociationRequest.DEVICE_PROFILE_WATCH);
+
+ mCdmConnectivityManager.startDiscovery(
+ Utils.getFakeDiscoveryFilter(), discoveredDeviceReceiver);
+
+ mTestExecutor.awaitTermination(1, TimeUnit.SECONDS);
+
+ verify(mCompanionDeviceManagerWrapper, times(1)).getAllAssociations();
+ verify(mCompanionDeviceManagerWrapper, times(1))
+ .getDeviceProfile(any(AssociationInfo.class));
+ assertThat(future.isDone()).isTrue();
+ }
+
+ @Test
+ public void testStartDiscovery_returnsMultipleWatchAssociations() throws InterruptedException {
+ int numAssociations = 3;
+ SettableFuture future = SettableFuture.create();
+ DiscoveredDeviceReceiver discoveredDeviceReceiver =
+ new DiscoveredDeviceReceiver() {
+ int mNumCallbacks = 0;
+
+ @Override
+ public void onDiscovered(DiscoveredDevice unused) {
+ ++mNumCallbacks;
+ if (mNumCallbacks == numAssociations) {
+ future.set(true);
+ }
+ }
+ };
+
+ when(mCompanionDeviceManagerWrapper.getAllAssociations())
+ .thenReturn(Utils.getFakeAssociationInfoList(numAssociations));
+ when(mCompanionDeviceManagerWrapper.getDeviceProfile(any(AssociationInfo.class)))
+ .thenReturn(AssociationRequest.DEVICE_PROFILE_WATCH);
+
+ mCdmConnectivityManager.startDiscovery(
+ Utils.getFakeDiscoveryFilter(), discoveredDeviceReceiver);
+
+ mTestExecutor.awaitTermination(1, TimeUnit.SECONDS);
+
+ verify(mCompanionDeviceManagerWrapper, times(1)).getAllAssociations();
+ verify(mCompanionDeviceManagerWrapper, times(numAssociations))
+ .getDeviceProfile(any(AssociationInfo.class));
+ assertThat(future.isDone()).isTrue();
+ }
+
+ @Test
+ public void testMultipleStartDiscovery_runsAllCallbacks() throws InterruptedException {
+ SettableFuture future1 = SettableFuture.create();
+ SettableFuture future2 = SettableFuture.create();
+ DiscoveredDeviceReceiver discoveredDeviceReceiver1 =
+ new DiscoveredDeviceReceiver() {
+ @Override
+ public void onDiscovered(DiscoveredDevice unused) {
+ future1.set(true);
+ }
+ };
+ DiscoveredDeviceReceiver discoveredDeviceReceiver2 =
+ new DiscoveredDeviceReceiver() {
+ @Override
+ public void onDiscovered(DiscoveredDevice unused) {
+ future2.set(true);
+ }
+ };
+
+ when(mCompanionDeviceManagerWrapper.getAllAssociations())
+ .thenReturn(Utils.getFakeAssociationInfoList(1));
+ when(mCompanionDeviceManagerWrapper.getDeviceProfile(any(AssociationInfo.class)))
+ .thenReturn(AssociationRequest.DEVICE_PROFILE_WATCH);
+
+ // Start discovery twice with different callbacks.
+ mCdmConnectivityManager.startDiscovery(
+ Utils.getFakeDiscoveryFilter(), discoveredDeviceReceiver1);
+ mCdmConnectivityManager.startDiscovery(
+ Utils.getFakeDiscoveryFilter(), discoveredDeviceReceiver2);
+
+ mTestExecutor.awaitTermination(1, TimeUnit.SECONDS);
+
+ verify(mCompanionDeviceManagerWrapper, times(2)).getAllAssociations();
+ verify(mCompanionDeviceManagerWrapper, times(2))
+ .getDeviceProfile(any(AssociationInfo.class));
+ assertThat(future1.isDone()).isTrue();
+ assertThat(future2.isDone()).isTrue();
+ }
+
+ @Test
+ public void testStartDiscovery_returnsExpectedDiscoveredDevice() throws InterruptedException {
+ SettableFuture future = SettableFuture.create();
+ DiscoveredDeviceReceiver discoveredDeviceReceiver =
+ new DiscoveredDeviceReceiver() {
+ @Override
+ public void onDiscovered(DiscoveredDevice device) {
+ assertThat(device.getConnectionInfo() instanceof CdmConnectionInfo)
+ .isTrue();
+
+ CdmConnectionInfo connectionInfo =
+ (CdmConnectionInfo) device.getConnectionInfo();
+ if (connectionInfo.getConnectionParams().getDeviceMacAddress().toString()
+ .equals(Utils.FAKE_PEER_ADDRESS)
+ && connectionInfo.getConnectionId() == Utils.FAKE_CONNECTION_ID) {
+ future.set(true);
+ }
+ }
+ };
+
+ when(mCompanionDeviceManagerWrapper.getAllAssociations())
+ .thenReturn(Utils.getFakeAssociationInfoList(1));
+ when(mCompanionDeviceManagerWrapper.getDeviceProfile(any(AssociationInfo.class)))
+ .thenReturn(AssociationRequest.DEVICE_PROFILE_WATCH);
+
+ mCdmConnectivityManager.startDiscovery(
+ Utils.getFakeDiscoveryFilter(), discoveredDeviceReceiver);
+
+ mTestExecutor.awaitTermination(1, TimeUnit.SECONDS);
+
+ verify(mCompanionDeviceManagerWrapper, times(1)).getAllAssociations();
+ verify(mCompanionDeviceManagerWrapper, times(1))
+ .getDeviceProfile(any(AssociationInfo.class));
+ assertThat(future.isDone()).isTrue();
+ }
+
+ @Test
+ public void testStopDiscovery_removesCallback() {
+ DiscoveredDeviceReceiver discoveredDeviceReceiver =
+ new DiscoveredDeviceReceiver() {
+ @Override
+ public void onDiscovered(DiscoveredDevice unused) {}
+ };
+
+ DiscoveryFilter discoveryFilter = Utils.getFakeDiscoveryFilter();
+ mCdmConnectivityManager.startDiscovery(discoveryFilter, discoveredDeviceReceiver);
+
+ assertThat(mCdmConnectivityManager.hasPendingCallbacks(discoveredDeviceReceiver)).isTrue();
+
+ mCdmConnectivityManager.stopDiscovery(discoveryFilter, discoveredDeviceReceiver);
+
+ assertThat(mCdmConnectivityManager.hasPendingCallbacks(discoveredDeviceReceiver)).isFalse();
+ }
+
+ @Test
+ public void testStopDiscovery_DoesNotRunCallback() {
+ SettableFuture future = SettableFuture.create();
+ DiscoveredDeviceReceiver discoveredDeviceReceiver =
+ new DiscoveredDeviceReceiver() {
+ @Override
+ public void onDiscovered(DiscoveredDevice unused) {
+ future.set(true);
+ }
+ };
+
+ DiscoveryFilter discoveryFilter = Utils.getFakeDiscoveryFilter();
+ mCdmConnectivityManager.startDiscovery(discoveryFilter, discoveredDeviceReceiver);
+ mCdmConnectivityManager.stopDiscovery(discoveryFilter, discoveredDeviceReceiver);
+
+ assertThat(future.isDone()).isFalse();
+ }
+}
+
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/connectivity/ConnectivityManagerFactoryTest.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/connectivity/ConnectivityManagerFactoryTest.java
new file mode 100644
index 0000000000..42eff90561
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/connectivity/ConnectivityManagerFactoryTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.connectivity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link CdmConnectivityManager}. */
+@RunWith(AndroidJUnit4.class)
+public class ConnectivityManagerFactoryTest {
+
+ @Before
+ public void setUp() {}
+
+ @Test
+ public void testFactory_returnsConnectivityManager() {
+ final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ ConnectivityManager connectivityManager =
+ ConnectivityManagerFactory.getConnectivityManager(context);
+
+ assertThat(connectivityManager).isNotNull();
+ }
+}
diff --git a/remoteauth/tests/unit/src/com/android/server/remoteauth/connectivity/Utils.java b/remoteauth/tests/unit/src/com/android/server/remoteauth/connectivity/Utils.java
new file mode 100644
index 0000000000..a5c992a1f2
--- /dev/null
+++ b/remoteauth/tests/unit/src/com/android/server/remoteauth/connectivity/Utils.java
@@ -0,0 +1,99 @@
+/*
+ * 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.connectivity;
+
+import android.companion.AssociationInfo;
+import android.companion.AssociationRequest;
+import android.content.pm.PackageManager;
+import android.net.MacAddress;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class Utils {
+ public static final int FAKE_CONNECTION_ID = 1;
+ public static final int FAKE_USER_ID = 0;
+ public static final String FAKE_DISPLAY_NAME = "FAKE-DISPLAY-NAME";
+ public static final String FAKE_PEER_ADDRESS = "ff:ff:ff:ff:ff:ff";
+ public static final String FAKE_DEVICE_PROFILE = "FAKE-DEVICE-PROFILE";
+ public static final String FAKE_PACKAGE_NAME = "FAKE-PACKAGE-NAME";
+
+ public static DiscoveryFilter getFakeDiscoveryFilter() {
+ return DiscoveryFilter.Builder.builder()
+ .setDeviceName(FAKE_DISPLAY_NAME)
+ .setPeerAddress("FAKE-PEER-ADDRESS")
+ .setDeviceType(DiscoveryFilter.WATCH)
+ .build();
+ }
+
+ public static DiscoveredDeviceReceiver getFakeDiscoveredDeviceReceiver() {
+ return new DiscoveredDeviceReceiver() {
+ @Override
+ public void onDiscovered(DiscoveredDevice unused) {}
+
+ @Override
+ public void onLost(DiscoveredDevice unused) {}
+ };
+ }
+
+ /**
+ * Returns a fake CDM connection info.
+ *
+ * @return connection info.
+ */
+ public static CdmConnectionInfo getFakeCdmConnectionInfo()
+ throws PackageManager.NameNotFoundException {
+ return new CdmConnectionInfo(FAKE_CONNECTION_ID, getFakeAssociationInfoList(1).get(0));
+ }
+
+ /**
+ * Returns a fake discovered device.
+ *
+ * @return discovered device.
+ */
+ public static DiscoveredDevice getFakeCdmDiscoveredDevice()
+ throws PackageManager.NameNotFoundException {
+ return new DiscoveredDevice(getFakeCdmConnectionInfo(), FAKE_DISPLAY_NAME);
+ }
+
+ /**
+ * Returns fake association info array.
+ *
+ * Creates an AssociationInfo object with fake values.
+ *
+ * @param associationsSize number of fake association info entries to return.
+ * @return list of {@link AssociationInfo} or null.
+ */
+ public static List getFakeAssociationInfoList(int associationsSize) {
+ if (associationsSize > 0) {
+ List associations = new ArrayList<>();
+ // Association id starts from 1.
+ for (int i = 1; i <= associationsSize; ++i) {
+ associations.add(
+ (new AssociationInfo.Builder(i, FAKE_USER_ID, FAKE_PACKAGE_NAME))
+ .setDeviceProfile(AssociationRequest.DEVICE_PROFILE_WATCH)
+ .setDisplayName(FAKE_DISPLAY_NAME)
+ .setDeviceMacAddress(MacAddress.fromString(FAKE_PEER_ADDRESS))
+ .build());
+ }
+ return associations;
+ }
+ return new ArrayList<>();
+ }
+
+ private Utils() {}
+}
diff --git a/service/ServiceConnectivityResources/res/values-as/strings.xml b/service/ServiceConnectivityResources/res/values-as/strings.xml
index 7e4dd42bf5..e753cb3bf2 100644
--- a/service/ServiceConnectivityResources/res/values-as/strings.xml
+++ b/service/ServiceConnectivityResources/res/values-as/strings.xml
@@ -18,7 +18,7 @@
"ছিষ্টেম সংযোগৰ উৎস"
- "Wi-Fi নেটৱৰ্কত ছাইন ইন কৰক"
+ "ৱাই-ফাই নেটৱৰ্কত ছাইন ইন কৰক"
"নেটৱৰ্কত ছাইন ইন কৰক"
diff --git a/service/ServiceConnectivityResources/res/values-kn/strings.xml b/service/ServiceConnectivityResources/res/values-kn/strings.xml
index 8046d0eb8a..98a2d9c825 100644
--- a/service/ServiceConnectivityResources/res/values-kn/strings.xml
+++ b/service/ServiceConnectivityResources/res/values-kn/strings.xml
@@ -30,7 +30,7 @@
"%1$s ಸೀಮಿತ ಸಂಪರ್ಕ ಕಲ್ಪಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿದೆ"
"ಹೇಗಾದರೂ ಸಂಪರ್ಕಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"
"%1$s ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"
- "%2$s ಇಂಟರ್ನೆಟ್ ಆ್ಯಕ್ಸೆಸ್ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು %1$s ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."
+ "%2$s ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು %1$s ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."
"%1$s ರಿಂದ %2$s ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"
- "ಮೊಬೈಲ್ ಡೇಟಾ"