Create SimRepository

Which unifies whether we should sim settings on some related pages.

Before this change, we check SubscriptionUtil.isSimHardwareVisible()
and / or Utils.isWifiOnly().

After this change, we unified logic to,
canChangeSimSettings() =
  packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) &&
    userManager.isAdminUser

Fix: 365924140
Flag: EXEMPT bug fix
Test: manual - check Network & internet
Test: unit tests
Change-Id: Ibf83237e3d0088f78c96a1b39ee8f1e3a9c756ea
diff --git a/src/com/android/settings/network/MobileNetworkListFragment.kt b/src/com/android/settings/network/MobileNetworkListFragment.kt
index bb88330..d110779 100644
--- a/src/com/android/settings/network/MobileNetworkListFragment.kt
+++ b/src/com/android/settings/network/MobileNetworkListFragment.kt
@@ -27,13 +27,13 @@
 import com.android.settings.SettingsPreferenceFragment
 import com.android.settings.dashboard.DashboardFragment
 import com.android.settings.flags.Flags
+import com.android.settings.network.telephony.SimRepository
 import com.android.settings.network.telephony.euicc.EuiccRepository
 import com.android.settings.search.BaseSearchIndexProvider
 import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
 import com.android.settings.spa.network.NetworkCellularGroupProvider
 import com.android.settingslib.search.SearchIndexable
 import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
-import com.android.settingslib.spaprivileged.framework.common.userManager
 import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBooleanFlow
 
 @SearchIndexable(forTarget = SearchIndexable.ALL and SearchIndexable.ARC.inv())
@@ -85,10 +85,11 @@
         val SEARCH_INDEX_DATA_PROVIDER = SearchIndexProvider()
 
         @VisibleForTesting
-        class SearchIndexProvider : BaseSearchIndexProvider(R.xml.network_provider_sims_list) {
+        class SearchIndexProvider(
+            private val simRepositoryFactory: (Context) -> SimRepository = ::SimRepository
+        ) : BaseSearchIndexProvider(R.xml.network_provider_sims_list) {
             public override fun isPageSearchEnabled(context: Context): Boolean =
-                SubscriptionUtil.isSimHardwareVisible(context) &&
-                    context.userManager.isAdminUser
+                simRepositoryFactory(context).showMobileNetworkPage()
         }
     }
 }
diff --git a/src/com/android/settings/network/MobileNetworkPreferenceController.java b/src/com/android/settings/network/MobileNetworkPreferenceController.java
deleted file mode 100644
index b49613a..0000000
--- a/src/com/android/settings/network/MobileNetworkPreferenceController.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2016 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.settings.network;
-
-import static android.os.UserHandle.myUserId;
-import static android.os.UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS;
-
-import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
-
-import static androidx.lifecycle.Lifecycle.Event;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.TelephonyCallback;
-import android.telephony.TelephonyManager;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.lifecycle.LifecycleObserver;
-import androidx.lifecycle.OnLifecycleEvent;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.network.telephony.MobileNetworkUtils;
-import com.android.settingslib.RestrictedLockUtilsInternal;
-import com.android.settingslib.RestrictedPreference;
-import com.android.settingslib.Utils;
-import com.android.settingslib.core.AbstractPreferenceController;
-
-public class MobileNetworkPreferenceController extends AbstractPreferenceController
-        implements PreferenceControllerMixin, LifecycleObserver {
-
-    @VisibleForTesting
-    static final String KEY_MOBILE_NETWORK_SETTINGS = "mobile_network_settings";
-
-    private final boolean mIsSecondaryUser;
-    private final TelephonyManager mTelephonyManager;
-    private final UserManager mUserManager;
-    private Preference mPreference;
-    @VisibleForTesting
-    MobileNetworkTelephonyCallback mTelephonyCallback;
-
-    private BroadcastReceiver mAirplanModeChangedReceiver;
-
-    public MobileNetworkPreferenceController(Context context) {
-        super(context);
-        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        mIsSecondaryUser = !mUserManager.isAdminUser();
-
-        mAirplanModeChangedReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                updateState(mPreference);
-            }
-        };
-    }
-
-    @Override
-    public boolean isAvailable() {
-        return !isUserRestricted() && !Utils.isWifiOnly(mContext);
-    }
-
-    public boolean isUserRestricted() {
-        return mIsSecondaryUser ||
-                RestrictedLockUtilsInternal.hasBaseUserRestriction(
-                        mContext,
-                        DISALLOW_CONFIG_MOBILE_NETWORKS,
-                        myUserId());
-    }
-
-    @Override
-    public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
-        mPreference = screen.findPreference(getPreferenceKey());
-    }
-
-    @Override
-    public String getPreferenceKey() {
-        return KEY_MOBILE_NETWORK_SETTINGS;
-    }
-
-    class MobileNetworkTelephonyCallback extends TelephonyCallback implements
-            TelephonyCallback.ServiceStateListener {
-        @Override
-        public void onServiceStateChanged(ServiceState serviceState) {
-            updateState(mPreference);
-        }
-    }
-
-    @OnLifecycleEvent(Event.ON_START)
-    public void onStart() {
-        if (isAvailable()) {
-            if (mTelephonyCallback == null) {
-                mTelephonyCallback = new MobileNetworkTelephonyCallback();
-            }
-            mTelephonyManager.registerTelephonyCallback(
-                    mContext.getMainExecutor(), mTelephonyCallback);
-        }
-        if (mAirplanModeChangedReceiver != null) {
-            mContext.registerReceiver(mAirplanModeChangedReceiver,
-                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
-        }
-    }
-
-    @OnLifecycleEvent(Event.ON_STOP)
-    public void onStop() {
-        if (mTelephonyCallback != null) {
-            mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
-        }
-        if (mAirplanModeChangedReceiver != null) {
-            mContext.unregisterReceiver(mAirplanModeChangedReceiver);
-        }
-    }
-
-    @Override
-    public void updateState(Preference preference) {
-        super.updateState(preference);
-
-        if (preference instanceof RestrictedPreference &&
-            ((RestrictedPreference) preference).isDisabledByAdmin()) {
-                return;
-        }
-        preference.setEnabled(Settings.Global.getInt(
-            mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 0);
-    }
-
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        if (KEY_MOBILE_NETWORK_SETTINGS.equals(preference.getKey())) {
-            final Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS);
-            intent.setPackage(SETTINGS_PACKAGE_NAME);
-            mContext.startActivity(intent);
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public CharSequence getSummary() {
-        return MobileNetworkUtils.getCurrentCarrierNameForDisplay(mContext);
-    }
-}
diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java
index 9bf6915..45d475f 100644
--- a/src/com/android/settings/network/MobileNetworkSummaryController.java
+++ b/src/com/android/settings/network/MobileNetworkSummaryController.java
@@ -21,7 +21,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.os.UserManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.euicc.EuiccManager;
 
@@ -35,10 +34,10 @@
 import com.android.settings.R;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.network.telephony.SimRepository;
 import com.android.settings.network.telephony.euicc.EuiccRepository;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.RestrictedPreference;
-import com.android.settingslib.Utils;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
@@ -56,7 +55,6 @@
     private static final String KEY = "mobile_network_list";
 
     private final MetricsFeatureProvider mMetricsFeatureProvider;
-    private UserManager mUserManager;
     private RestrictedPreference mPreference;
 
     private MobileNetworkRepository mMobileNetworkRepository;
@@ -85,7 +83,6 @@
             LifecycleOwner lifecycleOwner) {
         super(context);
         mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
-        mUserManager = context.getSystemService(UserManager.class);
         mLifecycleOwner = lifecycleOwner;
         mMobileNetworkRepository = MobileNetworkRepository.getInstance(context);
         mIsAirplaneModeOn = mMobileNetworkRepository.isAirplaneModeOn();
@@ -185,8 +182,7 @@
 
     @Override
     public boolean isAvailable() {
-        return SubscriptionUtil.isSimHardwareVisible(mContext) &&
-                !Utils.isWifiOnly(mContext) && mUserManager.isAdminUser();
+        return new SimRepository(mContext).showMobileNetworkPage();
     }
 
     @Override
diff --git a/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.java b/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.java
deleted file mode 100644
index a5c19ad..0000000
--- a/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2018 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.settings.network;
-
-import android.content.Context;
-import android.text.BidiFormatter;
-
-import com.android.settings.R;
-import com.android.settings.Utils;
-import com.android.settings.activityembedding.ActivityEmbeddingUtils;
-import com.android.settings.core.BasePreferenceController;
-
-public class TopLevelNetworkEntryPreferenceController extends BasePreferenceController {
-
-    private final MobileNetworkPreferenceController mMobileNetworkPreferenceController;
-
-    public TopLevelNetworkEntryPreferenceController(Context context, String preferenceKey) {
-        super(context, preferenceKey);
-        mMobileNetworkPreferenceController = new MobileNetworkPreferenceController(mContext);
-    }
-
-    @Override
-    public int getAvailabilityStatus() {
-        // TODO(b/281597506): Update the ActivityEmbeddingUtils.isEmbeddingActivityEnabled
-        //   while getting the new API.
-        return (Utils.isDemoUser(mContext)
-            && !ActivityEmbeddingUtils.isEmbeddingActivityEnabled(mContext))
-                ? UNSUPPORTED_ON_DEVICE : AVAILABLE;
-    }
-
-    @Override
-    public CharSequence getSummary() {
-        if (mMobileNetworkPreferenceController.isAvailable()) {
-            return BidiFormatter.getInstance()
-                    .unicodeWrap(mContext.getString(R.string.network_dashboard_summary_mobile));
-        } else {
-            return BidiFormatter.getInstance()
-                    .unicodeWrap(mContext.getString(R.string.network_dashboard_summary_no_mobile));
-        }
-    }
-}
diff --git a/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.kt b/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.kt
new file mode 100644
index 0000000..1722f6a
--- /dev/null
+++ b/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 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.settings.network
+
+import android.content.Context
+import android.text.BidiFormatter
+import com.android.settings.R
+import com.android.settings.Utils
+import com.android.settings.activityembedding.ActivityEmbeddingUtils
+import com.android.settings.core.BasePreferenceController
+import com.android.settings.network.telephony.SimRepository
+
+class TopLevelNetworkEntryPreferenceController
+@JvmOverloads
+constructor(
+    context: Context,
+    preferenceKey: String,
+    private val simRepository: SimRepository = SimRepository(context),
+    private val isDemoUser: () -> Boolean = { Utils.isDemoUser(context) },
+    private val isEmbeddingActivityEnabled: () -> Boolean = {
+        ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)
+    },
+) : BasePreferenceController(context, preferenceKey) {
+
+    override fun getAvailabilityStatus(): Int {
+        // TODO(b/281597506): Update the ActivityEmbeddingUtils.isEmbeddingActivityEnabled
+        //                    while getting the new API.
+        return if (isDemoUser() && !isEmbeddingActivityEnabled()) {
+            UNSUPPORTED_ON_DEVICE
+        } else {
+            AVAILABLE
+        }
+    }
+
+    override fun getSummary(): CharSequence {
+        val summaryResId =
+            if (simRepository.showMobileNetworkPage()) {
+                R.string.network_dashboard_summary_mobile
+            } else {
+                R.string.network_dashboard_summary_no_mobile
+            }
+        return BidiFormatter.getInstance().unicodeWrap(mContext.getString(summaryResId))
+    }
+}
diff --git a/src/com/android/settings/network/telephony/SimRepository.kt b/src/com/android/settings/network/telephony/SimRepository.kt
new file mode 100644
index 0000000..ed3c8aa
--- /dev/null
+++ b/src/com/android/settings/network/telephony/SimRepository.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.settings.network.telephony
+
+import android.content.Context
+import android.content.pm.PackageManager
+import com.android.settingslib.spaprivileged.framework.common.userManager
+
+class SimRepository(context: Context) {
+    private val packageManager = context.packageManager
+    private val userManager = context.userManager
+
+    /** Gets whether we show mobile network settings page to the current user. */
+    fun showMobileNetworkPage(): Boolean =
+        packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) && userManager.isAdminUser
+}
diff --git a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
index f76bba4..d736fe5 100644
--- a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
+++ b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
@@ -48,9 +48,9 @@
 import com.android.settings.R
 import com.android.settings.flags.Flags
 import com.android.settings.network.SubscriptionInfoListViewModel
-import com.android.settings.network.SubscriptionUtil
 import com.android.settings.network.telephony.DataSubscriptionRepository
 import com.android.settings.network.telephony.MobileDataRepository
+import com.android.settings.network.telephony.SimRepository
 import com.android.settings.network.telephony.requireSubscriptionManager
 import com.android.settings.spa.network.PrimarySimRepository.PrimarySimInfo
 import com.android.settings.spa.search.SearchablePage
@@ -66,7 +66,6 @@
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
 import com.android.settingslib.spa.widget.ui.Category
 import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverFlow
-import com.android.settingslib.spaprivileged.framework.common.userManager
 import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBooleanFlow
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
@@ -213,10 +212,7 @@
         const val fileName = "NetworkCellularGroupProvider"
 
         private fun isPageSearchable(context: Context) =
-            Flags.isDualSimOnboardingEnabled() &&
-            SubscriptionUtil.isSimHardwareVisible(context) &&
-                !com.android.settingslib.Utils.isWifiOnly(context) &&
-                context.userManager.isAdminUser
+            Flags.isDualSimOnboardingEnabled() && SimRepository(context).showMobileNetworkPage()
     }
 }
 
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
index 8d6d2d9..1823d6d 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
@@ -32,7 +32,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.os.UserManager;
 import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -73,8 +72,6 @@
     @Mock
     private PreferenceScreen mPreferenceScreen;
     @Mock
-    private UserManager mUserManager;
-    @Mock
     private MobileNetworkRepository mMobileNetworkRepository;
     @Mock
     private MobileNetworkRepository.MobileNetworkCallback mMobileNetworkCallback;
@@ -92,7 +89,6 @@
         doReturn(mTelephonyManager).when(mContext).getSystemService(TelephonyManager.class);
         doReturn(mSubscriptionManager).when(mContext).getSystemService(SubscriptionManager.class);
         doReturn(mEuiccManager).when(mContext).getSystemService(EuiccManager.class);
-        doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
         mMobileNetworkRepository = MobileNetworkRepository.getInstance(mContext);
         mLifecycleOwner = () -> mLifecycle;
         mLifecycle = new Lifecycle(mLifecycleOwner);
@@ -119,21 +115,6 @@
     }
 
     @Test
-    public void isAvailable_wifiOnlyMode_notAvailable() {
-        when(mTelephonyManager.isDataCapable()).thenReturn(false);
-        when(mUserManager.isAdminUser()).thenReturn(true);
-
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void isAvailable_secondaryUser_notAvailable() {
-        when(mTelephonyManager.isDataCapable()).thenReturn(true);
-        when(mUserManager.isAdminUser()).thenReturn(false);
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
     public void getSummary_noSubscriptions_returnSummaryCorrectly() {
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
diff --git a/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java
deleted file mode 100644
index 8e0c863..0000000
--- a/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2018 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.settings.network;
-
-import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.UserManager;
-import android.text.BidiFormatter;
-import android.util.FeatureFlagUtils;
-
-import com.android.settings.R;
-import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
-import com.android.settings.testutils.shadow.ShadowUserManager;
-import com.android.settings.testutils.shadow.ShadowUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadow.api.Shadow;
-import org.robolectric.util.ReflectionHelpers;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {
-        ShadowRestrictedLockUtilsInternal.class,
-        ShadowUtils.class,
-        ShadowUserManager.class,
-})
-public class TopLevelNetworkEntryPreferenceControllerTest {
-
-    @Mock
-    private MobileNetworkPreferenceController mMobileNetworkPreferenceController;;
-
-    private Context mContext;
-    private TopLevelNetworkEntryPreferenceController mController;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        final ShadowUserManager um = Shadow.extract(
-                RuntimeEnvironment.application.getSystemService(UserManager.class));
-        um.setIsAdminUser(true);
-
-        mController = new TopLevelNetworkEntryPreferenceController(mContext, "test_key");
-
-        ReflectionHelpers.setField(mController, "mMobileNetworkPreferenceController",
-                mMobileNetworkPreferenceController);
-    }
-
-    @After
-    public void tearDown() {
-        ShadowUtils.reset();
-    }
-
-    @Test
-    public void getAvailabilityStatus_demoUser_nonLargeScreen_unsupported() {
-        ShadowUtils.setIsDemoUser(true);
-        FeatureFlagUtils.setEnabled(mContext, "settings_support_large_screen", false);
-        assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
-    }
-
-    @Test
-    public void getSummary_hasMobile_shouldReturnMobileSummary() {
-        when(mMobileNetworkPreferenceController.isAvailable()).thenReturn(true);
-
-        assertThat(mController.getSummary()).isEqualTo(BidiFormatter.getInstance().unicodeWrap(
-                mContext.getString(R.string.network_dashboard_summary_mobile)));
-    }
-
-    @Test
-    public void getSummary_noMobile_shouldReturnNoMobileSummary() {
-        when(mMobileNetworkPreferenceController.isAvailable()).thenReturn(false);
-
-        assertThat(mController.getSummary()).isEqualTo(BidiFormatter.getInstance().unicodeWrap(
-                mContext.getString(R.string.network_dashboard_summary_no_mobile)));
-    }
-}
diff --git a/tests/spa_unit/src/com/android/settings/network/MobileNetworkListFragmentTest.kt b/tests/spa_unit/src/com/android/settings/network/MobileNetworkListFragmentTest.kt
index 3ba4bac..4bb5f2f 100644
--- a/tests/spa_unit/src/com/android/settings/network/MobileNetworkListFragmentTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/MobileNetworkListFragmentTest.kt
@@ -17,57 +17,37 @@
 package com.android.settings.network
 
 import android.content.Context
-import android.content.res.Resources
-import android.os.UserManager
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.settings.R
-import com.android.settingslib.spaprivileged.framework.common.userManager
+import com.android.settings.network.MobileNetworkListFragment.Companion.SearchIndexProvider
+import com.android.settings.network.telephony.SimRepository
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
-import org.mockito.kotlin.spy
 import org.mockito.kotlin.stub
 
 @RunWith(AndroidJUnit4::class)
 class MobileNetworkListFragmentTest {
-    private val mockUserManager = mock<UserManager>()
+    private val mockSimRepository = mock<SimRepository>()
 
-    private val mockResources = mock<Resources>()
-
-    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
-        on { userManager } doReturn mockUserManager
-        on { resources } doReturn mockResources
-    }
+    private val context: Context = ApplicationProvider.getApplicationContext()
 
     @Test
-    fun isPageSearchEnabled_adminUser_shouldReturnTrue() {
-        mockUserManager.stub {
-            on { isAdminUser } doReturn true
-        }
-        mockResources.stub {
-            on { getBoolean(R.bool.config_show_sim_info) } doReturn true
-        }
+    fun isPageSearchEnabled_showMobileNetworkPage_returnTrue() {
+        mockSimRepository.stub { on { showMobileNetworkPage() } doReturn true }
 
-        val isEnabled =
-            MobileNetworkListFragment.SEARCH_INDEX_DATA_PROVIDER.isPageSearchEnabled(context)
+        val isEnabled = SearchIndexProvider { mockSimRepository }.isPageSearchEnabled(context)
 
         assertThat(isEnabled).isTrue()
     }
 
     @Test
-    fun isPageSearchEnabled_nonAdminUser_shouldReturnFalse() {
-        mockUserManager.stub {
-            on { isAdminUser } doReturn false
-        }
-        mockResources.stub {
-            on { getBoolean(R.bool.config_show_sim_info) } doReturn true
-        }
+    fun isPageSearchEnabled_hideMobileNetworkPage_returnFalse() {
+        mockSimRepository.stub { on { showMobileNetworkPage() } doReturn false }
 
-        val isEnabled =
-            MobileNetworkListFragment.SEARCH_INDEX_DATA_PROVIDER.isPageSearchEnabled(context)
+        val isEnabled = SearchIndexProvider { mockSimRepository }.isPageSearchEnabled(context)
 
         assertThat(isEnabled).isFalse()
     }
diff --git a/tests/spa_unit/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.kt
new file mode 100644
index 0000000..27c9602
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2024 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.settings.network
+
+import android.content.Context
+import android.text.BidiFormatter
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.android.settings.core.BasePreferenceController
+import com.android.settings.network.telephony.SimRepository
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
+
+@RunWith(AndroidJUnit4::class)
+class TopLevelNetworkEntryPreferenceControllerTest {
+
+    private val mockSimRepository = mock<SimRepository>()
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    private var isDemoUser = false
+    private var isEmbeddingActivityEnabled = false
+
+    private var controller =
+        TopLevelNetworkEntryPreferenceController(
+            context = context,
+            preferenceKey = TEST_KEY,
+            simRepository = mockSimRepository,
+            isDemoUser = { isDemoUser },
+            isEmbeddingActivityEnabled = { isEmbeddingActivityEnabled },
+        )
+
+    @Test
+    fun getAvailabilityStatus_demoUser_largeScreen_unsupported() {
+        isDemoUser = true
+        isEmbeddingActivityEnabled = true
+
+        val availabilityStatus = controller.availabilityStatus
+
+        assertThat(availabilityStatus).isEqualTo(BasePreferenceController.AVAILABLE)
+    }
+
+    @Test
+    fun getAvailabilityStatus_demoUser_nonLargeScreen_unsupported() {
+        isDemoUser = true
+        isEmbeddingActivityEnabled = false
+
+        val availabilityStatus = controller.availabilityStatus
+
+        assertThat(availabilityStatus).isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE)
+    }
+
+    @Test
+    fun getSummary_hasMobile_shouldReturnMobileSummary() {
+        mockSimRepository.stub { on { showMobileNetworkPage() } doReturn true }
+
+        val summary = controller.summary
+
+        assertThat(summary)
+            .isEqualTo(
+                BidiFormatter.getInstance()
+                    .unicodeWrap(context.getString(R.string.network_dashboard_summary_mobile))
+            )
+    }
+
+    @Test
+    fun getSummary_noMobile_shouldReturnNoMobileSummary() {
+        mockSimRepository.stub { on { showMobileNetworkPage() } doReturn false }
+
+        val summary = controller.summary
+
+        assertThat(summary)
+            .isEqualTo(
+                BidiFormatter.getInstance()
+                    .unicodeWrap(context.getString(R.string.network_dashboard_summary_no_mobile))
+            )
+    }
+
+    private companion object {
+        const val TEST_KEY = "test_key"
+    }
+}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/SimRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/SimRepositoryTest.kt
new file mode 100644
index 0000000..bbcac08
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/SimRepositoryTest.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2024 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.settings.network.telephony
+
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.UserManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spaprivileged.framework.common.userManager
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
+
+@RunWith(AndroidJUnit4::class)
+class SimRepositoryTest {
+
+    private val mockUserManager = mock<UserManager>()
+
+    private val mockPackageManager = mock<PackageManager>()
+
+    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+        on { userManager } doReturn mockUserManager
+        on { packageManager } doReturn mockPackageManager
+    }
+
+    private val repository = SimRepository(context)
+
+    @Test
+    fun showMobileNetworkPage_adminUserAndHasTelephony_returnTrue() {
+        mockUserManager.stub {
+            on { isAdminUser } doReturn true
+        }
+        mockPackageManager.stub {
+            on { hasSystemFeature(PackageManager.FEATURE_TELEPHONY) } doReturn true
+        }
+
+        val showMobileNetworkPage = repository.showMobileNetworkPage()
+
+        assertThat(showMobileNetworkPage).isTrue()
+    }
+
+    @Test
+    fun showMobileNetworkPage_notAdminUser_returnFalse() {
+        mockUserManager.stub {
+            on { isAdminUser } doReturn false
+        }
+        mockPackageManager.stub {
+            on { hasSystemFeature(PackageManager.FEATURE_TELEPHONY) } doReturn true
+        }
+
+        val showMobileNetworkPage = repository.showMobileNetworkPage()
+
+        assertThat(showMobileNetworkPage).isFalse()
+    }
+
+    @Test fun showMobileNetworkPage_noTelephony_returnFalse() {
+        mockUserManager.stub {
+            on { isAdminUser } doReturn true
+        }
+        mockPackageManager.stub {
+            on { hasSystemFeature(PackageManager.FEATURE_TELEPHONY) } doReturn false
+        }
+
+        val showMobileNetworkPage = repository.showMobileNetworkPage()
+
+        assertThat(showMobileNetworkPage).isFalse()
+    }
+}
diff --git a/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java
deleted file mode 100644
index 1231c01..0000000
--- a/tests/unit/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2020 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.settings.network;
-
-import static androidx.lifecycle.Lifecycle.Event;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.Looper;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.provider.Settings.Global;
-import android.telephony.PhoneStateListener;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-
-import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.LifecycleRegistry;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceManager;
-import androidx.preference.PreferenceScreen;
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import com.android.settingslib.RestrictedPreference;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-public class MobileNetworkPreferenceControllerTest {
-    private Context mContext;
-    @Mock
-    private TelephonyManager mTelephonyManager;
-    @Mock
-    private SubscriptionManager mSubscriptionManager;
-
-    @Mock
-    private UserManager mUserManager;
-
-    private PreferenceManager mPreferenceManager;
-    private PreferenceScreen mScreen;
-
-    @Mock
-    private LifecycleOwner mLifecycleOwner;
-    private LifecycleRegistry mLifecycleRegistry;
-    private MobileNetworkPreferenceController mController;
-    private Preference mPreference;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = spy(ApplicationProvider.getApplicationContext());
-        when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
-        when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
-        when(mSubscriptionManager.createForAllUserProfiles()).thenReturn(mSubscriptionManager);
-        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-        mPreferenceManager = new PreferenceManager(mContext);
-        mScreen = mPreferenceManager.createPreferenceScreen(mContext);
-        mPreference = new Preference(mContext);
-        mPreference.setKey(MobileNetworkPreferenceController.KEY_MOBILE_NETWORK_SETTINGS);
-
-        mLifecycleRegistry = new LifecycleRegistry(mLifecycleOwner);
-        when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry);
-    }
-
-    @Test
-    public void secondaryUser_prefIsNotAvailable() {
-        when(mUserManager.isAdminUser()).thenReturn(false);
-        when(mTelephonyManager.isDataCapable()).thenReturn(true);
-
-        mController = new MobileNetworkPreferenceController(mContext);
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void wifiOnly_prefIsNotAvailable() {
-        when(mUserManager.isAdminUser()).thenReturn(true);
-        when(mTelephonyManager.isDataCapable()).thenReturn(false);
-
-        mController = new MobileNetworkPreferenceController(mContext);
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    @UiThreadTest
-    public void goThroughLifecycle_isAvailable_shouldListenToServiceChange() {
-        mController = spy(new MobileNetworkPreferenceController(mContext));
-        mLifecycleRegistry.addObserver(mController);
-        doReturn(true).when(mController).isAvailable();
-
-        mLifecycleRegistry.handleLifecycleEvent(Event.ON_START);
-        verify(mController).onStart();
-        verify(mTelephonyManager).registerTelephonyCallback(
-                mContext.getMainExecutor(), mController.mTelephonyCallback);
-
-        mLifecycleRegistry.handleLifecycleEvent(Event.ON_STOP);
-        verify(mController).onStop();
-        verify(mTelephonyManager).unregisterTelephonyCallback(mController.mTelephonyCallback);
-    }
-
-    @Test
-    @UiThreadTest
-    public void serviceStateChange_shouldUpdatePrefSummary() {
-        final String testCarrierName = "test";
-
-        mController = spy(new MobileNetworkPreferenceController(mContext));
-        mLifecycleRegistry.addObserver(mController);
-        doReturn(true).when(mController).isAvailable();
-
-        mScreen.addPreference(mPreference);
-
-        // Display pref and go through lifecycle to set up listener.
-        mController.displayPreference(mScreen);
-        mLifecycleRegistry.handleLifecycleEvent(Event.ON_START);
-        verify(mController).onStart();
-        verify(mTelephonyManager).registerTelephonyCallback(
-                mContext.getMainExecutor(), mController.mTelephonyCallback);
-
-        doReturn(testCarrierName).when(mController).getSummary();
-
-        mController.mTelephonyCallback.onServiceStateChanged(null);
-
-        // Carrier name should be set.
-        Assert.assertEquals(mPreference.getSummary(), testCarrierName);
-    }
-
-    @Test
-    public void airplaneModeTurnedOn_shouldDisablePreference() {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Global.AIRPLANE_MODE_ON, 1);
-        mController = spy(new MobileNetworkPreferenceController(mContext));
-        final RestrictedPreference mPreference = new RestrictedPreference(mContext);
-        mController.updateState(mPreference);
-        assertThat(mPreference.isEnabled()).isFalse();
-    }
-
-    @Test
-    public void airplaneModeTurnedOffAndNoUserRestriction_shouldEnablePreference() {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Global.AIRPLANE_MODE_ON, 0);
-        mController = spy(new MobileNetworkPreferenceController(mContext));
-        final RestrictedPreference mPreference = new RestrictedPreference(mContext);
-        mPreference.setDisabledByAdmin(null);
-        mController.updateState(mPreference);
-        assertThat(mPreference.isEnabled()).isTrue();
-    }
-
-    @Test
-    public void airplaneModeTurnedOffAndHasUserRestriction_shouldDisablePreference() {
-        Settings.Global.putInt(mContext.getContentResolver(),
-                Global.AIRPLANE_MODE_ON, 0);
-        mController = spy(new MobileNetworkPreferenceController(mContext));
-        final RestrictedPreference mPreference = new RestrictedPreference(mContext);
-        mPreference.setDisabledByAdmin(EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN);
-        mController.updateState(mPreference);
-        assertThat(mPreference.isEnabled()).isFalse();
-    }
-}