Merge "[ProviderModel] Use category to separate physical SIM and e-SIM" into sc-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bb38fcc..4c0f811 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -13248,6 +13248,22 @@
     <string name="carrier_wifi_offload_summary">Allow Google Fi to use W+ networks to improve speed and coverage</string>
     <!-- Title for merged carrier Wi-Fi network information. [CHAR LIMIT=NONE] -->
     <string name="carrier_wifi_network_title">W+ network</string>
+    <!-- Provider Model: title of SIM category -->
+    <string name="sim_category_title">SIM</string>
+    <!-- Provider Model: title of Downloaded category. [CHAR LIMIT=50] -->
+    <string name="downloaded_sim_category_title">DOWNLOADED SIM</string>
+    <!-- Provider Model: summary of Active in SIM category. [CHAR LIMIT=50] -->
+    <string name="sim_category_active_sim">Active</string>
+    <!-- Provider Model: summary of Inactive in SIM category. [CHAR LIMIT=50] -->
+    <string name="sim_category_inactive_sim">Inactive</string>
+    <!-- Provider Model: summary of default config. [CHAR LIMIT=50] -->
+    <string name="sim_category_default_active_sim">\u0020/ Default for <xliff:g name="default_sim_config" example=" / Default for calls">%1$s</xliff:g></string>
+    <!-- Provider Model: summary of default call. [CHAR LIMIT=50] -->
+    <string name="default_active_sim_calls">calls</string>
+    <!-- Provider Model: summary of default SMS. [CHAR LIMIT=50] -->
+    <string name="default_active_sim_sms">SMS</string>
+    <!-- Provider Model: summary of default mobile data. [CHAR LIMIT=50] -->
+    <string name="default_active_sim_mobile_data">mobile data</string>
 
     <!-- Summary text separator for preferences including a short description
          (eg. "Connected / 5G"). [CHAR LIMIT=50] -->
diff --git a/res/xml/network_provider_sims_list.xml b/res/xml/network_provider_sims_list.xml
new file mode 100644
index 0000000..0f866f1
--- /dev/null
+++ b/res/xml/network_provider_sims_list.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:title="@string/provider_network_settings_title">
+
+    <PreferenceCategory
+        android:key="provider_model_sim_category"
+        android:title="@string/sim_category_title"
+        android:order="20"
+        settings:controller="com.android.settings.network.NetworkProviderSimsCategoryController"/>
+
+    <PreferenceCategory
+        android:key="provider_model_downloaded_sim_category"
+        android:title="@string/downloaded_sim_category_title"
+        android:order="25"
+        settings:controller=
+            "com.android.settings.network.NetworkProviderDownloadedSimsCategoryController"
+        settings:allowDividerAbove="true"/>
+
+    <com.android.settingslib.RestrictedPreference
+        android:key="add_more"
+        settings:isPreferenceVisible="false"
+        settings:userRestriction="no_config_mobile_networks"
+        settings:useAdminDisabledSummary="true"
+        settings:searchable="false"
+        android:title="@string/mobile_network_list_add_more"
+        android:icon="@drawable/ic_menu_add_activated_tint"
+        android:order="100">
+        <intent android:action="android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION">
+            <extra android:name="android.telephony.euicc.extra.FORCE_PROVISION"
+                   android:value="true"/>
+        </intent>
+    </com.android.settingslib.RestrictedPreference>
+</PreferenceScreen>
diff --git a/src/com/android/settings/network/MobileNetworkListFragment.java b/src/com/android/settings/network/MobileNetworkListFragment.java
index c27775d..1767c1c 100644
--- a/src/com/android/settings/network/MobileNetworkListFragment.java
+++ b/src/com/android/settings/network/MobileNetworkListFragment.java
@@ -19,8 +19,12 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.os.UserManager;
+import android.provider.SearchIndexableResource;
+
+import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.R;
+import com.android.settings.Utils;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -33,9 +37,16 @@
 public class MobileNetworkListFragment extends DashboardFragment {
     private static final String LOG_TAG = "NetworkListFragment";
 
+    static final String KEY_PREFERENCE_CATEGORY_SIM = "provider_model_sim_category";
+    @VisibleForTesting
+    static final String KEY_PREFERENCE_CATEGORY_DOWNLOADED_SIM =
+            "provider_model_downloaded_sim_category";
+
     @Override
     protected int getPreferenceScreenResId() {
-        return R.xml.mobile_network_list;
+        return Utils.isProviderModelEnabled(getContext())
+                ? R.xml.network_provider_sims_list
+                : R.xml.mobile_network_list;
     }
 
     @Override
@@ -51,12 +62,39 @@
     @Override
     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
-        controllers.add(new MobileNetworkListController(getContext(), getLifecycle()));
+
+        if (Utils.isProviderModelEnabled(getContext())) {
+            NetworkProviderSimsCategoryController simCategoryPrefCtrl =
+                    new NetworkProviderSimsCategoryController(context, KEY_PREFERENCE_CATEGORY_SIM);
+            simCategoryPrefCtrl.init(getSettingsLifecycle());
+            controllers.add(simCategoryPrefCtrl);
+
+            NetworkProviderDownloadedSimsCategoryController downloadedSimsCategoryCtrl =
+                    new NetworkProviderDownloadedSimsCategoryController(context,
+                            KEY_PREFERENCE_CATEGORY_DOWNLOADED_SIM);
+            downloadedSimsCategoryCtrl.init(getSettingsLifecycle());
+            controllers.add(downloadedSimsCategoryCtrl);
+        } else {
+            controllers.add(new MobileNetworkListController(getContext(), getLifecycle()));
+        }
+
         return controllers;
     }
 
     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-            new BaseSearchIndexProvider(R.xml.mobile_network_list) {
+            new BaseSearchIndexProvider() {
+
+                @Override
+                public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
+                        boolean enabled) {
+                    final ArrayList<SearchIndexableResource> result = new ArrayList<>();
+                    final SearchIndexableResource sir = new SearchIndexableResource(context);
+                    sir.xmlResId = Utils.isProviderModelEnabled(context)
+                            ? R.xml.network_provider_sims_list
+                            : R.xml.mobile_network_list;
+                    result.add(sir);
+                    return result;
+                }
 
                 @Override
                 protected boolean isPageSearchEnabled(Context context) {
diff --git a/src/com/android/settings/network/NetworkProviderDownloadedSimListController.java b/src/com/android/settings/network/NetworkProviderDownloadedSimListController.java
new file mode 100644
index 0000000..43bdd80
--- /dev/null
+++ b/src/com/android/settings/network/NetworkProviderDownloadedSimListController.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2021 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.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.network.telephony.MobileNetworkActivity;
+import com.android.settings.network.telephony.MobileNetworkUtils;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class NetworkProviderDownloadedSimListController extends
+        AbstractPreferenceController implements
+        LifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+    private static final String TAG = "NetworkProviderDownloadedSimListCtrl";
+    private static final String KEY_PREFERENCE_CATEGORY_DOWNLOADED_SIM =
+            "provider_model_downloaded_sim_category";
+    private static final String KEY_PREFERENCE_DOWNLOADED_SIM =
+            "provider_model_downloaded_sim_list";
+    private static final String KEY_ADD_MORE = "add_more";
+
+    private SubscriptionManager mSubscriptionManager;
+    private SubscriptionsChangeListener mChangeListener;
+    private PreferenceCategory mPreferenceCategory;
+    private Map<Integer, Preference> mPreferences;
+
+    public NetworkProviderDownloadedSimListController(Context context, Lifecycle lifecycle) {
+        super(context);
+        mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
+        mChangeListener = new SubscriptionsChangeListener(context, this);
+        mPreferences = new ArrayMap<>();
+        lifecycle.addObserver(this);
+    }
+
+    @OnLifecycleEvent(ON_RESUME)
+    public void onResume() {
+        mChangeListener.start();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
+        mContext.registerReceiver(mDataSubscriptionChangedReceiver, filter);
+        update();
+    }
+
+    @OnLifecycleEvent(ON_PAUSE)
+    public void onPause() {
+        mChangeListener.stop();
+        if (mDataSubscriptionChangedReceiver != null) {
+            mContext.unregisterReceiver(mDataSubscriptionChangedReceiver);
+        }
+    }
+
+    @VisibleForTesting
+    final BroadcastReceiver mDataSubscriptionChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
+                update();
+            }
+        }
+    };
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreferenceCategory = screen.findPreference(KEY_PREFERENCE_CATEGORY_DOWNLOADED_SIM);
+        screen.findPreference(KEY_ADD_MORE).setVisible(
+                MobileNetworkUtils.showEuiccSettings(mContext));
+        update();
+    }
+
+    private void update() {
+        if (mPreferenceCategory == null) {
+            return;
+        }
+
+        final Map<Integer, Preference> existingPreferences = mPreferences;
+        mPreferences = new ArrayMap<>();
+
+        final List<SubscriptionInfo> subscriptions = getAvailableDownloadedSubscriptions();
+        for (SubscriptionInfo info : subscriptions) {
+            final int subId = info.getSubscriptionId();
+            Preference pref = existingPreferences.remove(subId);
+            if (pref == null) {
+                pref = new Preference(mPreferenceCategory.getContext());
+                mPreferenceCategory.addPreference(pref);
+            }
+            final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                    info, mContext);
+            pref.setTitle(displayName);
+            pref.setSummary(getSummary(subId));
+
+            pref.setOnPreferenceClickListener(clickedPref -> {
+                final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
+                intent.putExtra(Settings.EXTRA_SUB_ID, info.getSubscriptionId());
+                mContext.startActivity(intent);
+                return true;
+            });
+            mPreferences.put(subId, pref);
+        }
+        for (Preference pref : existingPreferences.values()) {
+            mPreferenceCategory.removePreference(pref);
+        }
+    }
+
+    public CharSequence getSummary(int subId) {
+        if (mSubscriptionManager.isActiveSubscriptionId(subId)) {
+            CharSequence config = SubscriptionUtil.getDefaultSimConfig(mContext, subId);
+            CharSequence summary = mContext.getResources().getString(
+                    R.string.sim_category_active_sim);
+            if (config == null) {
+                return summary;
+            } else {
+                final StringBuilder activeSim = new StringBuilder();
+                activeSim.append(summary).append(config);
+                return activeSim;
+            }
+        } else {
+            return mContext.getString(R.string.sim_category_inactive_sim);
+        }
+    }
+
+    @Override
+    public boolean isAvailable() {
+        if (!getAvailableDownloadedSubscriptions().isEmpty()) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_PREFERENCE_DOWNLOADED_SIM;
+    }
+
+    private List<SubscriptionInfo> getAvailableDownloadedSubscriptions() {
+        List<SubscriptionInfo> subList = new ArrayList<>();
+        for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mContext)) {
+            if (info.isEmbedded()) {
+                subList.add(info);
+            }
+        }
+        return subList;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        refreshSummary(mPreferenceCategory);
+        update();
+    }
+
+    @Override
+    public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+    }
+
+    @Override
+    public void onSubscriptionsChanged() {
+        update();
+    }
+
+    @VisibleForTesting
+    protected int getDefaultVoiceSubscriptionId() {
+        return SubscriptionManager.getDefaultVoiceSubscriptionId();
+    }
+
+    @VisibleForTesting
+    protected int getDefaultSmsSubscriptionId() {
+        return SubscriptionManager.getDefaultSmsSubscriptionId();
+    }
+
+    @VisibleForTesting
+    protected int getDefaultDataSubscriptionId() {
+        return SubscriptionManager.getDefaultDataSubscriptionId();
+    }
+}
diff --git a/src/com/android/settings/network/NetworkProviderDownloadedSimsCategoryController.java b/src/com/android/settings/network/NetworkProviderDownloadedSimsCategoryController.java
new file mode 100644
index 0000000..199740f
--- /dev/null
+++ b/src/com/android/settings/network/NetworkProviderDownloadedSimsCategoryController.java
@@ -0,0 +1,52 @@
+package com.android.settings.network;
+
+import android.content.Context;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.widget.PreferenceCategoryController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+
+public class NetworkProviderDownloadedSimsCategoryController extends
+        PreferenceCategoryController implements LifecycleObserver {
+
+    private static final String KEY_PREFERENCE_CATEGORY_DOWNLOADED_SIM =
+            "provider_model_downloaded_sim_category";
+    private NetworkProviderDownloadedSimListController mNetworkProviderDownloadedSimListController;
+
+    public NetworkProviderDownloadedSimsCategoryController(Context context, String key) {
+        super(context, key);
+    }
+
+    public void init(Lifecycle lifecycle) {
+        mNetworkProviderDownloadedSimListController = createDownloadedSimListController(lifecycle);
+    }
+
+    @VisibleForTesting
+    protected NetworkProviderDownloadedSimListController createDownloadedSimListController(
+            Lifecycle lifecycle) {
+        return new NetworkProviderDownloadedSimListController(mContext, lifecycle);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (mNetworkProviderDownloadedSimListController == null
+                || !mNetworkProviderDownloadedSimListController.isAvailable()) {
+            return CONDITIONALLY_UNAVAILABLE;
+        } else {
+            return AVAILABLE;
+        }
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        PreferenceCategory preferenceCategory = screen.findPreference(
+                KEY_PREFERENCE_CATEGORY_DOWNLOADED_SIM);
+        preferenceCategory.setVisible(isAvailable());
+        mNetworkProviderDownloadedSimListController.displayPreference(screen);
+    }
+}
diff --git a/src/com/android/settings/network/NetworkProviderSimListController.java b/src/com/android/settings/network/NetworkProviderSimListController.java
new file mode 100644
index 0000000..814a461
--- /dev/null
+++ b/src/com/android/settings/network/NetworkProviderSimListController.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2021 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.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.network.telephony.MobileNetworkActivity;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class NetworkProviderSimListController extends AbstractPreferenceController implements
+        LifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+    private static final String TAG = "NetworkProviderSimListCtrl";
+    private static final String KEY_PREFERENCE_CATEGORY_SIM = "provider_model_sim_category";
+    private static final String KEY_PREFERENCE_SIM = "provider_model_sim_list";
+
+    private SubscriptionManager mSubscriptionManager;
+    private SubscriptionsChangeListener mChangeListener;
+    private PreferenceCategory mPreferenceCategory;
+    private Map<Integer, Preference> mPreferences;
+
+    public NetworkProviderSimListController(Context context, Lifecycle lifecycle) {
+        super(context);
+        mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
+        mChangeListener = new SubscriptionsChangeListener(context, this);
+        mPreferences = new ArrayMap<>();
+        lifecycle.addObserver(this);
+    }
+
+    @OnLifecycleEvent(ON_RESUME)
+    public void onResume() {
+        mChangeListener.start();
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
+        mContext.registerReceiver(mDataSubscriptionChangedReceiver, filter);
+        update();
+    }
+
+    @OnLifecycleEvent(ON_PAUSE)
+    public void onPause() {
+        mChangeListener.stop();
+        if (mDataSubscriptionChangedReceiver != null) {
+            mContext.unregisterReceiver(mDataSubscriptionChangedReceiver);
+        }
+    }
+
+    @VisibleForTesting
+    final BroadcastReceiver mDataSubscriptionChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
+                update();
+            }
+        }
+    };
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreferenceCategory = screen.findPreference(KEY_PREFERENCE_CATEGORY_SIM);
+        update();
+    }
+
+    private void update() {
+        if (mPreferenceCategory == null) {
+            return;
+        }
+
+        final Map<Integer, Preference> existingPreferences = mPreferences;
+        mPreferences = new ArrayMap<>();
+
+        final List<SubscriptionInfo> subscriptions = getAvailablePhysicalSubscription();
+        for (SubscriptionInfo info : subscriptions) {
+            final int subId = info.getSubscriptionId();
+            Preference pref = existingPreferences.remove(subId);
+            if (pref == null) {
+                pref = new Preference(mPreferenceCategory.getContext());
+                mPreferenceCategory.addPreference(pref);
+            }
+            final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                    info, mContext);
+            pref.setTitle(displayName);
+            pref.setSummary(getSummary(subId, displayName));
+
+            pref.setOnPreferenceClickListener(clickedPref -> {
+                if (!mSubscriptionManager.isActiveSubscriptionId(subId)
+                        && !SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) {
+                    SubscriptionUtil.startToggleSubscriptionDialogActivity(mContext, subId,
+                            true);
+                } else {
+                    final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
+                    intent.putExtra(Settings.EXTRA_SUB_ID, info.getSubscriptionId());
+                    mContext.startActivity(intent);
+                }
+                return true;
+            });
+            mPreferences.put(subId, pref);
+        }
+        for (Preference pref : existingPreferences.values()) {
+            mPreferenceCategory.removePreference(pref);
+        }
+    }
+
+    public CharSequence getSummary(int subId, CharSequence displayName) {
+        if (mSubscriptionManager.isActiveSubscriptionId(subId)) {
+            CharSequence config = SubscriptionUtil.getDefaultSimConfig(mContext, subId);
+            CharSequence summary = mContext.getResources().getString(
+                    R.string.sim_category_active_sim);
+            if (config == null) {
+                return summary;
+            } else {
+                final StringBuilder activeSim = new StringBuilder();
+                activeSim.append(summary).append(config);
+                return activeSim;
+            }
+        } else if (SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) {
+            return mContext.getString(R.string.sim_category_inactive_sim);
+        } else {
+            return mContext.getString(R.string.mobile_network_tap_to_activate, displayName);
+        }
+    }
+
+    @Override
+    public boolean isAvailable() {
+        if (!getAvailablePhysicalSubscription().isEmpty()) {
+            return true;
+        }
+        return false;
+    }
+
+    @VisibleForTesting
+    protected List<SubscriptionInfo> getAvailablePhysicalSubscription() {
+        List<SubscriptionInfo> subList = new ArrayList<>();
+        for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mContext)) {
+            if (!info.isEmbedded()) {
+                subList.add(info);
+                break;
+            }
+        }
+        return subList;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_PREFERENCE_SIM;
+    }
+
+    @Override
+    public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+    }
+
+    @Override
+    public void onSubscriptionsChanged() {
+        update();
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        refreshSummary(mPreferenceCategory);
+        update();
+    }
+
+    @VisibleForTesting
+    protected int getDefaultVoiceSubscriptionId() {
+        return SubscriptionManager.getDefaultVoiceSubscriptionId();
+    }
+
+    @VisibleForTesting
+    protected int getDefaultSmsSubscriptionId() {
+        return SubscriptionManager.getDefaultSmsSubscriptionId();
+    }
+
+    @VisibleForTesting
+    protected int getDefaultDataSubscriptionId() {
+        return SubscriptionManager.getDefaultDataSubscriptionId();
+    }
+}
diff --git a/src/com/android/settings/network/NetworkProviderSimsCategoryController.java b/src/com/android/settings/network/NetworkProviderSimsCategoryController.java
new file mode 100644
index 0000000..e27575a
--- /dev/null
+++ b/src/com/android/settings/network/NetworkProviderSimsCategoryController.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 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 androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.widget.PreferenceCategoryController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+
+public class NetworkProviderSimsCategoryController extends PreferenceCategoryController implements
+        LifecycleObserver {
+
+    private static final String KEY_PREFERENCE_CATEGORY_SIM = "provider_model_sim_category";
+    private NetworkProviderSimListController mNetworkProviderSimListController;
+
+    public NetworkProviderSimsCategoryController(Context context, String key) {
+        super(context, key);
+    }
+
+    public void init(Lifecycle lifecycle) {
+        mNetworkProviderSimListController = createSimListController(lifecycle);
+    }
+
+    @VisibleForTesting
+    protected NetworkProviderSimListController createSimListController(
+            Lifecycle lifecycle) {
+        return new NetworkProviderSimListController(mContext, lifecycle);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        if (mNetworkProviderSimListController == null
+                || !mNetworkProviderSimListController.isAvailable()) {
+            return CONDITIONALLY_UNAVAILABLE;
+        } else {
+            return AVAILABLE;
+        }
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        PreferenceCategory preferenceCategory = screen.findPreference(KEY_PREFERENCE_CATEGORY_SIM);
+        preferenceCategory.setVisible(isAvailable());
+        mNetworkProviderSimListController.displayPreference(screen);
+    }
+}
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index 4ba7fc9..e7dd5e9 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -36,6 +36,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.telephony.MccTable;
+import com.android.settings.R;
 import com.android.settings.network.telephony.DeleteEuiccSubscriptionDialogActivity;
 import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity;
 import com.android.settingslib.DeviceInfoUtils;
@@ -343,7 +344,6 @@
      *
      * @return map of active subscription ids to diaplay names.
      */
-    @VisibleForTesting
     public static CharSequence getUniqueSubscriptionDisplayName(
             SubscriptionInfo info, Context context) {
         if (info == null) {
@@ -585,4 +585,56 @@
         }
         return null;
     }
+
+    public static CharSequence getDefaultSimConfig(Context context, int subId) {
+        boolean isDefaultCall = subId == getDefaultVoiceSubscriptionId();
+        boolean isDefaultSms = subId == getDefaultSmsSubscriptionId();
+        boolean isDefaultData = subId == getDefaultDataSubscriptionId();
+
+        if (!isDefaultData && !isDefaultCall && !isDefaultSms) {
+            return null;
+        }
+
+        final StringBuilder defaultConfig = new StringBuilder();
+        if (isDefaultData) {
+            defaultConfig.append(
+                    getResForDefaultConfig(context, R.string.default_active_sim_mobile_data))
+                    .append(", ");
+        }
+
+        if (isDefaultCall) {
+            defaultConfig.append(getResForDefaultConfig(context, R.string.default_active_sim_calls))
+                    .append(", ");
+        }
+
+        if (isDefaultSms) {
+            defaultConfig.append(getResForDefaultConfig(context, R.string.default_active_sim_sms))
+                    .append(", ");
+        }
+
+        // Do not add ", " for the last config.
+        defaultConfig.setLength(defaultConfig.length() - 2);
+
+        final String summary = context.getResources().getString(
+                R.string.sim_category_default_active_sim,
+                defaultConfig);
+
+        return summary;
+    }
+
+    private static String getResForDefaultConfig(Context context, int resId) {
+        return context.getResources().getString(resId);
+    }
+
+    private static int getDefaultVoiceSubscriptionId() {
+        return SubscriptionManager.getDefaultVoiceSubscriptionId();
+    }
+
+    private static int getDefaultSmsSubscriptionId() {
+        return SubscriptionManager.getDefaultSmsSubscriptionId();
+    }
+
+    private static int getDefaultDataSubscriptionId() {
+        return SubscriptionManager.getDefaultDataSubscriptionId();
+    }
 }
diff --git a/tests/unit/src/com/android/settings/network/NetworkProviderDownloadedSimListControllerTest.java b/tests/unit/src/com/android/settings/network/NetworkProviderDownloadedSimListControllerTest.java
new file mode 100644
index 0000000..939bf34
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/NetworkProviderDownloadedSimListControllerTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2021 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 org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+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.settings.testutils.ResourcesUtils;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+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.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class NetworkProviderDownloadedSimListControllerTest {
+
+    private static final int SUB_ID = 1;
+    private static final String KEY_PREFERENCE_DOWNLOADED_SIM =
+            "provider_model_downloaded_sim_list";
+    private static final String KEY_ADD_MORE = "add_more";
+    private static final String DISPLAY_NAME = "Sub 1";
+
+    @Mock
+    private SubscriptionManager mSubscriptionManager;
+    @Mock
+    private SubscriptionInfo mSubscriptionInfo;
+    @Mock
+    private Lifecycle mLifecycle;
+    @Mock
+    private LifecycleOwner mLifecycleOwner;
+    private LifecycleRegistry mLifecycleRegistry;
+
+    private MockNetworkProviderDownloadedSimListController mController;
+    private PreferenceManager mPreferenceManager;
+    private PreferenceScreen mPreferenceScreen;
+    private Preference mPreference;
+    private Preference mAddMorePreference;
+
+    private Context mContext;
+
+    /**
+     * Mock the MockNetworkProviderDownloadedSimListController that allows one to set a
+     * default voice, SMS and mobile data subscription ID.
+     */
+    @SuppressWarnings("ClassCanBeStatic")
+    private class MockNetworkProviderDownloadedSimListController extends
+            com.android.settings.network.NetworkProviderDownloadedSimListController {
+        public MockNetworkProviderDownloadedSimListController(Context context,
+                Lifecycle lifecycle) {
+            super(context, lifecycle);
+        }
+
+        private int mDefaultVoiceSubscriptionId;
+        private int mDefaultSmsSubscriptionId;
+        private int mDefaultDataSubscriptionId;
+
+        @Override
+        protected int getDefaultVoiceSubscriptionId() {
+            return mDefaultVoiceSubscriptionId;
+        }
+
+        @Override
+        protected int getDefaultSmsSubscriptionId() {
+            return mDefaultSmsSubscriptionId;
+        }
+
+        @Override
+        protected int getDefaultDataSubscriptionId() {
+            return mDefaultDataSubscriptionId;
+        }
+
+        public void setDefaultVoiceSubscriptionId(int subscriptionId) {
+            mDefaultVoiceSubscriptionId = subscriptionId;
+        }
+
+        public void setDefaultSmsSubscriptionId(int subscriptionId) {
+            mDefaultSmsSubscriptionId = subscriptionId;
+        }
+
+        public void setDefaultDataSubscriptionId(int subscriptionId) {
+            mDefaultDataSubscriptionId = subscriptionId;
+        }
+
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
+
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        mPreferenceManager = new PreferenceManager(mContext);
+        mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
+        mPreference = new Preference(mContext);
+        mPreference.setKey(KEY_PREFERENCE_DOWNLOADED_SIM);
+        mController = new MockNetworkProviderDownloadedSimListController(mContext, mLifecycle);
+        mAddMorePreference = new Preference(mContext);
+        mAddMorePreference.setKey(KEY_ADD_MORE);
+        mAddMorePreference.setVisible(true);
+        mLifecycleRegistry = new LifecycleRegistry(mLifecycleOwner);
+        when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry);
+    }
+
+    private void displayPreferenceWithLifecycle() {
+        mLifecycleRegistry.addObserver(mController);
+        mPreferenceScreen.addPreference(mPreference);
+        mPreferenceScreen.addPreference(mAddMorePreference);
+        mController.displayPreference(mPreferenceScreen);
+        mLifecycleRegistry.handleLifecycleEvent(Event.ON_RESUME);
+    }
+
+    private void setupSubscriptionInfoList(int subId, String displayName,
+            SubscriptionInfo subscriptionInfo) {
+        when(subscriptionInfo.getSubscriptionId()).thenReturn(subId);
+        doReturn(subscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(subId);
+        when(subscriptionInfo.getDisplayName()).thenReturn(displayName);
+        when(subscriptionInfo.isEmbedded()).thenReturn(true);
+    }
+
+    private String setSummaryResId(String resName) {
+        return ResourcesUtils.getResourcesString(mContext, resName);
+    }
+
+    @Test
+    @UiThreadTest
+    public void getSummary_inactiveESim() {
+        setupSubscriptionInfoList(SUB_ID, DISPLAY_NAME, mSubscriptionInfo);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(new ArrayList<>());
+        when(mSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(new ArrayList<>());
+        doReturn(false).when(mSubscriptionManager).isActiveSubscriptionId(SUB_ID);
+
+        displayPreferenceWithLifecycle();
+        String summary = setSummaryResId("sim_category_inactive_sim");
+
+        assertTrue(TextUtils.equals(mController.getSummary(SUB_ID), summary));
+    }
+
+    @Test
+    @UiThreadTest
+    public void getSummary_defaultCalls() {
+        mController.setDefaultVoiceSubscriptionId(SUB_ID);
+        setupSubscriptionInfoList(SUB_ID, DISPLAY_NAME, mSubscriptionInfo);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(
+                Arrays.asList(mSubscriptionInfo));
+        when(mSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
+                Arrays.asList(mSubscriptionInfo));
+        doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(SUB_ID);
+
+        displayPreferenceWithLifecycle();
+        CharSequence defaultCall = SubscriptionUtil.getDefaultSimConfig(mContext, SUB_ID);
+        final StringBuilder summary = new StringBuilder();
+        summary.append(setSummaryResId("sim_category_active_sim"))
+                .append(defaultCall);
+
+        assertTrue(TextUtils.equals(mController.getSummary(SUB_ID), summary));
+    }
+
+    @Test
+    @UiThreadTest
+    public void getSummary_defaultCallsAndMobileData() {
+        mController.setDefaultVoiceSubscriptionId(SUB_ID);
+        mController.setDefaultDataSubscriptionId(SUB_ID);
+        setupSubscriptionInfoList(SUB_ID, DISPLAY_NAME, mSubscriptionInfo);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(
+                Arrays.asList(mSubscriptionInfo));
+        when(mSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
+                Arrays.asList(mSubscriptionInfo));
+        doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(SUB_ID);
+
+        displayPreferenceWithLifecycle();
+        CharSequence defaultCall = SubscriptionUtil.getDefaultSimConfig(mContext, SUB_ID);
+        final StringBuilder summary = new StringBuilder();
+        summary.append(setSummaryResId("sim_category_active_sim"))
+                .append(defaultCall);
+
+        assertTrue(TextUtils.equals(mController.getSummary(SUB_ID), summary));
+    }
+
+}
diff --git a/tests/unit/src/com/android/settings/network/NetworkProviderDownloadedSimsCategoryControllerTest.java b/tests/unit/src/com/android/settings/network/NetworkProviderDownloadedSimsCategoryControllerTest.java
new file mode 100644
index 0000000..e34b489
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/NetworkProviderDownloadedSimsCategoryControllerTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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 com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+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 NetworkProviderDownloadedSimsCategoryControllerTest {
+
+    private static final String KEY_PREFERENCE_CATEGORY_DOWNLOADED_SIM =
+            "provider_model_downloaded_sim_category";
+
+    @Mock
+    private NetworkProviderDownloadedSimListController mNetworkProviderDownloadedSimListController;
+    @Mock
+    private PreferenceCategory mPreferenceCategory;
+    @Mock
+    private Lifecycle mLifecycle;
+
+    private Context mContext;
+    private NetworkProviderDownloadedSimsCategoryController mCategoryController;
+
+    private PreferenceManager mPreferenceManager;
+    private PreferenceScreen mPreferenceScreen;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        mCategoryController = new NetworkProviderDownloadedSimsCategoryController(
+                mContext, KEY_PREFERENCE_CATEGORY_DOWNLOADED_SIM) {
+            @Override
+            protected NetworkProviderDownloadedSimListController createDownloadedSimListController(
+                    Lifecycle lifecycle) {
+                return mNetworkProviderDownloadedSimListController;
+            }
+        };
+
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        mPreferenceManager = new PreferenceManager(mContext);
+        mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
+        when(mPreferenceCategory.getKey()).thenReturn(KEY_PREFERENCE_CATEGORY_DOWNLOADED_SIM);
+        when(mPreferenceCategory.getPreferenceCount()).thenReturn(1);
+        mPreferenceScreen.addPreference(mPreferenceCategory);
+    }
+
+    @Test
+    public void getAvailabilityStatus_returnUnavailable() {
+        mNetworkProviderDownloadedSimListController = null;
+
+        assertThat(mCategoryController.getAvailabilityStatus()).isEqualTo(
+                CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
+    public void displayPreference_isVisible() {
+        when(mNetworkProviderDownloadedSimListController.isAvailable()).thenReturn(true);
+        mCategoryController.init(mLifecycle);
+        mCategoryController.displayPreference(mPreferenceScreen);
+
+        assertEquals(mPreferenceCategory.isVisible(), true);
+    }
+}
diff --git a/tests/unit/src/com/android/settings/network/NetworkProviderSimListControllerTest.java b/tests/unit/src/com/android/settings/network/NetworkProviderSimListControllerTest.java
new file mode 100644
index 0000000..3b0a40a
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/NetworkProviderSimListControllerTest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2021 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 org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+import androidx.preference.PreferenceManager;
+import androidx.preference.Preference;
+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.settings.testutils.ResourcesUtils;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+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.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class NetworkProviderSimListControllerTest {
+
+    private static final int SUB_ID_1 = 1;
+    private static final String KEY_PREFERENCE_SIM_LIST = "provider_model_sim_list";
+    private static final String DISPLAY_NAME_1 = "Sub 1";
+
+    @Mock
+    private SubscriptionManager mSubscriptionManager;
+    @Mock
+    private SubscriptionInfo mSubscriptionInfo;
+    @Mock
+    private Lifecycle mLifecycle;
+    @Mock
+    private LifecycleOwner mLifecycleOwner;
+    private LifecycleRegistry mLifecycleRegistry;
+
+    private MockNetworkProviderSimListController mController;
+    private PreferenceManager mPreferenceManager;
+    private PreferenceScreen mPreferenceScreen;
+    private Preference mPreference;
+
+    private Context mContext;
+
+    /**
+     * Mock the NetworkProviderSimListController that allows one to set a default voice,
+     * SMS and mobile data subscription ID.
+     */
+    @SuppressWarnings("ClassCanBeStatic")
+    private class MockNetworkProviderSimListController extends
+            com.android.settings.network.NetworkProviderSimListController {
+        public MockNetworkProviderSimListController(Context context, Lifecycle lifecycle) {
+            super(context, lifecycle);
+        }
+
+        private int mDefaultVoiceSubscriptionId;
+        private int mDefaultSmsSubscriptionId;
+        private int mDefaultDataSubscriptionId;
+
+        @Override
+        protected int getDefaultVoiceSubscriptionId() {
+            return mDefaultVoiceSubscriptionId;
+        }
+
+        @Override
+        protected int getDefaultSmsSubscriptionId() {
+            return mDefaultSmsSubscriptionId;
+        }
+
+        @Override
+        protected int getDefaultDataSubscriptionId() {
+            return mDefaultDataSubscriptionId;
+        }
+
+        public void setDefaultVoiceSubscriptionId(int subscriptionId) {
+            mDefaultVoiceSubscriptionId = subscriptionId;
+        }
+
+        public void setDefaultSmsSubscriptionId(int subscriptionId) {
+            mDefaultSmsSubscriptionId = subscriptionId;
+        }
+
+        public void setDefaultDataSubscriptionId(int subscriptionId) {
+            mDefaultDataSubscriptionId = subscriptionId;
+        }
+
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
+
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        mPreferenceManager = new PreferenceManager(mContext);
+        mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
+        mPreference = new Preference(mContext);
+        mPreference.setKey(KEY_PREFERENCE_SIM_LIST);
+        mController = new MockNetworkProviderSimListController(mContext, mLifecycle);
+        mLifecycleRegistry = new LifecycleRegistry(mLifecycleOwner);
+        when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry);
+    }
+
+    private void displayPreferenceWithLifecycle() {
+        mLifecycleRegistry.addObserver(mController);
+        mPreferenceScreen.addPreference(mPreference);
+        mController.displayPreference(mPreferenceScreen);
+        mLifecycleRegistry.handleLifecycleEvent(Event.ON_RESUME);
+    }
+
+    private void setupSubscriptionInfoList(int subId, String displayName,
+            SubscriptionInfo subscriptionInfo) {
+        when(subscriptionInfo.getSubscriptionId()).thenReturn(subId);
+        doReturn(subscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(subId);
+        when(subscriptionInfo.getDisplayName()).thenReturn(displayName);
+        when(subscriptionInfo.isEmbedded()).thenReturn(false);
+    }
+
+    private String setSummaryResId(String resName, String value) {
+        return ResourcesUtils.getResourcesString(mContext, resName, value);
+    }
+
+    @Test
+    @UiThreadTest
+    public void getSummary_tapToActivePSim() {
+        setupSubscriptionInfoList(SUB_ID_1, DISPLAY_NAME_1, mSubscriptionInfo);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(new ArrayList<>());
+        when(mSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(new ArrayList<>());
+        doReturn(false).when(mSubscriptionManager).isActiveSubscriptionId(SUB_ID_1);
+
+        displayPreferenceWithLifecycle();
+        String summary = setSummaryResId("mobile_network_tap_to_activate", DISPLAY_NAME_1);
+
+        assertTrue(TextUtils.equals(mController.getSummary(SUB_ID_1, DISPLAY_NAME_1), summary));
+    }
+
+
+    @Test
+    @UiThreadTest
+    public void getSummary_inactivePSim() {
+        setupSubscriptionInfoList(SUB_ID_1, DISPLAY_NAME_1, mSubscriptionInfo);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(new ArrayList<>());
+        when(mSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(new ArrayList<>());
+        doReturn(false).when(mSubscriptionManager).isActiveSubscriptionId(SUB_ID_1);
+        doReturn(true).when(mSubscriptionManager).canDisablePhysicalSubscription();
+
+        displayPreferenceWithLifecycle();
+        String summary = setSummaryResId("sim_category_inactive_sim", null);
+
+        assertTrue(TextUtils.equals(mController.getSummary(SUB_ID_1, DISPLAY_NAME_1), summary));
+    }
+
+    @Test
+    @UiThreadTest
+    public void getSummary_defaultCalls() {
+        mController.setDefaultVoiceSubscriptionId(SUB_ID_1);
+        setupSubscriptionInfoList(SUB_ID_1, DISPLAY_NAME_1, mSubscriptionInfo);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(
+                Arrays.asList(mSubscriptionInfo));
+        when(mSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
+                Arrays.asList(mSubscriptionInfo));
+        doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(SUB_ID_1);
+
+        displayPreferenceWithLifecycle();
+        CharSequence defaultCall = SubscriptionUtil.getDefaultSimConfig(mContext, SUB_ID_1);
+        final StringBuilder summary = new StringBuilder();
+        summary.append(setSummaryResId("sim_category_active_sim", null))
+                .append(defaultCall);
+
+        assertTrue(TextUtils.equals(mController.getSummary(SUB_ID_1, DISPLAY_NAME_1), summary));
+    }
+
+    @Test
+    @UiThreadTest
+    public void getSummary_defaultCallsAndSms() {
+        mController.setDefaultVoiceSubscriptionId(SUB_ID_1);
+        mController.setDefaultSmsSubscriptionId(SUB_ID_1);
+        setupSubscriptionInfoList(SUB_ID_1, DISPLAY_NAME_1, mSubscriptionInfo);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(
+                Arrays.asList(mSubscriptionInfo));
+        when(mSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
+                Arrays.asList(mSubscriptionInfo));
+        doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(SUB_ID_1);
+
+        displayPreferenceWithLifecycle();
+        CharSequence defaultCall = SubscriptionUtil.getDefaultSimConfig(mContext, SUB_ID_1);
+        final StringBuilder summary = new StringBuilder();
+        summary.append(setSummaryResId("sim_category_active_sim", null))
+                .append(defaultCall);
+
+        assertTrue(TextUtils.equals(mController.getSummary(SUB_ID_1, DISPLAY_NAME_1), summary));
+    }
+
+}
diff --git a/tests/unit/src/com/android/settings/network/NetworkProviderSimsCategoryControllerTest.java b/tests/unit/src/com/android/settings/network/NetworkProviderSimsCategoryControllerTest.java
new file mode 100644
index 0000000..cfa376b
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/NetworkProviderSimsCategoryControllerTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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 com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+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 NetworkProviderSimsCategoryControllerTest {
+
+    private static final String KEY_PREFERENCE_CATEGORY_SIM = "provider_model_sim_category";
+
+    @Mock
+    private NetworkProviderSimListController mNetworkProviderSimListController;
+    @Mock
+    private PreferenceCategory mPreferenceCategory;
+    @Mock
+    private Lifecycle mLifecycle;
+
+    private Context mContext;
+    private NetworkProviderSimsCategoryController mCategoryController;
+
+    private PreferenceManager mPreferenceManager;
+    private PreferenceScreen mPreferenceScreen;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        mCategoryController = new NetworkProviderSimsCategoryController(
+                mContext, KEY_PREFERENCE_CATEGORY_SIM) {
+            @Override
+            protected NetworkProviderSimListController createSimListController(
+                    Lifecycle lifecycle) {
+                return mNetworkProviderSimListController;
+            }
+        };
+
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        mPreferenceManager = new PreferenceManager(mContext);
+        mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
+        when(mPreferenceCategory.getKey()).thenReturn(KEY_PREFERENCE_CATEGORY_SIM);
+        when(mPreferenceCategory.getPreferenceCount()).thenReturn(1);
+        mPreferenceScreen.addPreference(mPreferenceCategory);
+    }
+
+    @Test
+    public void getAvailabilityStatus_returnUnavailable() {
+        mNetworkProviderSimListController = null;
+
+        assertThat(mCategoryController.getAvailabilityStatus()).isEqualTo(
+                CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
+    public void displayPreference_isVisible() {
+        when(mNetworkProviderSimListController.isAvailable()).thenReturn(true);
+        mCategoryController.init(mLifecycle);
+        mCategoryController.displayPreference(mPreferenceScreen);
+
+        assertEquals(mPreferenceCategory.isVisible(), true);
+    }
+}