Merge "Update setDenylist() input structure" into main
diff --git a/Android.bp b/Android.bp
index 0777aa7..2699c38 100644
--- a/Android.bp
+++ b/Android.bp
@@ -89,6 +89,7 @@
         "SettingsLib",
         "SettingsLibActivityEmbedding",
         "aconfig_settings_flags_lib",
+        "accessibility_settings_flags_lib",
         "app-usage-event-protos-lite",
         "battery-event-protos-lite",
         "battery-usage-slot-protos-lite",
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index 37b03ba..de6d0af 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -35,4 +35,15 @@
 java_aconfig_library {
     name: "MediaDrmSettingsFlagsLib",
     aconfig_declarations: "media_drm_flags",
-}
\ No newline at end of file
+}
+
+aconfig_declarations {
+    name: "accessibility_flags",
+    package: "com.android.settings.accessibility",
+    srcs: ["accessibility/*.aconfig"],
+}
+
+java_aconfig_library {
+    name: "accessibility_settings_flags_lib",
+    aconfig_declarations: "accessibility_flags",
+}
diff --git a/aconfig/accessibility/OWNERS b/aconfig/accessibility/OWNERS
new file mode 100644
index 0000000..7a76c21
--- /dev/null
+++ b/aconfig/accessibility/OWNERS
@@ -0,0 +1 @@
+include /src/com/android/settings/accessibility/OWNERS
diff --git a/aconfig/accessibility/accessibility_flags.aconfig b/aconfig/accessibility/accessibility_flags.aconfig
new file mode 100644
index 0000000..7f1f909
--- /dev/null
+++ b/aconfig/accessibility/accessibility_flags.aconfig
@@ -0,0 +1,10 @@
+package: "com.android.settings.accessibility"
+
+# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
+
+flag {
+  name: "remove_qs_tooltip_in_suw"
+  namespace: "accessibility"
+  description: "Don't show quick settings tooltip in SUW, since the user can't use quick settings there."
+  bug: "294560581"
+}
\ No newline at end of file
diff --git a/aconfig/settings_accessibility_flag_declarations.aconfig b/aconfig/settings_accessibility_flag_declarations_legacy.aconfig
similarity index 86%
rename from aconfig/settings_accessibility_flag_declarations.aconfig
rename to aconfig/settings_accessibility_flag_declarations_legacy.aconfig
index 246f983..acdce96 100644
--- a/aconfig/settings_accessibility_flag_declarations.aconfig
+++ b/aconfig/settings_accessibility_flag_declarations_legacy.aconfig
@@ -1,5 +1,8 @@
 package: "com.android.settings.flags"
 
+# NOTE: Don't add new accessibility flags here, since the package name doesn't follow
+# the best practice for setting's feature flag go/settings-trunk-stable
+
 # NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
 
 # NOTE: All Settings flags share the same Flags class, so prefix our
diff --git a/res/drawable/ic_calls_sms.xml b/res/drawable/ic_calls_sms.xml
deleted file mode 100644
index 2033e8f..0000000
--- a/res/drawable/ic_calls_sms.xml
+++ /dev/null
@@ -1,29 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?android:attr/colorControlNormal"
-    >
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M20.17,14.85l-3.26-0.65c-0.33-0.07-0.67,0.04-0.9,0.27l-2.62,2.62c-2.75-1.49-5.01-3.75-6.5-6.5l2.62-2.62 c0.24-0.24,0.34-0.58,0.27-0.9L9.13,3.82c-0.09-0.47-0.5-0.8-0.98-0.8H4c-0.56,0-1.03,0.47-1,1.03c0.17,2.91,1.04,5.63,2.43,8.01 c1.57,2.69,3.81,4.93,6.5,6.5c2.38,1.39,5.1,2.26,8.01,2.43c0.56,0.03,1.03-0.44,1.03-1v-4.15C20.97,15.36,20.64,14.95,20.17,14.85 L20.17,14.85z M12,3v10l3-3h6V3H12z M19,8h-5V5h5V8z" />
-</vector>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cffaaa8..e4e5750 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1743,7 +1743,7 @@
     <string name="bluetooth_device_context_disconnect">Disconnect</string>
     <!-- Bluetooth settings.  Context menu item for a device.  Action will first pair, and then connect to all profiles on the device. -->
     <string name="bluetooth_device_context_pair_connect">Pair &amp; connect</string>
-    <!-- Bluetooth settings. Text displayed when Bluetooth is off and device list is empty [CHAR LIMIT=50]-->
+    <!-- Bluetooth settings. Text displayed when Bluetooth is off and device list is empty [CHAR LIMIT=NONE]-->
     <string name="bluetooth_empty_list_bluetooth_off">When Bluetooth is turned on, your device can communicate with other nearby Bluetooth devices</string>
     <!-- Bluetooth settings. Text displayed when Bluetooth is off and bluetooth scanning is turned on [CHAR LIMIT=NONE] -->
     <string name="bluetooth_scanning_on_info_message">When Bluetooth is turned on, your device can communicate with other nearby Bluetooth devices.\n\nTo improve device experience, apps and services can still scan for nearby devices at any time, even when Bluetooth is off. This can be used, for example, to improve location-based features and services. You can change this in Bluetooth scanning settings.</string>
diff --git a/res/xml/network_provider_internet.xml b/res/xml/network_provider_internet.xml
index ef6ed16..b055ea3 100644
--- a/res/xml/network_provider_internet.xml
+++ b/res/xml/network_provider_internet.xml
@@ -31,16 +31,11 @@
         settings:keywords="@string/keywords_internet"
         settings:useAdminDisabledSummary="true" />
 
-    <com.android.settingslib.RestrictedPreference
+    <com.android.settings.spa.preference.ComposePreference
         android:key="calls_and_sms"
         android:title="@string/calls_and_sms"
-        android:icon="@drawable/ic_calls_sms"
         android:order="-20"
-        android:summary="@string/summary_placeholder"
-        settings:isPreferenceVisible="@bool/config_show_sim_info"
-        settings:allowDividerBelow="true"
-        settings:keywords="@string/calls_and_sms"
-        settings:useAdminDisabledSummary="true" />
+        settings:controller="com.android.settings.network.NetworkProviderCallsSmsController" />
 
     <com.android.settingslib.RestrictedPreference
         android:key="mobile_network_list"
diff --git a/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java b/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
index 6bd8747..f268a40 100644
--- a/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
+++ b/src/com/android/settings/accessibility/PreviewSizeSeekBarController.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.accessibility;
 
+import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Bundle;
@@ -33,6 +34,8 @@
 import com.android.settingslib.core.lifecycle.events.OnDestroy;
 import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
 
+import com.google.android.setupcompat.util.WizardManagerHelper;
+
 import java.util.Optional;
 
 /**
@@ -207,6 +210,13 @@
             return;
         }
 
+        if (Flags.removeQsTooltipInSuw()
+                && mContext instanceof Activity
+                && WizardManagerHelper.isAnySetupWizard(((Activity) mContext).getIntent())) {
+            // Don't show QuickSettingsTooltip in Setup Wizard
+            return;
+        }
+
         if (!mNeedsQSTooltipReshow && AccessibilityQuickSettingUtils.hasValueInSharedPreferences(
                 mContext, tileComponentName)) {
             // Returns if quick settings tooltip only show once.
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
index 427cad9..c76bb8b 100644
--- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -905,6 +905,14 @@
             return;
         }
 
+        Activity activity = getActivity();
+        if (com.android.settings.accessibility.Flags.removeQsTooltipInSuw()
+                && activity != null
+                && WizardManagerHelper.isAnySetupWizard(activity.getIntent())) {
+            // Don't show QuickSettingsTooltip in Setup Wizard
+            return;
+        }
+
         if (!mNeedsQSTooltipReshow && AccessibilityQuickSettingUtils.hasValueInSharedPreferences(
                 getContext(), tileComponentName)) {
             // Returns if quick settings tooltip only show once.
diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java
index d558aa8..4790c65 100644
--- a/src/com/android/settings/network/NetworkDashboardFragment.java
+++ b/src/com/android/settings/network/NetworkDashboardFragment.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
-import android.provider.SearchIndexableResource;
 import android.util.Log;
 
 import androidx.appcompat.app.AlertDialog;
@@ -31,19 +30,16 @@
 
 import com.android.settings.R;
 import com.android.settings.SettingsDumpService;
-import com.android.settings.Utils;
 import com.android.settings.core.OnActivityResultListener;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.network.MobilePlanPreferenceController.MobilePlanPreferenceHost;
 import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.wifi.WifiPrimarySwitchPreferenceController;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.search.SearchIndexable;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 @SearchIndexable
@@ -122,7 +118,6 @@
             controllers.add(internetPreferenceController);
         }
         controllers.add(privateDnsPreferenceController);
-        controllers.add(new NetworkProviderCallsSmsController(context, lifecycle, lifecycleOwner));
 
         // Start SettingsDumpService after the MobileNetworkRepository is created.
         Intent intent = new Intent(context, SettingsDumpService.class);
diff --git a/src/com/android/settings/network/NetworkProviderCallsSmsController.java b/src/com/android/settings/network/NetworkProviderCallsSmsController.java
deleted file mode 100644
index 5eec3d9..0000000
--- a/src/com/android/settings/network/NetworkProviderCallsSmsController.java
+++ /dev/null
@@ -1,258 +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 android.content.Context;
-import android.os.UserManager;
-import android.telephony.ServiceState;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.view.View;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.lifecycle.LifecycleObserver;
-import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.OnLifecycleEvent;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settingslib.RestrictedPreference;
-import com.android.settingslib.Utils;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
-
-import java.util.List;
-
-public class NetworkProviderCallsSmsController extends AbstractPreferenceController implements
-        LifecycleObserver, MobileNetworkRepository.MobileNetworkCallback,
-        DefaultSubscriptionReceiver.DefaultSubscriptionListener {
-
-    private static final String TAG = "NetworkProviderCallsSmsController";
-    private static final String KEY = "calls_and_sms";
-    private static final String RTL_MARK = "\u200F";
-
-    private UserManager mUserManager;
-    private TelephonyManager mTelephonyManager;
-    private RestrictedPreference mPreference;
-    private boolean mIsRtlMode;
-    private LifecycleOwner mLifecycleOwner;
-    private MobileNetworkRepository mMobileNetworkRepository;
-    private List<SubscriptionInfoEntity> mSubInfoEntityList;
-    private int mDefaultVoiceSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-    private int mDefaultSmsSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-    private DefaultSubscriptionReceiver mDataSubscriptionChangedReceiver;
-
-    /**
-     * The summary text and click behavior of the "Calls & SMS" item on the
-     * Network & internet page.
-     */
-    public NetworkProviderCallsSmsController(Context context, Lifecycle lifecycle,
-            LifecycleOwner lifecycleOwner) {
-        super(context);
-
-        mUserManager = context.getSystemService(UserManager.class);
-        mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
-        mIsRtlMode = context.getResources().getConfiguration().getLayoutDirection()
-                == View.LAYOUT_DIRECTION_RTL;
-        mLifecycleOwner = lifecycleOwner;
-        mMobileNetworkRepository = MobileNetworkRepository.getInstance(context);
-        mDataSubscriptionChangedReceiver = new DefaultSubscriptionReceiver(context, this);
-        if (lifecycle != null) {
-            lifecycle.addObserver(this);
-        }
-    }
-
-    @OnLifecycleEvent(Event.ON_RESUME)
-    public void onResume() {
-        mMobileNetworkRepository.addRegister(mLifecycleOwner, this,
-                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-        mMobileNetworkRepository.updateEntity();
-        mDataSubscriptionChangedReceiver.registerReceiver();
-        mDefaultVoiceSubId = SubscriptionManager.getDefaultVoiceSubscriptionId();
-        mDefaultSmsSubId = SubscriptionManager.getDefaultSmsSubscriptionId();
-    }
-
-    @OnLifecycleEvent(Event.ON_PAUSE)
-    public void onPause() {
-        mMobileNetworkRepository.removeRegister(this);
-        mDataSubscriptionChangedReceiver.unRegisterReceiver();
-    }
-
-    @Override
-    public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
-        mPreference = screen.findPreference(getPreferenceKey());
-    }
-
-    @Override
-    public CharSequence getSummary() {
-        List<SubscriptionInfoEntity> list = getSubscriptionInfoList();
-        if (list == null || list.isEmpty()) {
-            return setSummaryResId(R.string.calls_sms_no_sim);
-        } else {
-            final StringBuilder summary = new StringBuilder();
-            SubscriptionInfoEntity[] entityArray = list.toArray(
-                    new SubscriptionInfoEntity[0]);
-            for (SubscriptionInfoEntity subInfo : entityArray) {
-                int subsSize = list.size();
-                int subId = Integer.parseInt(subInfo.subId);
-                final CharSequence displayName = subInfo.uniqueName;
-
-                // Set displayName as summary if there is only one valid SIM.
-                if (subsSize == 1
-                        && list.get(0).isValidSubscription
-                        && isInService(subId)) {
-                    return displayName;
-                }
-
-                CharSequence status = getPreferredStatus(subInfo, subsSize, subId);
-                if (status.toString().isEmpty()) {
-                    // If there are 2 or more SIMs and one of these has no preferred status,
-                    // set only its displayName as summary.
-                    summary.append(displayName);
-                } else {
-                    summary.append(displayName)
-                            .append(" (")
-                            .append(status)
-                            .append(")");
-                }
-                // Do not add ", " for the last subscription.
-                if (list.size() > 0 && !subInfo.equals(list.get(list.size() - 1))) {
-                    summary.append(", ");
-                }
-
-                if (mIsRtlMode) {
-                    summary.insert(0, RTL_MARK).insert(summary.length(), RTL_MARK);
-                }
-            }
-            return summary;
-        }
-    }
-
-    @VisibleForTesting
-    protected CharSequence getPreferredStatus(SubscriptionInfoEntity subInfo, int subsSize,
-            int subId) {
-        String status = "";
-        boolean isCallPreferred = subInfo.getSubId() == getDefaultVoiceSubscriptionId();
-        boolean isSmsPreferred = subInfo.getSubId() == getDefaultSmsSubscriptionId();
-
-        if (!subInfo.isValidSubscription || !isInService(subId)) {
-            status = setSummaryResId(subsSize > 1 ? R.string.calls_sms_unavailable :
-                    R.string.calls_sms_temp_unavailable);
-        } else {
-            if (isCallPreferred && isSmsPreferred) {
-                status = setSummaryResId(R.string.calls_sms_preferred);
-            } else if (isCallPreferred) {
-                status = setSummaryResId(R.string.calls_sms_calls_preferred);
-            } else if (isSmsPreferred) {
-                status = setSummaryResId(R.string.calls_sms_sms_preferred);
-            }
-        }
-        return status;
-    }
-
-    private String setSummaryResId(int resId) {
-        return mContext.getResources().getString(resId);
-    }
-
-    @VisibleForTesting
-    protected List<SubscriptionInfoEntity> getSubscriptionInfoList() {
-        return mSubInfoEntityList;
-    }
-
-    private void update() {
-        if (mPreference == null || mPreference.isDisabledByAdmin()) {
-            return;
-        }
-        refreshSummary(mPreference);
-        mPreference.setOnPreferenceClickListener(null);
-        mPreference.setFragment(null);
-
-        if (mSubInfoEntityList == null || mSubInfoEntityList.isEmpty()) {
-            mPreference.setEnabled(false);
-        } else {
-            mPreference.setEnabled(true);
-            mPreference.setFragment(NetworkProviderCallsSmsFragment.class.getCanonicalName());
-        }
-    }
-
-    @Override
-    public boolean isAvailable() {
-        return SubscriptionUtil.isSimHardwareVisible(mContext) &&
-                mUserManager.isAdminUser();
-    }
-
-    @Override
-    public String getPreferenceKey() {
-        return KEY;
-    }
-
-    @Override
-    public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
-        update();
-    }
-
-    @Override
-    public void updateState(Preference preference) {
-        super.updateState(preference);
-        if (preference == null) {
-            return;
-        }
-        refreshSummary(mPreference);
-        update();
-    }
-
-    @VisibleForTesting
-    protected boolean isInService(int subId) {
-        ServiceState serviceState =
-                mTelephonyManager.createForSubscriptionId(subId).getServiceState();
-        return Utils.isInService(serviceState);
-    }
-
-    @Override
-    public void onActiveSubInfoChanged(List<SubscriptionInfoEntity> activeSubInfoList) {
-        mSubInfoEntityList = activeSubInfoList;
-        update();
-    }
-
-    @VisibleForTesting
-    protected int getDefaultVoiceSubscriptionId() {
-        return mDefaultVoiceSubId;
-    }
-
-    @VisibleForTesting
-    protected int getDefaultSmsSubscriptionId() {
-        return mDefaultSmsSubId;
-    }
-
-    @Override
-    public void onDefaultVoiceChanged(int defaultVoiceSubId) {
-        mDefaultVoiceSubId = defaultVoiceSubId;
-        update();
-    }
-
-    @Override
-    public void onDefaultSmsChanged(int defaultSmsSubId) {
-        mDefaultSmsSubId = defaultSmsSubId;
-        update();
-    }
-}
diff --git a/src/com/android/settings/network/NetworkProviderCallsSmsController.kt b/src/com/android/settings/network/NetworkProviderCallsSmsController.kt
new file mode 100644
index 0000000..a265041
--- /dev/null
+++ b/src/com/android/settings/network/NetworkProviderCallsSmsController.kt
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network
+
+import android.app.settings.SettingsEnums
+import android.content.Context
+import android.content.IntentFilter
+import android.os.UserManager
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager
+import androidx.annotation.VisibleForTesting
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.PermPhoneMsg
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.lifecycle.viewmodel.compose.viewModel
+import com.android.settings.R
+import com.android.settings.core.SubSettingLauncher
+import com.android.settings.spa.preference.ComposePreferenceController
+import com.android.settingslib.Utils
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.ui.SettingsIcon
+import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverFlow
+import com.android.settingslib.spaprivileged.framework.common.userManager
+import com.android.settingslib.spaprivileged.framework.compose.placeholder
+import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
+import com.android.settingslib.spaprivileged.template.preference.RestrictedPreference
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+/**
+ * The summary text and click behavior of the "Calls & SMS" item on the Network & internet page.
+ */
+open class NetworkProviderCallsSmsController @JvmOverloads constructor(
+    context: Context,
+    preferenceKey: String,
+    private val getDisplayName: (SubscriptionInfo) -> CharSequence = { subInfo ->
+        SubscriptionUtil.getUniqueSubscriptionDisplayName(subInfo, context)
+    },
+    private val isInService: (Int) -> Boolean = IsInServiceImpl(context)::isInService,
+) : ComposePreferenceController(context, preferenceKey) {
+
+    override fun getAvailabilityStatus() = when {
+        !SubscriptionUtil.isSimHardwareVisible(mContext) -> UNSUPPORTED_ON_DEVICE
+        !mContext.userManager.isAdminUser -> DISABLED_FOR_USER
+        else -> AVAILABLE
+    }
+
+    @Composable
+    override fun Content() {
+        Column {
+            CallsAndSms()
+            HorizontalDivider()
+        }
+    }
+
+    @Composable
+    private fun CallsAndSms() {
+        val viewModel: SubscriptionInfoListViewModel = viewModel()
+        val subscriptionInfos by viewModel.subscriptionInfoListFlow.collectAsStateWithLifecycle()
+        val summary by remember { summaryFlow(viewModel.subscriptionInfoListFlow) }
+            .collectAsStateWithLifecycle(initialValue = placeholder())
+        RestrictedPreference(
+            model = object : PreferenceModel {
+                override val title = stringResource(R.string.calls_and_sms)
+                override val icon = @Composable { SettingsIcon(Icons.Outlined.PermPhoneMsg) }
+                override val summary = { summary }
+                override val enabled = { subscriptionInfos.isNotEmpty() }
+                override val onClick = {
+                    SubSettingLauncher(mContext).apply {
+                        setDestination(NetworkProviderCallsSmsFragment::class.qualifiedName)
+                        setSourceMetricsCategory(SettingsEnums.SETTINGS_NETWORK_CATEGORY)
+                    }.launch()
+                }
+            },
+            restrictions = Restrictions(keys = listOf(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)),
+        )
+    }
+
+    private fun summaryFlow(subscriptionInfoListFlow: Flow<List<SubscriptionInfo>>) = combine(
+        subscriptionInfoListFlow,
+        mContext.defaultVoiceSubscriptionFlow(),
+        mContext.defaultSmsSubscriptionFlow(),
+        ::getSummary,
+    ).flowOn(Dispatchers.Default)
+
+    @VisibleForTesting
+    fun getSummary(
+        activeSubscriptionInfoList: List<SubscriptionInfo>,
+        defaultVoiceSubscriptionId: Int,
+        defaultSmsSubscriptionId: Int,
+    ): String {
+        if (activeSubscriptionInfoList.isEmpty()) {
+            return mContext.getString(R.string.calls_sms_no_sim)
+        }
+
+        activeSubscriptionInfoList.singleOrNull()?.let {
+            // Set displayName as summary if there is only one valid SIM.
+            if (isInService(it.subscriptionId)) return it.displayName.toString()
+        }
+
+        return activeSubscriptionInfoList.joinToString { subInfo ->
+            val displayName = getDisplayName(subInfo)
+
+            val subId = subInfo.subscriptionId
+            val statusResId = getPreferredStatus(
+                subId = subId,
+                subsSize = activeSubscriptionInfoList.size,
+                isCallPreferred = subId == defaultVoiceSubscriptionId,
+                isSmsPreferred = subId == defaultSmsSubscriptionId,
+            )
+            if (statusResId == null) {
+                // If there are 2 or more SIMs and one of these has no preferred status,
+                // set only its displayName as summary.
+                displayName
+            } else {
+                "$displayName (${mContext.getString(statusResId)})"
+            }
+        }
+    }
+
+    private fun getPreferredStatus(
+        subId: Int,
+        subsSize: Int,
+        isCallPreferred: Boolean,
+        isSmsPreferred: Boolean,
+    ): Int? = when {
+        !isInService(subId) -> {
+            if (subsSize > 1) {
+                R.string.calls_sms_unavailable
+            } else {
+                R.string.calls_sms_temp_unavailable
+            }
+        }
+
+        isCallPreferred && isSmsPreferred -> R.string.calls_sms_preferred
+        isCallPreferred -> R.string.calls_sms_calls_preferred
+        isSmsPreferred -> R.string.calls_sms_sms_preferred
+        else -> null
+    }
+}
+
+private fun Context.defaultVoiceSubscriptionFlow(): Flow<Int> =
+    merge(
+        flowOf(null), // kick an initial value
+        broadcastReceiverFlow(
+            IntentFilter(TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED)
+        ),
+    ).map { SubscriptionManager.getDefaultVoiceSubscriptionId() }
+        .conflate().flowOn(Dispatchers.Default)
+
+private fun Context.defaultSmsSubscriptionFlow(): Flow<Int> =
+    merge(
+        flowOf(null), // kick an initial value
+        broadcastReceiverFlow(
+            IntentFilter(SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED)
+        ),
+    ).map { SubscriptionManager.getDefaultSmsSubscriptionId() }
+        .conflate().flowOn(Dispatchers.Default)
+
+private class IsInServiceImpl(context: Context) {
+    private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
+
+    fun isInService(subId: Int): Boolean {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) return false
+
+        val serviceState = telephonyManager.createForSubscriptionId(subId).serviceState
+        return Utils.isInService(serviceState)
+    }
+}
diff --git a/src/com/android/settings/network/SubscriptionInfoListViewModel.kt b/src/com/android/settings/network/SubscriptionInfoListViewModel.kt
new file mode 100644
index 0000000..d30b21d
--- /dev/null
+++ b/src/com/android/settings/network/SubscriptionInfoListViewModel.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network
+
+import android.app.Application
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.plus
+
+class SubscriptionInfoListViewModel(application: Application) : AndroidViewModel(application) {
+    private val scope = viewModelScope + Dispatchers.Default
+
+    val subscriptionInfoListFlow = callbackFlow<List<SubscriptionInfo>> {
+        val subscriptionManager = application.getSystemService(SubscriptionManager::class.java)!!
+
+        val listener = object : SubscriptionManager.OnSubscriptionsChangedListener() {
+            override fun onSubscriptionsChanged() {
+                trySend(subscriptionManager.activeSubscriptionInfoList ?: emptyList())
+            }
+        }
+
+        subscriptionManager.addOnSubscriptionsChangedListener(
+            Dispatchers.Default.asExecutor(),
+            listener,
+        )
+
+        awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(listener) }
+    }.conflate().stateIn(scope, SharingStarted.Eagerly, initialValue = emptyList())
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
index 87cd544..14306e0 100644
--- a/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/PreviewSizeSeekBarControllerTest.java
@@ -26,31 +26,39 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.Activity;
 import android.content.ComponentName;
-import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.view.LayoutInflater;
 import android.widget.PopupWindow;
 import android.widget.SeekBar;
 
+import androidx.fragment.app.testing.EmptyFragmentActivity;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
 import androidx.preference.PreferenceViewHolder;
 import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
 
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.testutils.shadow.ShadowFragment;
-import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
 import com.android.settings.widget.LabeledSeekBarPreference;
+import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
+
+import com.google.android.setupcompat.util.WizardManagerHelper;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
 import org.robolectric.annotation.LooperMode;
@@ -64,10 +72,16 @@
 @LooperMode(LooperMode.Mode.LEGACY)
 @Config(shadows = {ShadowInteractionJankMonitor.class})
 public class PreviewSizeSeekBarControllerTest {
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    @Rule
+    public ActivityScenarioRule<EmptyFragmentActivity> rule =
+            new ActivityScenarioRule<>(EmptyFragmentActivity.class);
     private static final String FONT_SIZE_KEY = "font_size";
     private static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
-    @Spy
-    private final Context mContext = ApplicationProvider.getApplicationContext();
+    private Activity mContext;
     private PreviewSizeSeekBarController mSeekBarController;
     private FontSizeData mFontSizeData;
     private LabeledSeekBarPreference mSeekBarPreference;
@@ -91,7 +105,9 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        ShadowInteractionJankMonitor.reset();
 
+        rule.getScenario().onActivity(activity -> mContext = activity);
         mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat);
         mFragment = spy(new TestFragment());
         when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
@@ -197,6 +213,24 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_REMOVE_QS_TOOLTIP_IN_SUW)
+    public void onProgressChanged_inSuw_toolTipShouldNotShown() {
+        Intent intent = mContext.getIntent();
+        intent.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true);
+        mContext.setIntent(intent);
+        mSeekBarController.displayPreference(mPreferenceScreen);
+
+        // Simulate changing the progress for the first time
+        int newProgress = (mSeekBarPreference.getProgress() != 0) ? 0 : mSeekBarPreference.getMax();
+        mSeekBarPreference.setProgress(newProgress);
+        mSeekBarPreference.onProgressChanged(new SeekBar(mContext),
+                newProgress,
+                /* fromUser= */ false);
+
+        assertThat(getLatestPopupWindow()).isNull();
+    }
+
+    @Test
     public void onProgressChanged_tooltipViewHasBeenShown_notShowTooltipView() {
         mSeekBarController.displayPreference(mPreferenceScreen);
         // Simulate changing the progress for the first time
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
index 66211a2..2c59c26 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
@@ -60,6 +60,8 @@
 import com.android.settings.testutils.shadow.ShadowFragment;
 import com.android.settingslib.widget.TopIntroPreference;
 
+import com.google.android.setupcompat.util.WizardManagerHelper;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -302,6 +304,20 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(com.android.settings.accessibility.Flags.FLAG_REMOVE_QS_TOOLTIP_IN_SUW)
+    @Config(shadows = ShadowFragment.class)
+    public void onPreferenceToggledOnEnabledService_inSuw_toolTipViewShouldNotShow() {
+        Intent suwIntent = new Intent();
+        suwIntent.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true);
+        when(mActivity.getIntent()).thenReturn(suwIntent);
+
+        mFragment.onPreferenceToggled(
+                ToggleFeaturePreferenceFragment.KEY_USE_SERVICE_PREFERENCE, /* enabled= */ true);
+
+        assertThat(getLatestPopupWindow()).isNull();
+    }
+
+    @Test
     @Config(shadows = ShadowFragment.class)
     public void onPreferenceToggledOnEnabledService_tooltipViewShown_notShowTooltipView() {
         mFragment.onPreferenceToggled(
diff --git a/tests/spa_unit/src/com/android/settings/network/NetworkProviderCallsSmsControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/NetworkProviderCallsSmsControllerTest.kt
new file mode 100644
index 0000000..110fd5e
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/NetworkProviderCallsSmsControllerTest.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network
+
+import android.content.Context
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class NetworkProviderCallsSmsControllerTest {
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    private var isInService: (Int) -> Boolean = { true }
+
+    private val controller = NetworkProviderCallsSmsController(
+        context = context,
+        preferenceKey = TEST_KEY,
+        getDisplayName = { subInfo -> subInfo.displayName },
+        isInService = { isInService(it) },
+    )
+
+    @Test
+    fun getSummary_noSim_returnNoSim() {
+        val summary = controller.getSummary(
+            activeSubscriptionInfoList = emptyList(),
+            defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+            defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+        )
+
+        assertThat(summary).isEqualTo(context.getString(R.string.calls_sms_no_sim))
+    }
+
+    @Test
+    fun getSummary_invalidSubId_returnUnavailable() {
+        isInService = { false }
+
+        val summary = controller.getSummary(
+            activeSubscriptionInfoList = listOf(SUB_INFO_1),
+            defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+            defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+        )
+
+        assertThat(summary).isEqualTo("Sub 1 (Temporarily unavailable)")
+    }
+
+    @Test
+    fun getSummary_oneIsInvalidSubIdTwoIsValidSubId_returnOneIsUnavailable() {
+        isInService = { it == SUB_INFO_2.subscriptionId }
+
+        val summary = controller.getSummary(
+            activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2),
+            defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+            defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+        )
+
+        assertThat(summary).isEqualTo("Sub 1 (unavailable), Sub 2")
+    }
+
+    @Test
+    fun getSummary_oneSubscription_returnDisplayName() {
+        val summary = controller.getSummary(
+            activeSubscriptionInfoList = listOf(SUB_INFO_1),
+            defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+            defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+        )
+
+        assertThat(summary).isEqualTo(DISPLAY_NAME_1)
+    }
+
+    @Test
+    fun getSummary_allSubscriptionsHaveNoPreferredStatus_returnDisplayName() {
+        val summary = controller.getSummary(
+            activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2),
+            defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+            defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+        )
+
+        assertThat(summary).isEqualTo("Sub 1, Sub 2")
+    }
+
+    @Test
+    fun getSummary_oneSubscriptionsIsCallPreferredTwoIsSmsPreferred_returnStatus() {
+        val summary = controller.getSummary(
+            activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2),
+            defaultVoiceSubscriptionId = SUB_INFO_1.subscriptionId,
+            defaultSmsSubscriptionId = SUB_INFO_2.subscriptionId,
+        )
+
+        assertThat(summary).isEqualTo("Sub 1 (preferred for calls), Sub 2 (preferred for SMS)")
+    }
+
+    @Test
+    fun getSummary_oneSubscriptionsIsSmsPreferredTwoIsCallPreferred_returnStatus() {
+        val summary = controller.getSummary(
+            activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2),
+            defaultVoiceSubscriptionId = SUB_INFO_2.subscriptionId,
+            defaultSmsSubscriptionId = SUB_INFO_1.subscriptionId,
+        )
+
+        assertThat(summary).isEqualTo("Sub 1 (preferred for SMS), Sub 2 (preferred for calls)")
+    }
+
+    @Test
+    fun getSummary_oneSubscriptionsIsSmsPreferredAndIsCallPreferred_returnStatus() {
+        val summary = controller.getSummary(
+            activeSubscriptionInfoList = listOf(SUB_INFO_1, SUB_INFO_2),
+            defaultVoiceSubscriptionId = SUB_INFO_1.subscriptionId,
+            defaultSmsSubscriptionId = SUB_INFO_1.subscriptionId,
+        )
+
+        assertThat(summary).isEqualTo("Sub 1 (preferred), Sub 2")
+    }
+
+    private companion object {
+        const val TEST_KEY = "test_key"
+        const val DISPLAY_NAME_1 = "Sub 1"
+        const val DISPLAY_NAME_2 = "Sub 2"
+
+        val SUB_INFO_1: SubscriptionInfo = SubscriptionInfo.Builder().apply {
+            setId(1)
+            setDisplayName(DISPLAY_NAME_1)
+        }.build()
+
+        val SUB_INFO_2: SubscriptionInfo = SubscriptionInfo.Builder().apply {
+            setId(2)
+            setDisplayName(DISPLAY_NAME_2)
+        }.build()
+    }
+}
diff --git a/tests/unit/src/com/android/settings/network/NetworkProviderCallsSmsControllerTest.java b/tests/unit/src/com/android/settings/network/NetworkProviderCallsSmsControllerTest.java
deleted file mode 100644
index 51aecc5..0000000
--- a/tests/unit/src/com/android/settings/network/NetworkProviderCallsSmsControllerTest.java
+++ /dev/null
@@ -1,360 +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.junit.Assert.assertTrue;
-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.telephony.TelephonyManager;
-import android.text.TextUtils;
-
-import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.LifecycleRegistry;
-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.RestrictedPreference;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
-
-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.List;
-
-
-@RunWith(AndroidJUnit4.class)
-public class NetworkProviderCallsSmsControllerTest {
-
-    private static final String SUB_ID_1 = "1";
-    private static final String SUB_ID_2 = "2";
-    private static final String INVALID_SUB_ID = "-1";
-    private static final String KEY_PREFERENCE_CALLS_SMS = "calls_and_sms";
-    private static final String DISPLAY_NAME_1 = "Sub 1";
-    private static final String DISPLAY_NAME_2 = "Sub 2";
-    private static final String SUB_MCC_1 = "123";
-    private static final String SUB_MNC_1 = "456";
-    private static final String SUB_MCC_2 = "223";
-    private static final String SUB_MNC_2 = "456";
-    private static final String SUB_COUNTRY_ISO_1 = "Sub 1";
-    private static final String SUB_COUNTRY_ISO_2 = "Sub 2";
-
-    @Mock
-    private SubscriptionInfoEntity mSubInfo1;
-    @Mock
-    private SubscriptionInfoEntity mSubInfo2;
-    @Mock
-    private Lifecycle mLifecycle;
-    @Mock
-    private LifecycleOwner mLifecycleOwner;
-
-    private LifecycleRegistry mLifecycleRegistry;
-    private MockNetworkProviderCallsSmsController mController;
-    private PreferenceManager mPreferenceManager;
-    private PreferenceScreen mPreferenceScreen;
-    private RestrictedPreference mPreference;
-    private Context mContext;
-    private List<SubscriptionInfoEntity> mSubscriptionInfoEntityList = new ArrayList<>();
-
-    /**
-     * Mock the NetworkProviderCallsSmsController that allows one to set a default voice
-     * and SMS subscription ID.
-     */
-    private class MockNetworkProviderCallsSmsController extends
-            com.android.settings.network.NetworkProviderCallsSmsController {
-        public MockNetworkProviderCallsSmsController(Context context, Lifecycle lifecycle,
-                LifecycleOwner lifecycleOwner) {
-            super(context, lifecycle, lifecycleOwner);
-        }
-
-        private List<SubscriptionInfoEntity> mSubscriptionInfoEntity;
-        private boolean mIsInService;
-        private int mDefaultVoiceSubscriptionId;
-        private int mDefaultSmsSubscriptionId;
-
-        @Override
-        protected List<SubscriptionInfoEntity> getSubscriptionInfoList() {
-            return mSubscriptionInfoEntity;
-        }
-
-        public void setSubscriptionInfoList(List<SubscriptionInfoEntity> list) {
-            mSubscriptionInfoEntity = list;
-        }
-
-        @Override
-        protected boolean isInService(int subId) {
-            return mIsInService;
-        }
-
-        public void setInService(boolean inService) {
-            mIsInService = inService;
-        }
-
-        @Override
-        protected int getDefaultVoiceSubscriptionId() {
-            return mDefaultVoiceSubscriptionId;
-        }
-
-        @Override
-        protected int getDefaultSmsSubscriptionId() {
-            return mDefaultSmsSubscriptionId;
-        }
-
-        public void setDefaultVoiceSubscriptionId(int subscriptionId) {
-            mDefaultVoiceSubscriptionId = subscriptionId;
-        }
-
-        public void setDefaultSmsSubscriptionId(int subscriptionId) {
-            mDefaultSmsSubscriptionId = subscriptionId;
-        }
-    }
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = spy(ApplicationProvider.getApplicationContext());
-
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
-        mPreferenceManager = new PreferenceManager(mContext);
-        mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
-        mPreference = new RestrictedPreference(mContext);
-        mPreference.setKey(KEY_PREFERENCE_CALLS_SMS);
-        mController = new MockNetworkProviderCallsSmsController(mContext, mLifecycle,
-                mLifecycleOwner);
-        mController.setInService(true);
-        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 String setSummaryResId(String resName) {
-        return ResourcesUtils.getResourcesString(mContext, resName);
-    }
-
-    @Test
-    @UiThreadTest
-    public void getSummary_noSim_returnNoSim() {
-        mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
-        displayPreferenceWithLifecycle();
-
-        assertTrue(TextUtils.equals(mController.getSummary(),
-                setSummaryResId("calls_sms_no_sim")));
-    }
-
-    private SubscriptionInfoEntity setupSubscriptionInfoEntity(String subId, int slotId,
-            int carrierId, String displayName, String mcc, String mnc, String countryIso,
-            int cardId, boolean isValid, boolean isActive, boolean isAvailable) {
-        return new SubscriptionInfoEntity(subId, slotId, carrierId,
-                displayName, displayName, 0, mcc, mnc, countryIso, false, cardId,
-                TelephonyManager.DEFAULT_PORT_INDEX, false, null,
-                SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, displayName, false,
-                "1234567890", true, false, isValid,
-                true, isActive, isAvailable, false);
-    }
-
-    @Test
-    @UiThreadTest
-    public void getSummary_invalidSubId_returnUnavailable() {
-
-        mSubInfo1 = setupSubscriptionInfoEntity(INVALID_SUB_ID,
-                SubscriptionManager.INVALID_SIM_SLOT_INDEX, TelephonyManager.UNKNOWN_CARRIER_ID,
-                DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1, SUB_COUNTRY_ISO_1,
-                TelephonyManager.UNINITIALIZED_CARD_ID, false, true, true);
-        mSubscriptionInfoEntityList.add(mSubInfo1);
-        mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
-        displayPreferenceWithLifecycle();
-
-        final StringBuilder summary = new StringBuilder();
-        summary.append(DISPLAY_NAME_1)
-                .append(" (")
-                .append(setSummaryResId("calls_sms_temp_unavailable"))
-                .append(")");
-
-        assertTrue(TextUtils.equals(mController.getSummary(), summary));
-    }
-
-    @Test
-    @UiThreadTest
-    public void getSummary_oneIsInvalidSubIdTwoIsValidSubId_returnOneIsUnavailable() {
-
-        mSubInfo1 = setupSubscriptionInfoEntity(INVALID_SUB_ID,
-                SubscriptionManager.INVALID_SIM_SLOT_INDEX, TelephonyManager.UNKNOWN_CARRIER_ID,
-                DISPLAY_NAME_1, SUB_MCC_1, SUB_MNC_1, SUB_COUNTRY_ISO_1,
-                TelephonyManager.UNINITIALIZED_CARD_ID, false, true, true);
-        mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 1, 1, DISPLAY_NAME_2, SUB_MCC_2,
-                SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, true, true, true);
-        mSubscriptionInfoEntityList.add(mSubInfo1);
-        mSubscriptionInfoEntityList.add(mSubInfo2);
-        mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
-        displayPreferenceWithLifecycle();
-
-        final StringBuilder summary = new StringBuilder();
-        summary.append(DISPLAY_NAME_1)
-                .append(" (")
-                .append(setSummaryResId("calls_sms_unavailable"))
-                .append(")")
-                .append(", ")
-                .append(DISPLAY_NAME_2);
-
-        assertTrue(TextUtils.equals(mController.getSummary(), summary));
-    }
-
-    @Test
-    @UiThreadTest
-    public void getSummary_oneSubscription_returnDisplayName() {
-
-        mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
-                SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
-        mSubscriptionInfoEntityList.add(mSubInfo1);
-        mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
-        displayPreferenceWithLifecycle();
-
-        assertThat(mPreference.getSummary()).isEqualTo(DISPLAY_NAME_1);
-    }
-
-    @Test
-    @UiThreadTest
-    public void getSummary_allSubscriptionsHaveNoPreferredStatus_returnDisplayName() {
-
-        mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
-                SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
-        mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 1, 1, DISPLAY_NAME_2, SUB_MCC_2,
-                SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, true, true, true);
-        mSubscriptionInfoEntityList.add(mSubInfo1);
-        mSubscriptionInfoEntityList.add(mSubInfo2);
-        mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
-        displayPreferenceWithLifecycle();
-
-        final StringBuilder summary = new StringBuilder();
-        summary.append(DISPLAY_NAME_1).append(", ").append(DISPLAY_NAME_2);
-
-        assertTrue(TextUtils.equals(mController.getSummary(), summary));
-    }
-
-    @Test
-    @UiThreadTest
-    public void getSummary_oneSubscriptionsIsCallPreferredTwoIsSmsPreferred_returnStatus() {
-
-        mController.setDefaultVoiceSubscriptionId(Integer.parseInt(SUB_ID_1));
-        mController.setDefaultSmsSubscriptionId(Integer.parseInt(SUB_ID_2));
-
-        mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
-                SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
-        mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 1, 1, DISPLAY_NAME_2, SUB_MCC_2,
-                SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, true, true, true);
-        mSubscriptionInfoEntityList.add(mSubInfo1);
-        mSubscriptionInfoEntityList.add(mSubInfo2);
-        mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
-        displayPreferenceWithLifecycle();
-
-        final StringBuilder summary = new StringBuilder();
-        summary.append(DISPLAY_NAME_1)
-                .append(" (")
-                .append(setSummaryResId("calls_sms_calls_preferred"))
-                .append(")")
-                .append(", ")
-                .append(DISPLAY_NAME_2)
-                .append(" (")
-                .append(setSummaryResId("calls_sms_sms_preferred"))
-                .append(")");
-
-        assertTrue(TextUtils.equals(mController.getSummary(), summary));
-    }
-
-    @Test
-    @UiThreadTest
-    public void getSummary_oneSubscriptionsIsSmsPreferredTwoIsCallPreferred_returnStatus() {
-
-        mController.setDefaultSmsSubscriptionId(Integer.parseInt(SUB_ID_1));
-        mController.setDefaultVoiceSubscriptionId(Integer.parseInt(SUB_ID_2));
-
-        mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
-                SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
-        mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 2, 2, DISPLAY_NAME_2, SUB_MCC_2,
-                SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, true, true, true);
-        mSubscriptionInfoEntityList.add(mSubInfo1);
-        mSubscriptionInfoEntityList.add(mSubInfo2);
-        mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
-        displayPreferenceWithLifecycle();
-
-        final StringBuilder summary = new StringBuilder();
-        summary.append(DISPLAY_NAME_1)
-                .append(" (")
-                .append(setSummaryResId("calls_sms_sms_preferred"))
-                .append(")")
-                .append(", ")
-                .append(DISPLAY_NAME_2)
-                .append(" (")
-                .append(setSummaryResId("calls_sms_calls_preferred"))
-                .append(")");
-
-        assertTrue(TextUtils.equals(mController.getSummary(), summary));
-    }
-
-    @Test
-    @UiThreadTest
-    public void getSummary_oneSubscriptionsIsSmsPreferredAndIsCallPreferred_returnStatus() {
-
-        mController.setDefaultSmsSubscriptionId(Integer.parseInt(SUB_ID_1));
-        mController.setDefaultVoiceSubscriptionId(Integer.parseInt(SUB_ID_1));
-
-        mSubInfo1 = setupSubscriptionInfoEntity(SUB_ID_1, 1, 1, DISPLAY_NAME_1, SUB_MCC_1,
-                SUB_MNC_1, SUB_COUNTRY_ISO_1, 1, true, true, true);
-        mSubInfo2 = setupSubscriptionInfoEntity(SUB_ID_2, 1, 1, DISPLAY_NAME_2, SUB_MCC_2,
-                SUB_MNC_2, SUB_COUNTRY_ISO_2, 1, true, true, true);
-        mSubscriptionInfoEntityList.add(mSubInfo1);
-        mSubscriptionInfoEntityList.add(mSubInfo2);
-        mController.setSubscriptionInfoList(mSubscriptionInfoEntityList);
-        displayPreferenceWithLifecycle();
-
-        final StringBuilder summary = new StringBuilder();
-        summary.append(DISPLAY_NAME_1)
-                .append(" (")
-                .append(setSummaryResId("calls_sms_preferred"))
-                .append(")")
-                .append(", ")
-                .append(DISPLAY_NAME_2);
-
-        assertTrue(TextUtils.equals(mController.getSummary(), summary));
-    }
-}