Merge "Import translations. DO NOT MERGE ANYWHERE"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f399fc8..8b3160f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3672,6 +3672,12 @@
         <service android:name=".sim.SimNotificationService"
                  android:permission="android.permission.BIND_JOB_SERVICE" />
 
+        <activity android:name=".sim.smartForwarding.SmartForwardingActivity"
+            android:theme="@style/Theme.SubSettings.Base"
+            android:exported="true"
+            android:launchMode="singleTask">
+        </activity>
+
         <!-- This is the longest AndroidManifest.xml ever. -->
     </application>
 </manifest>
diff --git a/res/layout/search_bar.xml b/res/layout/search_bar.xml
index c4dd15d..75b43f0 100644
--- a/res/layout/search_bar.xml
+++ b/res/layout/search_bar.xml
@@ -23,7 +23,7 @@
     android:layout_marginTop="@dimen/search_bar_margin"
     android:layout_marginStart="@dimen/search_bar_margin"
     android:layout_marginEnd="@dimen/search_bar_margin"
-    android:layout_marginBottom="16dp"
+    android:layout_marginBottom="@dimen/search_bar_margin_bottom"
     app:layout_scrollFlags="scroll|enterAlways">
 
     <com.google.android.material.card.MaterialCardView
diff --git a/res/layout/settings_collapsing_base_layout.xml b/res/layout/settings_collapsing_base_layout.xml
index be7bf6c..ba9e625 100644
--- a/res/layout/settings_collapsing_base_layout.xml
+++ b/res/layout/settings_collapsing_base_layout.xml
@@ -23,6 +23,7 @@
     android:transitionGroup="true">
 
     <com.google.android.material.appbar.AppBarLayout
+        android:id="@+id/app_bar"
         android:layout_width="match_parent"
         android:layout_height="180dp"
         android:theme="@style/Theme.CollapsingToolbar.Settings">
@@ -38,6 +39,7 @@
             app:statusBarScrim="?android:attr/colorPrimary"
             app:layout_scrollFlags="scroll|exitUntilCollapsed"
             app:expandedTitleMarginStart="18dp"
+            app:expandedTitleMarginEnd="18dp"
             app:toolbarId="@id/action_bar">
 
             <Toolbar
diff --git a/res/layout/settings_homepage_container.xml b/res/layout/settings_homepage_container.xml
index fe119c6..d65d140 100644
--- a/res/layout/settings_homepage_container.xml
+++ b/res/layout/settings_homepage_container.xml
@@ -27,7 +27,7 @@
         android:id="@+id/main_content_scrollable_container"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        app:layout_behavior="com.android.settings.widget.FloatingAppBarScrollingViewBehavior">
+        app:layout_behavior="com.android.settings.widget.HomepageAppBarScrollingViewBehavior">
 
         <LinearLayout
             android:id="@+id/homepage_container"
@@ -53,6 +53,7 @@
     </androidx.core.widget.NestedScrollView>
 
     <com.google.android.material.appbar.AppBarLayout
+        android:id="@+id/app_bar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:touchscreenBlocksFocus="false"
diff --git a/res/values/config.xml b/res/values/config.xml
index d34c481..fd0063e 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -479,4 +479,7 @@
 
     <!-- Orders for overriding tile positions on the homepage -->
     <integer-array name="config_homepage_tile_orders"/>
+
+    <!-- Whether to handle slot change events -->
+    <bool name="config_handle_sim_slot_change">false</bool>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 761280b..8f6be68 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -131,6 +131,7 @@
 
     <!-- Search bar and avatar -->
     <dimen name="search_bar_margin">24dp</dimen>
+    <dimen name="search_bar_margin_bottom">16dp</dimen>
     <dimen name="search_bar_height">48dp</dimen>
     <dimen name="search_bar_text_size">16sp</dimen>
     <dimen name="search_bar_card_elevation">2dp</dimen>
@@ -138,7 +139,7 @@
     <dimen name="avatar_length">@dimen/search_bar_height</dimen>
 
     <!-- Contextual suggestions -->
-    <dimen name="suggestion_height">224dp</dimen>
+    <dimen name="suggestion_height">232dp</dimen>
     <dimen name="suggestion_padding_horizontal">24dp</dimen>
     <dimen name="suggestion_padding_bottom">8dp</dimen>
     <dimen name="suggestion_button_margin_top">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bcae9a5..d72a7bd 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -9981,6 +9981,10 @@
     <!-- Description at the footer of the default USB configuration window that describes how the setting works. -->
     <string name="usb_default_info">When another device is connected and your phone is unlocked, these settings will be applied. Only connect to trusted devices.</string>
 
+    <!-- The title used in USB Preferences which provides the user with the control over this
+         device's power role. -->
+    <string name="usb_power_title">Power options</string>
+
     <!-- Settings item title for USB preference [CHAR LIMIT=35] -->
     <string name="usb_pref">USB</string>
     <!-- Settings screen title for USB preference [CHAR LIMIT=35] -->
@@ -12188,10 +12192,10 @@
     <string name="force_desktop_mode">Force desktop mode</string>
     <!-- UI debug setting: force desktop mode summary [CHAR LIMIT=NONE] -->
     <string name="force_desktop_mode_summary">Force experimental desktop mode on secondary displays</string>
-    <!-- UI debug setting: enable non-resizables in freeform [CHAR LIMIT=60] -->
-    <string name="enable_sizecompat_freeform">Enable freeform sizecompat</string>
-    <!-- UI debug setting: enable non-resizables in freeform summary [CHAR LIMIT=NONE] -->
-    <string name="enable_sizecompat_freeform_summary">Allows sizecompat apps to be in freeform</string>
+    <!-- UI debug setting: enable non-resizables in multi window [CHAR LIMIT=60] -->
+    <string name="enable_non_resizable_multi_window">Enable non-resizable in multi window</string>
+    <!-- UI debug setting: enable non-resizables in multi window summary [CHAR LIMIT=NONE] -->
+    <string name="enable_non_resizable_multi_window_summary">Allows non-resizable apps to be in multi window</string>
 
     <!-- UI debug setting: Force enable "smart dark" UI rendering feature [CHAR LIMIT=60] -->
     <string name="hwui_force_dark_title">Override force-dark</string>
@@ -12554,6 +12558,8 @@
     <string name="airplane_mode_network_available">Airplane mode networks available</string>
     <!-- Summary for warning to disconnect ethernet first then switch to other networks. [CHAR LIMIT=60] -->
     <string name="to_switch_networks_disconnect_ethernet">To switch networks, disconnect ethernet</string>
+    <!-- Summary for cannot switch networks to Wi-Fi nor mobile data networks while connected to an ethernet network. [CHAR LIMIT=60] -->
+    <string name="cannot_switch_networks_while_connected">Cannot switch networks while connected</string>
 
     <!-- Summary text separator for preferences including a short description
          (eg. "Connected / 5G"). [CHAR LIMIT=50] -->
@@ -12627,4 +12633,29 @@
 
     <!-- Default preference title for showing all apps on device [CHAR_LIMIT=50]-->
     <string name="default_see_all_apps_title">See all apps</string>
+
+    <!-- Title for smart forwarding [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_title">Smart Forwarding</string>
+    <!-- Summary for smart forwarding enabled [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_summary_enabled">Smart Forwarding Enabled</string>
+    <!-- Summary for smart forwarding disabled [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_summary_disabled">Smart Forwarding Disabled</string>
+    <!-- Dialog title for smart forwarding ongoing [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_ongoing_title">Call Settings</string>
+    <!-- Subtext for smart forwarding ongoing [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_ongoing_text">Updating Settings...</string>
+    <!-- Dialog title for smart forwarding failed [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_failed_title">Call Settings error</string>
+    <!-- Subtext for smart forwarding failed [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_failed_text">Network or SIM card error.</string>
+    <!-- Subtext for sim is not activated [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_failed_not_activated_text">Sim is not activated.</string>
+    <!-- Title when smart forwarding can't get the phone number [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_input_mdn_title">Enter Phone numbers</string>
+    <!-- Dialog title when user update the phone number [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_input_mdn_dialog_title">Enter Phone number</string>
+    <!-- Alert Dialog text when user didn't input the phone number [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_missing_mdn_text">Phone number is missing.</string>
+    <!-- Alert Dialog text when user didn't input the phone number [CHAR LIMIT=50]-->
+    <string name="smart_forwarding_missing_alert_dialog_text">OK</string>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 0f3875d..b54028e 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -792,7 +792,7 @@
     <style name="ContextualSuggestionText" parent="@android:style/TextAppearance.DeviceDefault">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
-        <item name="android:textSize">32sp</item>
+        <item name="android:textSize">36sp</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
     </style>
diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml
index 2e70c44..a801ae1 100644
--- a/res/xml/app_notification_settings.xml
+++ b/res/xml/app_notification_settings.xml
@@ -16,7 +16,8 @@
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:settings="http://schemas.android.com/apk/res-auto"
-        android:key="app_notifications">
+        android:key="app_notifications"
+        android:title="@string/notifications_title">
 
     <com.android.settingslib.widget.LayoutPreference
         android:key="pref_app_header"
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 06887f8..faf1cfd 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -640,9 +640,9 @@
             android:summary="@string/force_desktop_mode_summary" />
 
         <SwitchPreference
-            android:key="enable_sizecompat_freeform"
-            android:title="@string/enable_sizecompat_freeform"
-            android:summary="@string/enable_sizecompat_freeform_summary" />
+            android:key="enable_non_resizable_multi_window"
+            android:title="@string/enable_non_resizable_multi_window"
+            android:summary="@string/enable_non_resizable_multi_window_summary" />
 
         <Preference
             android:key="reset_shortcut_manager_throttling"
diff --git a/res/xml/network_provider_settings.xml b/res/xml/network_provider_settings.xml
index 17546a5..67fc73d 100644
--- a/res/xml/network_provider_settings.xml
+++ b/res/xml/network_provider_settings.xml
@@ -36,6 +36,12 @@
         android:layout="@layout/view_airplane_mode_networks_button"
         settings:allowDividerBelow="true"/>
 
+    <Preference
+        android:key="connected_ethernet_network"
+        android:title="@string/ethernet"
+        android:summary="@string/cannot_switch_networks_while_connected"
+        android:icon="@drawable/ic_settings_ethernet"/>
+
     <PreferenceCategory
         android:key="connected_access_point"
         android:layout="@layout/preference_category_no_label"/>
diff --git a/res/xml/smart_forwarding_mdn_handler.xml b/res/xml/smart_forwarding_mdn_handler.xml
new file mode 100644
index 0000000..cefbcbf
--- /dev/null
+++ b/res/xml/smart_forwarding_mdn_handler.xml
@@ -0,0 +1,27 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+    <fragment android:id="@+id/fragment_settings"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_above="@+id/cancel"
+            android:name="com.android.settings.sim.smartForwarding.MDNHandlerHeaderFragment"
+            android:layout_marginBottom="15dp" />
+
+    <Button android:id="@+id/process"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:layout_margin="5dip"
+            android:text="process" />
+
+    <Button android:id="@+id/cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_margin="5dip"
+            android:text="cancel" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/xml/smart_forwarding_mdn_handler_header.xml b/res/xml/smart_forwarding_mdn_handler_header.xml
new file mode 100644
index 0000000..30e873f
--- /dev/null
+++ b/res/xml/smart_forwarding_mdn_handler_header.xml
@@ -0,0 +1,18 @@
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:key="network_and_internet_screen"
+    android:title="@string/smart_forwarding_input_mdn_title">
+
+    <EditTextPreference
+            android:key="slot0_phone_number"
+            android:title="SIM 1"
+            android:dialogTitle="@string/smart_forwarding_input_mdn_dialog_title"
+            android:persistent="false" />
+
+    <EditTextPreference
+            android:key="slot1_phone_number"
+            android:title="SIM 2"
+            android:dialogTitle="@string/smart_forwarding_input_mdn_dialog_title"
+            android:persistent="false" />
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/smart_forwarding_switch.xml b/res/xml/smart_forwarding_switch.xml
new file mode 100644
index 0000000..dda9d5a
--- /dev/null
+++ b/res/xml/smart_forwarding_switch.xml
@@ -0,0 +1,14 @@
+<PreferenceScreen
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:settings="http://schemas.android.com/apk/res-auto"
+        android:key="smart_forwarding_preference"
+        android:title="@string/smart_forwarding_title">
+
+      <SwitchPreference
+          android:key="smart_forwarding_switch"
+          android:title="Smart forwarding"
+          android:summaryOff="@string/smart_forwarding_summary_disabled"
+          android:summaryOn="@string/smart_forwarding_summary_enabled"
+          android:disableDependentsState="true" />
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/usb_details_fragment.xml b/res/xml/usb_details_fragment.xml
index 4a6cefa..62ccf08 100644
--- a/res/xml/usb_details_fragment.xml
+++ b/res/xml/usb_details_fragment.xml
@@ -34,6 +34,7 @@
         android:title="@string/usb_use"/>
 
     <PreferenceCategory
-        android:key="usb_details_power_role"/>
+        android:key="usb_details_power_role"
+        android:title="@string/usb_power_title"/>
 
 </PreferenceScreen>
diff --git a/src/com/android/settings/IccLockSettings.java b/src/com/android/settings/IccLockSettings.java
index a9b5b31..e89e84b 100644
--- a/src/com/android/settings/IccLockSettings.java
+++ b/src/com/android/settings/IccLockSettings.java
@@ -56,6 +56,7 @@
 import androidx.preference.SwitchPreference;
 
 import com.android.settings.network.ProxySubscriptionManager;
+import com.android.settings.network.SubscriptionUtil;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -310,7 +311,8 @@
                 mTabHost.addTab(buildTabSpec(tag,
                         String.valueOf(subInfo == null
                                 ? getContext().getString(R.string.sim_editor_title, slot + 1)
-                                : subInfo.getDisplayName())));
+                                : SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                                        subInfo, getContext()))));
             }
 
             mTabHost.setCurrentTabByTag(getTagForSlotId(mSlotId));
diff --git a/src/com/android/settings/ResetNetwork.java b/src/com/android/settings/ResetNetwork.java
index c4fa90d..854a237 100644
--- a/src/com/android/settings/ResetNetwork.java
+++ b/src/com/android/settings/ResetNetwork.java
@@ -47,6 +47,7 @@
 import com.android.settings.core.InstrumentedFragment;
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
+import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.password.ChooseLockSettingsHelper;
 import com.android.settings.password.ConfirmLockPattern;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
@@ -194,7 +195,8 @@
                     // Set the first selected value to the default
                     selectedIndex = subscriptionNames.size();
                 }
-                String name = record.getDisplayName().toString();
+                String name = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                        record, getContext()).toString();
                 if (TextUtils.isEmpty(name)) {
                     name = record.getNumber();
                 }
diff --git a/src/com/android/settings/datausage/CellDataPreference.java b/src/com/android/settings/datausage/CellDataPreference.java
index 6dc40e8..0e47bc4 100644
--- a/src/com/android/settings/datausage/CellDataPreference.java
+++ b/src/com/android/settings/datausage/CellDataPreference.java
@@ -36,6 +36,7 @@
 import com.android.settings.R;
 import com.android.settings.network.MobileDataEnabledListener;
 import com.android.settings.network.ProxySubscriptionManager;
+import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.CustomDialogPreferenceCompat;
 
@@ -200,12 +201,14 @@
 
         final String previousName = (nextSir == null)
             ? getContext().getResources().getString(R.string.sim_selection_required_pref)
-            : nextSir.getDisplayName().toString();
+                : SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                        nextSir, getContext()).toString();
 
         builder.setTitle(R.string.sim_change_data_title);
         builder.setMessage(getContext().getString(R.string.sim_change_data_message,
-                String.valueOf(currentSir != null ? currentSir.getDisplayName() : null),
-                previousName));
+                String.valueOf(currentSir != null
+                    ? SubscriptionUtil.getUniqueSubscriptionDisplayName(currentSir, getContext())
+                    : null), previousName));
 
         builder.setPositiveButton(R.string.okay, listener);
         builder.setNegativeButton(R.string.cancel, null);
diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java
index 9d9bf9c..b11935f 100644
--- a/src/com/android/settings/datausage/DataUsageSummary.java
+++ b/src/com/android/settings/datausage/DataUsageSummary.java
@@ -35,6 +35,7 @@
 import com.android.settings.R;
 import com.android.settings.datausage.lib.DataUsageLib;
 import com.android.settings.network.ProxySubscriptionManager;
+import com.android.settings.network.SubscriptionUtil;
 import com.android.settingslib.NetworkPolicyEditor;
 import com.android.settingslib.core.AbstractPreferenceController;
 
@@ -170,9 +171,11 @@
         category.setTemplate(DataUsageLib.getMobileTemplate(getContext(), subId),
                 subId, services);
         category.pushTemplates(services);
-        if (subInfo != null && !TextUtils.isEmpty(subInfo.getDisplayName())) {
+        final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                subInfo, getContext());
+        if (subInfo != null && !TextUtils.isEmpty(displayName)) {
             Preference title  = category.findPreference(KEY_MOBILE_USAGE_TITLE);
-            title.setTitle(subInfo.getDisplayName());
+            title.setTitle(displayName);
         }
     }
 
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 7b4926a..e9dd9fd 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -553,7 +553,7 @@
         controllers.add(new ResizableActivityPreferenceController(context));
         controllers.add(new FreeformWindowsPreferenceController(context));
         controllers.add(new DesktopModePreferenceController(context));
-        controllers.add(new SizeCompatFreeformPreferenceController(context));
+        controllers.add(new NonResizableMultiWindowPreferenceController(context));
         controllers.add(new ShortcutManagerThrottlingPreferenceController(context));
         controllers.add(new EnableGnssRawMeasFullTrackingPreferenceController(context));
         controllers.add(new DefaultLaunchPreferenceController(context, "running_apps"));
diff --git a/src/com/android/settings/development/SizeCompatFreeformPreferenceController.java b/src/com/android/settings/development/NonResizableMultiWindowPreferenceController.java
similarity index 74%
rename from src/com/android/settings/development/SizeCompatFreeformPreferenceController.java
rename to src/com/android/settings/development/NonResizableMultiWindowPreferenceController.java
index 2e54d1d..b1c4be9 100644
--- a/src/com/android/settings/development/SizeCompatFreeformPreferenceController.java
+++ b/src/com/android/settings/development/NonResizableMultiWindowPreferenceController.java
@@ -16,7 +16,7 @@
 
 package com.android.settings.development;
 
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
 
 import android.content.Context;
 import android.provider.Settings;
@@ -29,32 +29,35 @@
 import com.android.settingslib.development.DeveloperOptionsPreferenceController;
 
 /**
- * Preference Controller for whether to allow launching size-compat apps in freeform windows.
+ * Preference Controller for whether to allow launching non-resizable apps in multi window,
+ * such as freeform and splitscreen.
  */
-public class SizeCompatFreeformPreferenceController extends DeveloperOptionsPreferenceController
+public class NonResizableMultiWindowPreferenceController
+        extends DeveloperOptionsPreferenceController
         implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
 
-    private static final String ENABLE_SIZECOMPAT_FREEFORM_KEY = "enable_sizecompat_freeform";
+    private static final String ENABLE_NON_RESIZABLE_MULTI_WINDOW_KEY =
+            "enable_non_resizable_multi_window";
 
     @VisibleForTesting
     static final int SETTING_VALUE_OFF = 0;
     @VisibleForTesting
     static final int SETTING_VALUE_ON = 1;
 
-    public SizeCompatFreeformPreferenceController(Context context) {
+    public NonResizableMultiWindowPreferenceController(Context context) {
         super(context);
     }
 
     @Override
     public String getPreferenceKey() {
-        return ENABLE_SIZECOMPAT_FREEFORM_KEY;
+        return ENABLE_NON_RESIZABLE_MULTI_WINDOW_KEY;
     }
 
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
         final boolean isEnabled = (Boolean) newValue;
         Settings.Global.putInt(mContext.getContentResolver(),
-                DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM,
+                DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
                 isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
         return true;
     }
@@ -62,7 +65,7 @@
     @Override
     public void updateState(Preference preference) {
         final int mode = Settings.Global.getInt(mContext.getContentResolver(),
-                DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, SETTING_VALUE_OFF);
+                DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, SETTING_VALUE_OFF);
         ((SwitchPreference) mPreference).setChecked(mode != SETTING_VALUE_OFF);
     }
 
@@ -70,7 +73,7 @@
     protected void onDeveloperOptionsSwitchDisabled() {
         super.onDeveloperOptionsSwitchDisabled();
         Settings.Global.putInt(mContext.getContentResolver(),
-                DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, SETTING_VALUE_OFF);
+                DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, SETTING_VALUE_OFF);
         ((SwitchPreference) mPreference).setChecked(false);
     }
 }
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 5eb9d94..2259441 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -27,7 +27,6 @@
 import android.widget.ImageView;
 import android.widget.Toolbar;
 
-import androidx.annotation.VisibleForTesting;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentActivity;
 import androidx.fragment.app.FragmentManager;
@@ -43,7 +42,6 @@
 public class SettingsHomepageActivity extends FragmentActivity {
 
     private static final String TAG = "SettingsHomepageActivity";
-    private int mSearchBoxHeight;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -56,7 +54,7 @@
 
         final View appBar = findViewById(R.id.app_bar_container);
         appBar.setMinimumHeight(getSearchBoxHeight());
-        setDefaultHomepageContainerPaddingTop();
+        initHomepageContainer();
 
         final Toolbar toolbar = findViewById(R.id.search_action_bar);
         FeatureFactory.getFactory(this).getSearchFeatureProvider()
@@ -89,8 +87,6 @@
 
         try {
             showFragment(fragment.newInstance(), R.id.contextual_suggestion_content);
-            setHomepageContainerTopOffset(getResources()
-                    .getDimensionPixelSize(R.dimen.suggestion_height));
         } catch (IllegalAccessException | InstantiationException e) {
             Log.w(TAG, "Cannot show fragment", e);
         }
@@ -109,33 +105,19 @@
         fragmentTransaction.commit();
     }
 
-    @VisibleForTesting
-    void setHomepageContainerTopOffset(int offset) {
+    private void initHomepageContainer() {
         final View view = findViewById(R.id.homepage_container);
-        final int paddingTop = getSearchBoxHeight() + offset;
-        view.setPadding(0 /* left */, paddingTop, 0 /* right */, 0 /* bottom */);
-
         // Prevent inner RecyclerView gets focus and invokes scrolling.
         view.setFocusableInTouchMode(true);
         view.requestFocus();
     }
 
-    @VisibleForTesting
-    void setDefaultHomepageContainerPaddingTop() {
-        setHomepageContainerTopOffset(0);
-    }
-
-    @VisibleForTesting
-    int getSearchBoxHeight() {
-        if (mSearchBoxHeight != 0) {
-            return mSearchBoxHeight;
-        }
-
+    private int getSearchBoxHeight() {
         final int searchBarHeight = getResources().getDimensionPixelSize(R.dimen.search_bar_height);
-        final int searchBarMargin = getResources().getDimensionPixelSize(R.dimen.search_bar_margin);
-
-        // The height of search box is the height of search bar(48dp) + top/bottom margins(24dp)
-        mSearchBoxHeight = searchBarHeight + searchBarMargin * 2;
-        return mSearchBoxHeight;
+        final int searchBarMarginTop = getResources().getDimensionPixelSize(
+                R.dimen.search_bar_margin);
+        final int searchBarMarginBottom = getResources().getDimensionPixelSize(
+                R.dimen.search_bar_margin_bottom);
+        return searchBarHeight + searchBarMarginTop + searchBarMarginBottom;
     }
 }
diff --git a/src/com/android/settings/network/ConnectedEthernetNetworkController.java b/src/com/android/settings/network/ConnectedEthernetNetworkController.java
new file mode 100644
index 0000000..5918331
--- /dev/null
+++ b/src/com/android/settings/network/ConnectedEthernetNetworkController.java
@@ -0,0 +1,83 @@
+/*
+ * 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 com.android.settings.network.InternetUpdater.INTERNET_ETHERNET;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settingslib.Utils;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+/**
+ * PreferenceController to show the connected ethernet network.
+ */
+public class ConnectedEthernetNetworkController extends AbstractPreferenceController
+        implements InternetUpdater.OnInternetTypeChangedListener {
+
+    public static final String KEY = "connected_ethernet_network";
+
+    private Preference mPreference;
+    private InternetUpdater mInternetUpdater;
+    private @InternetUpdater.InternetType int mInternetType;
+
+    public ConnectedEthernetNetworkController(Context context, Lifecycle lifecycle) {
+        super(context);
+        mInternetUpdater = new InternetUpdater(context, lifecycle, this);
+        mInternetType = mInternetUpdater.getInternetType();
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mInternetType == INTERNET_ETHERNET;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = screen.findPreference(KEY);
+        final Drawable drawable = mContext.getDrawable(R.drawable.ic_settings_ethernet);
+        if (drawable != null) {
+            drawable.setTintList(
+                    Utils.getColorAttr(mContext, android.R.attr.colorControlActivated));
+            mPreference.setIcon(drawable);
+        }
+    }
+
+    /**
+     * Called when internet type is changed.
+     *
+     * @param internetType the internet type
+     */
+    public void onInternetTypeChanged(@InternetUpdater.InternetType int internetType) {
+        mInternetType = internetType;
+        if (mPreference != null) {
+            mPreference.setVisible(isAvailable());
+        }
+    }
+}
diff --git a/src/com/android/settings/network/MobileNetworkListController.java b/src/com/android/settings/network/MobileNetworkListController.java
index 77c93ff..cd7375c 100644
--- a/src/com/android/settings/network/MobileNetworkListController.java
+++ b/src/com/android/settings/network/MobileNetworkListController.java
@@ -26,6 +26,12 @@
 import android.telephony.SubscriptionManager;
 import android.util.ArrayMap;
 
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
 import com.android.settings.network.telephony.MobileNetworkActivity;
@@ -35,12 +41,6 @@
 import java.util.List;
 import java.util.Map;
 
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-import androidx.lifecycle.OnLifecycleEvent;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
 /**
  * This populates the entries on a page which lists all available mobile subscriptions. Each entry
  * has the name of the subscription with some subtext giving additional detail, and clicking on the
@@ -106,7 +106,9 @@
                 pref = new Preference(mPreferenceScreen.getContext());
                 mPreferenceScreen.addPreference(pref);
             }
-            pref.setTitle(info.getDisplayName());
+            final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                    info, mContext);
+            pref.setTitle(displayName);
 
             if (info.isEmbedded()) {
                 if (mSubscriptionManager.isActiveSubscriptionId(subId)) {
@@ -121,7 +123,7 @@
                     pref.setSummary(mContext.getString(R.string.mobile_network_inactive_sim));
                 } else {
                     pref.setSummary(mContext.getString(R.string.mobile_network_tap_to_activate,
-                            SubscriptionUtil.getDisplayName(info)));
+                            displayName));
                 }
             }
 
diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java
index 08da41a..abffe11 100644
--- a/src/com/android/settings/network/MobileNetworkSummaryController.java
+++ b/src/com/android/settings/network/MobileNetworkSummaryController.java
@@ -116,13 +116,14 @@
             return null;
         } else if (subs.size() == 1) {
             final SubscriptionInfo info = subs.get(0);
+            final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                    info, mContext);
             final int subId = info.getSubscriptionId();
             if (!info.isEmbedded() && !mSubscriptionManager.isActiveSubscriptionId(subId)
                     && !SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) {
-                return mContext.getString(R.string.mobile_network_tap_to_activate,
-                        SubscriptionUtil.getDisplayName(info));
+                return mContext.getString(R.string.mobile_network_tap_to_activate, displayName);
             } else {
-                return subs.get(0).getDisplayName();
+                return displayName;
             }
         } else {
             if (com.android.settings.Utils.isProviderModelEnabled(mContext)) {
@@ -135,8 +136,9 @@
     }
 
     private CharSequence getSummaryForProviderModel(List<SubscriptionInfo> subs) {
-        return String.join(", ", subs.stream().map(SubscriptionInfo::getDisplayName)
-                .collect(Collectors.toList()));
+        return String.join(", ", subs.stream().map(subInfo -> {
+            return SubscriptionUtil.getUniqueSubscriptionDisplayName(subInfo, mContext);
+        }).collect(Collectors.toList()));
     }
 
     private void startAddSimFlow() {
diff --git a/src/com/android/settings/network/NetworkProviderCallsSmsController.java b/src/com/android/settings/network/NetworkProviderCallsSmsController.java
index 3a228dc..417c4a9 100644
--- a/src/com/android/settings/network/NetworkProviderCallsSmsController.java
+++ b/src/com/android/settings/network/NetworkProviderCallsSmsController.java
@@ -91,20 +91,22 @@
             final StringBuilder summary = new StringBuilder();
             for (SubscriptionInfo subInfo : subs) {
                 int subsSize = subs.size();
+                final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                        subInfo, mContext);
 
                 // Set displayName as summary if there is only one valid SIM.
                 if (subsSize == 1
                         && SubscriptionManager.isValidSubscriptionId(subInfo.getSubscriptionId())) {
-                    return subInfo.getDisplayName();
+                    return displayName;
                 }
 
                 CharSequence status = getPreferredStatus(subInfo);
                 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(subInfo.getDisplayName());
+                    summary.append(displayName);
                 } else {
-                    summary.append(subInfo.getDisplayName())
+                    summary.append(displayName)
                             .append(" (")
                             .append(status)
                             .append(")");
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index 4446833..ae9b2d8 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -207,6 +207,8 @@
             mViewAirplaneModeNetworksButtonPreference;
     @VisibleForTesting
     LayoutPreference mResetInternetPreference;
+    @VisibleForTesting
+    ConnectedEthernetNetworkController mConnectedEthernetNetworkController;
 
     /**
      * Mobile networks list for provider model
@@ -267,6 +269,7 @@
         }
         addNetworkMobileProviderController();
         addViewAirplaneModeNetworksButtonController();
+        addConnectedEthernetNetworkController();
     }
 
     private void addNetworkMobileProviderController() {
@@ -287,6 +290,14 @@
         mViewAirplaneModeNetworksButtonPreference.displayPreference(getPreferenceScreen());
     }
 
+    private void addConnectedEthernetNetworkController() {
+        if (mConnectedEthernetNetworkController == null) {
+            mConnectedEthernetNetworkController =
+                    new ConnectedEthernetNetworkController(getContext(), getSettingsLifecycle());
+        }
+        mConnectedEthernetNetworkController.displayPreference(getPreferenceScreen());
+    }
+
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
diff --git a/src/com/android/settings/network/ProviderModelSlice.java b/src/com/android/settings/network/ProviderModelSlice.java
index 443c239..7e71fef 100644
--- a/src/com/android/settings/network/ProviderModelSlice.java
+++ b/src/com/android/settings/network/ProviderModelSlice.java
@@ -24,6 +24,7 @@
 import android.app.settings.SettingsEnums;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
@@ -35,6 +36,7 @@
 
 import com.android.settings.R;
 import com.android.settings.SubSettings;
+import com.android.settings.Utils;
 import com.android.settings.network.telephony.MobileNetworkUtils;
 import com.android.settings.network.telephony.NetworkProviderWorker;
 import com.android.settings.slices.CustomSliceable;
@@ -105,12 +107,18 @@
         final boolean hasCarrier = mHelper.hasCarrier();
         log("hasCarrier: " + hasCarrier);
 
-        // First section:  Add a Wi-Fi item which state is connected.
-        final WifiSliceItem connectedWifiItem = mHelper.getConnectedWifiItem(wifiList);
-        if (connectedWifiItem != null) {
-            log("get Wi-Fi item witch is connected");
-            listBuilder.addRow(getWifiSliceItemRow(connectedWifiItem));
+        // First section:  Add a Ethernet or Wi-Fi item which state is connected.
+        if (isEthernetConnected()) {
+            log("get Ethernet item which is connected");
+            listBuilder.addRow(createEthernetRow());
             maxListSize--;
+        } else {
+            final WifiSliceItem connectedWifiItem = mHelper.getConnectedWifiItem(wifiList);
+            if (connectedWifiItem != null) {
+                log("get Wi-Fi item which is connected");
+                listBuilder.addRow(getWifiSliceItemRow(connectedWifiItem));
+                maxListSize--;
+            }
         }
 
         // Second section:  Add a carrier item.
@@ -228,4 +236,25 @@
     NetworkProviderWorker getWorker() {
         return SliceBackgroundWorker.getInstance(getUri());
     }
+
+    private boolean isEthernetConnected() {
+        final NetworkProviderWorker worker = getWorker();
+        if (worker == null) {
+            return false;
+        }
+        return worker.isEthernetConnected();
+    }
+
+    @VisibleForTesting
+    ListBuilder.RowBuilder createEthernetRow() {
+        final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder();
+        final Drawable drawable = mContext.getDrawable(R.drawable.ic_settings_ethernet);
+        if (drawable != null) {
+            drawable.setTintList(Utils.getColorAttr(mContext, android.R.attr.colorAccent));
+            rowBuilder.setTitleItem(Utils.createIconWithDrawable(drawable), ListBuilder.ICON_IMAGE);
+        }
+        return rowBuilder
+                .setTitle(mContext.getText(R.string.ethernet))
+                .setSubtitle(mContext.getText(R.string.cannot_switch_networks_while_connected));
+    }
 }
diff --git a/src/com/android/settings/network/ProviderModelSliceHelper.java b/src/com/android/settings/network/ProviderModelSliceHelper.java
index dd8aa60..6c678ec 100644
--- a/src/com/android/settings/network/ProviderModelSliceHelper.java
+++ b/src/com/android/settings/network/ProviderModelSliceHelper.java
@@ -261,7 +261,8 @@
         final SubscriptionInfo defaultSubscription = mSubscriptionManager.getActiveSubscriptionInfo(
                 mSubscriptionManager.getDefaultDataSubscriptionId());
         if (defaultSubscription != null) {
-            title = defaultSubscription.getDisplayName().toString();
+            title = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                    defaultSubscription, mContext).toString();
         }
         return title;
     }
diff --git a/src/com/android/settings/network/SubscriptionsPreferenceController.java b/src/com/android/settings/network/SubscriptionsPreferenceController.java
index ada1c89..d028c58 100644
--- a/src/com/android/settings/network/SubscriptionsPreferenceController.java
+++ b/src/com/android/settings/network/SubscriptionsPreferenceController.java
@@ -241,7 +241,8 @@
                     startMobileNetworkActivity(mContext, subInfo.getSubscriptionId()));
         }
 
-        mSubsGearPref.setTitle(subInfo.getDisplayName());
+        mSubsGearPref.setTitle(SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                subInfo, mContext));
         mSubsGearPref.setOrder(mStartOrder);
         mSubsGearPref.setSummary(getMobilePreferenceSummary(subInfo.getSubscriptionId()));
         mSubsGearPref.setIcon(getIcon(subInfo.getSubscriptionId()));
@@ -322,7 +323,7 @@
                 pref = new Preference(mPreferenceGroup.getContext());
                 mPreferenceGroup.addPreference(pref);
             }
-            pref.setTitle(info.getDisplayName());
+            pref.setTitle(SubscriptionUtil.getUniqueSubscriptionDisplayName(info, mContext));
             final boolean isDefaultForData = (subId == dataDefaultSubId);
             pref.setSummary(getSummary(subId, isDefaultForData));
             setIcon(pref, subId, isDefaultForData);
@@ -584,4 +585,4 @@
                     NO_CELL_DATA_TYPE_ICON, cutOut);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/network/telephony/ContactDiscoveryPreferenceController.java b/src/com/android/settings/network/telephony/ContactDiscoveryPreferenceController.java
index eead41f..b231da2 100644
--- a/src/com/android/settings/network/telephony/ContactDiscoveryPreferenceController.java
+++ b/src/com/android/settings/network/telephony/ContactDiscoveryPreferenceController.java
@@ -145,7 +145,7 @@
 
         for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(context)) {
             if (mSubId == info.getSubscriptionId()) {
-                result = info.getDisplayName();
+                result = SubscriptionUtil.getUniqueSubscriptionDisplayName(info, context);
                 break;
             }
         }
diff --git a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
index 560922c..4fb6cff7 100644
--- a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
+++ b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
@@ -126,7 +126,7 @@
         final SubscriptionInfo info = getDefaultSubscriptionInfo();
         if (info != null) {
             // display subscription based account
-            return info.getDisplayName();
+            return SubscriptionUtil.getUniqueSubscriptionDisplayName(info, mContext);
         } else {
             if (isAskEverytimeSupported()) {
                 return mContext.getString(R.string.calls_and_sms_ask_every_time);
@@ -160,7 +160,8 @@
 
         if (Utils.isProviderModelEnabled(mContext) && subs.size() == 1) {
             mPreference.setEnabled(false);
-            mPreference.setSummary(subs.get(0).getDisplayName());
+            mPreference.setSummary(SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                    subs.get(0), mContext));
             return;
         }
 
@@ -171,7 +172,7 @@
             if (sub.isOpportunistic()) {
                 continue;
             }
-            displayNames.add(sub.getDisplayName());
+            displayNames.add(SubscriptionUtil.getUniqueSubscriptionDisplayName(sub, mContext));
             final int subId = sub.getSubscriptionId();
             subscriptionIds.add(Integer.toString(subId));
             if (subId == serviceDefaultSubId) {
diff --git a/src/com/android/settings/network/telephony/DeleteEuiccSubscriptionDialogActivity.java b/src/com/android/settings/network/telephony/DeleteEuiccSubscriptionDialogActivity.java
index 8257bf3..f429f8b 100644
--- a/src/com/android/settings/network/telephony/DeleteEuiccSubscriptionDialogActivity.java
+++ b/src/com/android/settings/network/telephony/DeleteEuiccSubscriptionDialogActivity.java
@@ -16,7 +16,6 @@
 
 package com.android.settings.network.telephony;
 
-import android.app.AlertDialog;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
@@ -141,7 +140,9 @@
                 DIALOG_TAG_DELETE_SIM_CONFIRMATION,
                 getString(R.string.erase_sim_dialog_title),
                 getString(
-                        R.string.erase_sim_dialog_text, mSubscriptionToBeDeleted.getDisplayName()),
+                        R.string.erase_sim_dialog_text,
+                        SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                                mSubscriptionToBeDeleted, this)),
                 getString(R.string.erase_sim_confirm_button),
                 getString(R.string.cancel));
     }
diff --git a/src/com/android/settings/network/telephony/MobileDataDialogFragment.java b/src/com/android/settings/network/telephony/MobileDataDialogFragment.java
index 180d503..9533827 100644
--- a/src/com/android/settings/network/telephony/MobileDataDialogFragment.java
+++ b/src/com/android/settings/network/telephony/MobileDataDialogFragment.java
@@ -28,6 +28,7 @@
 
 import com.android.settings.R;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.wifi.WifiPickerTrackerHelper;
 
 
@@ -97,12 +98,14 @@
                 final String previousName = (nextSubInfo == null)
                         ? getContext().getResources().getString(
                         R.string.sim_selection_required_pref)
-                        : nextSubInfo.getDisplayName().toString();
+                        : SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                                nextSubInfo, getContext()).toString();
 
                 final String newName = (currentSubInfo == null)
                         ? getContext().getResources().getString(
                         R.string.sim_selection_required_pref)
-                        : currentSubInfo.getDisplayName().toString();
+                        : SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                                currentSubInfo, getContext()).toString();
 
                 return new AlertDialog.Builder(context)
                         .setTitle(context.getString(R.string.sim_change_data_title, newName))
diff --git a/src/com/android/settings/network/telephony/MobileDataSlice.java b/src/com/android/settings/network/telephony/MobileDataSlice.java
index 106f336..7ec31be 100644
--- a/src/com/android/settings/network/telephony/MobileDataSlice.java
+++ b/src/com/android/settings/network/telephony/MobileDataSlice.java
@@ -167,7 +167,7 @@
             return null; // no summary text
         }
 
-        return defaultSubscription.getDisplayName();
+        return SubscriptionUtil.getUniqueSubscriptionDisplayName(defaultSubscription, mContext);
     }
 
     private PendingIntent getPrimaryAction() {
diff --git a/src/com/android/settings/network/telephony/MobileNetworkActivity.java b/src/com/android/settings/network/telephony/MobileNetworkActivity.java
index b1b2321..20b37c1 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkActivity.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkActivity.java
@@ -207,7 +207,7 @@
         // title will just default to the label for this activity that's already specified in
         // AndroidManifest.xml.
         if (subscription != null) {
-            setTitle(subscription.getDisplayName());
+            setTitle(SubscriptionUtil.getUniqueSubscriptionDisplayName(subscription, this));
         }
     }
 
@@ -299,7 +299,7 @@
         CharSequence carrierName = "";
         if (info != null) {
             subId = info.getSubscriptionId();
-            carrierName = info.getDisplayName();
+            carrierName = SubscriptionUtil.getUniqueSubscriptionDisplayName(info, this);
         }
         // If this activity was launched using ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN, show the
         // associated dialog only if the opt-in has not been granted yet.
diff --git a/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java b/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java
index 50e7d9b..44fd029 100644
--- a/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java
+++ b/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java
@@ -32,13 +32,11 @@
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.LifecycleObserver;
 import androidx.lifecycle.OnLifecycleEvent;
 import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
 import androidx.preference.PreferenceGroup;
 import androidx.preference.PreferenceScreen;
 
@@ -194,7 +192,7 @@
                 mPreferenceGroup.addPreference(pref);
             }
 
-            CharSequence title = info.getDisplayName();
+            CharSequence title = SubscriptionUtil.getUniqueSubscriptionDisplayName(info, mContext);
             if (getPhoneAccountHandleForSubscriptionId(subId) != null) {
                 final Intent intent = MobileNetworkUtils.buildPhoneAccountConfigureIntent(mContext,
                         getPhoneAccountHandleForSubscriptionId(subId));
diff --git a/src/com/android/settings/network/telephony/NetworkProviderWorker.java b/src/com/android/settings/network/telephony/NetworkProviderWorker.java
index 18aeb4d..e2e0264 100644
--- a/src/com/android/settings/network/telephony/NetworkProviderWorker.java
+++ b/src/com/android/settings/network/telephony/NetworkProviderWorker.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.network.telephony;
 
+import static com.android.settings.network.InternetUpdater.INTERNET_ETHERNET;
 import static com.android.settingslib.mobile.MobileMappings.getIconKey;
 import static com.android.settingslib.mobile.MobileMappings.mapIconSets;
 
@@ -33,6 +34,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.settings.network.InternetUpdater;
 import com.android.settings.network.MobileDataContentObserver;
 import com.android.settings.network.MobileDataEnabledListener;
 import com.android.settings.network.SubscriptionsChangeListener;
@@ -50,7 +52,8 @@
 public class NetworkProviderWorker extends WifiScanWorker implements
         SignalStrengthListener.Callback, MobileDataEnabledListener.Client,
         DataConnectivityListener.Client,
-        SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+        SubscriptionsChangeListener.SubscriptionsChangeListenerClient,
+        InternetUpdater.OnInternetTypeChangedListener {
     private static final String TAG = "NetworkProviderWorker";
     private static final int PROVIDER_MODEL_DEFAULT_EXPANDED_ROW_COUNT = 4;
     private DataContentObserver mMobileDataObserver;
@@ -67,6 +70,8 @@
     private TelephonyDisplayInfo mTelephonyDisplayInfo =
             new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN,
                     TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
+    private InternetUpdater mInternetUpdater;
+    private @InternetUpdater.InternetType int mInternetType;
 
     public NetworkProviderWorker(Context context, Uri uri) {
         super(context, uri);
@@ -85,6 +90,9 @@
         mConnectivityListener = new DataConnectivityListener(context, this);
         mSignalStrengthListener = new SignalStrengthListener(context, this);
         mConfig = getConfig(mContext);
+
+        mInternetUpdater = new InternetUpdater(mContext, getLifecycle(), this);
+        mInternetType = mInternetUpdater.getInternetType();
     }
 
     @Override
@@ -260,4 +268,28 @@
         return updateNetworkTypeName(mContext, mConfig, mTelephonyDisplayInfo,
                 mDefaultDataSubid);
     }
+
+    /**
+     * Called when internet type is changed.
+     *
+     * @param internetType the internet type
+     */
+    public void onInternetTypeChanged(@InternetUpdater.InternetType int internetType) {
+        if (mInternetType == internetType) {
+            return;
+        }
+        boolean changeWithEthernet =
+                mInternetType == INTERNET_ETHERNET || internetType == INTERNET_ETHERNET;
+        mInternetType = internetType;
+        if (changeWithEthernet) {
+            updateSlice();
+        }
+    }
+
+    /**
+     * Returns true, if the ethernet network is connected.
+     */
+    public boolean isEthernetConnected() {
+        return mInternetType == INTERNET_ETHERNET;
+    }
 }
diff --git a/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java b/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java
index 2a7bc02..c782b66 100644
--- a/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java
+++ b/src/com/android/settings/network/telephony/RenameMobileNetworkDialogFragment.java
@@ -47,6 +47,7 @@
 
 import com.android.settings.R;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.network.SubscriptionUtil;
 import com.android.settingslib.DeviceInfoUtils;
 
 import com.google.common.collect.ImmutableMap;
@@ -163,7 +164,8 @@
             Log.w(TAG, "got null SubscriptionInfo for mSubId:" + mSubId);
             return;
         }
-        final CharSequence displayName = info.getDisplayName();
+        final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                info, getContext());
         mNameView.setText(displayName);
         if (!TextUtils.isEmpty(displayName)) {
             mNameView.setSelection(displayName.length());
diff --git a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
index 4af42ba..c1be63c 100644
--- a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
+++ b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
@@ -201,7 +201,8 @@
                     showProgressDialog(
                             getString(
                                     R.string.sim_action_switch_sub_dialog_progress,
-                                    mSubInfo.getDisplayName()));
+                                    SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                                            mSubInfo, this)));
                     mSwitchToEuiccSubscriptionSidecar.run(mSubInfo.getSubscriptionId());
                     return;
                 }
@@ -345,13 +346,14 @@
 
     /* Displays the SIM toggling confirmation dialog. */
     private void showDisableSimConfirmDialog() {
+        final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                mSubInfo, this);
         String title =
-                mSubInfo == null || TextUtils.isEmpty(mSubInfo.getDisplayName())
+                mSubInfo == null || TextUtils.isEmpty(displayName)
                         ? getString(
                                 R.string.privileged_action_disable_sub_dialog_title_without_carrier)
                         : getString(
-                                R.string.privileged_action_disable_sub_dialog_title,
-                                mSubInfo.getDisplayName());
+                                R.string.privileged_action_disable_sub_dialog_title, displayName);
 
         ConfirmDialogFragment.show(
                 this,
@@ -402,40 +404,48 @@
     private String getSwitchDialogPosBtnText() {
         return mIsEsimOperation
                 ? getString(
-                        R.string.sim_action_switch_sub_dialog_confirm, mSubInfo.getDisplayName())
+                        R.string.sim_action_switch_sub_dialog_confirm,
+                        SubscriptionUtil.getUniqueSubscriptionDisplayName(mSubInfo, this))
                 : getString(R.string.sim_switch_button);
     }
 
     private String getEnableSubscriptionTitle() {
-        if (mSubInfo == null || TextUtils.isEmpty(mSubInfo.getDisplayName())) {
+        final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                mSubInfo, this);
+        if (mSubInfo == null || TextUtils.isEmpty(displayName)) {
             return getString(R.string.sim_action_enable_sub_dialog_title_without_carrier_name);
         }
-        return getString(R.string.sim_action_enable_sub_dialog_title, mSubInfo.getDisplayName());
+        return getString(R.string.sim_action_enable_sub_dialog_title, displayName);
     }
 
     private String getSwitchSubscriptionTitle() {
         if (mIsEsimOperation) {
             return getString(
-                    R.string.sim_action_switch_sub_dialog_title, mSubInfo.getDisplayName());
+                    R.string.sim_action_switch_sub_dialog_title,
+                    SubscriptionUtil.getUniqueSubscriptionDisplayName(mSubInfo, this));
         }
         return getString(R.string.sim_action_switch_psim_dialog_title);
     }
 
     private String getSwitchDialogBodyMsg(SubscriptionInfo activeSub, boolean betweenEsim) {
+        final CharSequence subInfoName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                mSubInfo, this);
+        final CharSequence activeSubName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                activeSub, this);
         if (betweenEsim && mIsEsimOperation) {
             return getString(
                     R.string.sim_action_switch_sub_dialog_text_downloaded,
-                    mSubInfo.getDisplayName(),
-                    activeSub.getDisplayName());
+                    subInfoName,
+                    activeSubName);
         } else if (mIsEsimOperation) {
             return getString(
                     R.string.sim_action_switch_sub_dialog_text,
-                    mSubInfo.getDisplayName(),
-                    activeSub.getDisplayName());
+                    subInfoName,
+                    activeSubName);
         } else {
             return getString(
                     R.string.sim_action_switch_sub_dialog_text_single_sim,
-                    activeSub.getDisplayName());
+                    activeSubName);
         }
     }
 
diff --git a/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java b/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
index 684a27a..297bfdb 100644
--- a/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
+++ b/src/com/android/settings/notification/app/AppChannelsBypassingDndPreferenceController.java
@@ -59,7 +59,7 @@
 
     private RestrictedSwitchPreference mAllNotificationsToggle;
     private PreferenceCategory mPreferenceCategory;
-    private final List<NotificationChannel> mChannels = new ArrayList<>();
+    private List<NotificationChannel> mChannels = new ArrayList<>();
 
     public AppChannelsBypassingDndPreferenceController(
             Context context,
@@ -126,17 +126,18 @@
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... unused) {
+                List<NotificationChannel> newChannelList = new ArrayList<>();
                 List<NotificationChannelGroup> mChannelGroupList = mBackend.getGroups(mAppRow.pkg,
                         mAppRow.uid).getList();
-                mChannels.clear();
                 for (NotificationChannelGroup channelGroup : mChannelGroupList) {
                     for (NotificationChannel channel : channelGroup.getChannels()) {
                         if (!isConversation(channel)) {
-                            mChannels.add(channel);
+                            newChannelList.add(channel);
                         }
                     }
                 }
-                Collections.sort(mChannels, CHANNEL_COMPARATOR);
+                Collections.sort(newChannelList, CHANNEL_COMPARATOR);
+                mChannels = newChannelList;
                 return null;
             }
 
diff --git a/src/com/android/settings/notification/app/BlockPreferenceController.java b/src/com/android/settings/notification/app/BlockPreferenceController.java
index 589a03d..e5a7e98 100644
--- a/src/com/android/settings/notification/app/BlockPreferenceController.java
+++ b/src/com/android/settings/notification/app/BlockPreferenceController.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.notification.app;
 
+import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
 
@@ -107,7 +108,7 @@
                         ? IMPORTANCE_NONE
                         : isDefaultChannel()
                                 ? IMPORTANCE_UNSPECIFIED
-                                : mChannel.getOriginalImportance();
+                                : Math.max(mChannel.getOriginalImportance(), IMPORTANCE_LOW);
                 mChannel.setImportance(importance);
                 saveChannel();
             }
diff --git a/src/com/android/settings/notification/app/ChannelListPreferenceController.java b/src/com/android/settings/notification/app/ChannelListPreferenceController.java
index 8410ce1..5fd607f 100644
--- a/src/com/android/settings/notification/app/ChannelListPreferenceController.java
+++ b/src/com/android/settings/notification/app/ChannelListPreferenceController.java
@@ -339,7 +339,9 @@
         channelPref.setOnPreferenceChangeListener(
                 (preference, o) -> {
                     boolean value = (Boolean) o;
-                    int importance = value ? channel.getOriginalImportance() : IMPORTANCE_NONE;
+                    int importance = value
+                            ? Math.max(channel.getOriginalImportance(), IMPORTANCE_LOW)
+                            : IMPORTANCE_NONE;
                     channel.setImportance(importance);
                     channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
                     PrimarySwitchPreference channelPref1 = (PrimarySwitchPreference) preference;
diff --git a/src/com/android/settings/sim/PreferredSimDialogFragment.java b/src/com/android/settings/sim/PreferredSimDialogFragment.java
index 29f4c65..c4a9484 100644
--- a/src/com/android/settings/sim/PreferredSimDialogFragment.java
+++ b/src/com/android/settings/sim/PreferredSimDialogFragment.java
@@ -30,6 +30,7 @@
 import androidx.appcompat.app.AlertDialog;
 
 import com.android.settings.R;
+import com.android.settings.network.SubscriptionUtil;
 
 /**
  * Presents a dialog asking the user if they want to update all services to use a given "preferred"
@@ -86,7 +87,9 @@
             return;
         }
         final String message =
-                getContext().getString(R.string.sim_preferred_message, info.getDisplayName());
+                getContext().getString(
+                        R.string.sim_preferred_message,
+                        SubscriptionUtil.getUniqueSubscriptionDisplayName(info, getContext()));
         dialog.setMessage(message);
     }
 
diff --git a/src/com/android/settings/sim/SimActivationNotifier.java b/src/com/android/settings/sim/SimActivationNotifier.java
index 85d3da2..4a4edef 100644
--- a/src/com/android/settings/sim/SimActivationNotifier.java
+++ b/src/com/android/settings/sim/SimActivationNotifier.java
@@ -117,10 +117,12 @@
             return;
         }
 
+        CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                activeRemovableSub, mContext);
         String carrierName =
-                TextUtils.isEmpty(activeRemovableSub.getDisplayName())
+                TextUtils.isEmpty(displayName)
                         ? mContext.getString(R.string.sim_card_label)
-                        : activeRemovableSub.getDisplayName().toString();
+                        : displayName.toString();
         String title =
                 mContext.getString(
                         R.string.post_dsds_reboot_notification_title_with_carrier, carrierName);
diff --git a/src/com/android/settings/sim/SimListDialogFragment.java b/src/com/android/settings/sim/SimListDialogFragment.java
index d1fb374..2e3cfc7 100644
--- a/src/com/android/settings/sim/SimListDialogFragment.java
+++ b/src/com/android/settings/sim/SimListDialogFragment.java
@@ -38,6 +38,7 @@
 
 import com.android.settings.R;
 import com.android.settings.Utils;
+import com.android.settings.network.SubscriptionUtil;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -179,7 +180,7 @@
                 icon.setImageTintList(
                         Utils.getColorAttr(mContext, android.R.attr.textColorSecondary));
             } else {
-                title.setText(sub.getDisplayName());
+                title.setText(SubscriptionUtil.getUniqueSubscriptionDisplayName(sub, mContext));
                 summary.setText(isMdnProvisioned(sub.getNumber()) ? sub.getNumber() : "");
                 icon.setImageBitmap(sub.createIconBitmap(mContext));
 
diff --git a/src/com/android/settings/sim/SimSelectNotification.java b/src/com/android/settings/sim/SimSelectNotification.java
index 4b46939..7dab4c0 100644
--- a/src/com/android/settings/sim/SimSelectNotification.java
+++ b/src/com/android/settings/sim/SimSelectNotification.java
@@ -139,7 +139,8 @@
         }
 
         CharSequence notificationSummary = context.getResources().getString(
-                R.string.enable_mms_notification_summary, SubscriptionUtil.getDisplayName(info));
+                R.string.enable_mms_notification_summary,
+                SubscriptionUtil.getUniqueSubscriptionDisplayName(info, context));
 
         cancelEnableMmsNotification(context);
 
diff --git a/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java b/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java
index 17a1b8d..a730dd1 100644
--- a/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java
+++ b/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java
@@ -27,6 +27,7 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.settings.R;
 import com.android.settingslib.utils.ThreadUtils;
 
 import java.util.List;
@@ -60,6 +61,11 @@
 
     // Checks whether the slot event should be handled.
     private boolean shouldHandleSlotChange(Context context) {
+        if (!context.getResources().getBoolean(R.bool.config_handle_sim_slot_change)) {
+            Log.i(TAG, "The flag is off. Ignore slot changes.");
+            return false;
+        }
+
         final EuiccManager euiccManager = context.getSystemService(EuiccManager.class);
         if (euiccManager == null || !euiccManager.isEnabled()) {
             Log.i(TAG, "Ignore slot changes because EuiccManager is disabled.");
diff --git a/src/com/android/settings/sim/smartForwarding/DisableSmartForwardingTask.java b/src/com/android/settings/sim/smartForwarding/DisableSmartForwardingTask.java
new file mode 100644
index 0000000..45333ec
--- /dev/null
+++ b/src/com/android/settings/sim/smartForwarding/DisableSmartForwardingTask.java
@@ -0,0 +1,53 @@
+/*
+ * 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.sim.smartForwarding;
+
+import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.TAG;
+
+import android.telephony.CallForwardingInfo;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+public class DisableSmartForwardingTask implements Runnable {
+    private final TelephonyManager tm;
+    private final boolean[] callWaitingStatus;
+    private final CallForwardingInfo[] callForwardingInfo;
+
+    public DisableSmartForwardingTask(TelephonyManager tm,
+            boolean[] callWaitingStatus, CallForwardingInfo[] callForwardingInfo) {
+        this.tm = tm;
+        this.callWaitingStatus = callWaitingStatus;
+        this.callForwardingInfo = callForwardingInfo;
+    }
+
+    @Override
+    public void run() {
+        for (int i = 0; i < tm.getActiveModemCount(); i++) {
+            if (callWaitingStatus != null) {
+                Log.d(TAG, "Restore call waiting to " + callWaitingStatus[i]);
+                tm.setCallWaitingEnabled(callWaitingStatus[i], null, null);
+            }
+
+            if (callForwardingInfo != null
+                    && callForwardingInfo[i] != null
+                    && callForwardingInfo[i].getTimeoutSeconds() > 0) {
+                Log.d(TAG, "Restore call waiting to " + callForwardingInfo);
+                tm.setCallForwarding(callForwardingInfo[i], null, null);
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/sim/smartForwarding/EnableSmartForwardingTask.java b/src/com/android/settings/sim/smartForwarding/EnableSmartForwardingTask.java
new file mode 100644
index 0000000..6fe62e0
--- /dev/null
+++ b/src/com/android/settings/sim/smartForwarding/EnableSmartForwardingTask.java
@@ -0,0 +1,456 @@
+/*
+ * 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.sim.smartForwarding;
+
+import static android.telephony.CallForwardingInfo.REASON_NOT_REACHABLE;
+
+import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.TAG;
+
+import android.content.Context;
+import android.telephony.CallForwardingInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+public class EnableSmartForwardingTask
+        implements Callable<EnableSmartForwardingTask.FeatureResult> {
+
+    private static final int TIMEOUT = 20;
+
+    private final SubscriptionManager sm;
+    private final TelephonyManager tm;
+    private final String[] mCallForwardingNumber;
+
+    FeatureResult mResult = new FeatureResult(false, null);
+    SettableFuture<FeatureResult> client = SettableFuture.create();
+
+    public EnableSmartForwardingTask(Context context, String[] callForwardingNumber) {
+        tm = context.getSystemService(TelephonyManager.class);
+        sm = context.getSystemService(SubscriptionManager.class);
+        mCallForwardingNumber = callForwardingNumber;
+    }
+
+    @Override
+    public FeatureResult call() throws TimeoutException, InterruptedException, ExecutionException {
+        FlowController controller = new FlowController();
+        if (controller.init(mCallForwardingNumber)) {
+            controller.startProcess();
+        } else {
+            client.set(mResult);
+        }
+
+        return client.get(TIMEOUT, TimeUnit.SECONDS);
+    }
+
+    class FlowController {
+        private SlotUTData[] mSlotUTData;
+        private final ArrayList<Command> mSteps = new ArrayList<>();
+
+        public boolean init(String[] phoneNum) {
+            if (!initObject(phoneNum)) return false;
+            initSteps();
+            return true;
+        }
+
+        private boolean initObject(String[] phoneNum) {
+            Executor executor = Executors.newSingleThreadExecutor();
+            if (tm == null || sm == null) {
+                Log.e(TAG, "TelephonyManager or SubscriptionManager is null");
+                return false;
+            }
+
+            if (phoneNum.length != tm.getActiveModemCount()) {
+                Log.e(TAG, "The length of PhoneNum array should same as phone count.");
+                return false;
+            }
+
+            mSlotUTData = new SlotUTData[tm.getActiveModemCount()];
+            for (int i = 0; i < mSlotUTData.length; i++) {
+                int[] subIdList = sm.getSubscriptionIds(i);
+                if (subIdList.length < 1) {
+                    Log.e(TAG, "getSubscriptionIds() return empty sub id list.");
+                    return false;
+                }
+                int subId = subIdList[0];
+
+                if (!sm.isActiveSubId(subId)) {
+                    mResult.setReason(FeatureResult.FailedReason.SIM_NOT_ACTIVE);
+                    return false;
+                }
+
+                QueryCallWaitingCommand queryCallWaitingCommand =
+                        new QueryCallWaitingCommand(tm, executor, subId);
+                QueryCallForwardingCommand queryCallForwardingCommand =
+                        new QueryCallForwardingCommand(tm, executor, subId);
+                UpdateCallWaitingCommand updateCallWaitingCommand =
+                        new UpdateCallWaitingCommand(tm, executor, queryCallWaitingCommand, subId);
+                UpdateCallForwardingCommand updateCallForwardingCommand =
+                        new UpdateCallForwardingCommand(tm, executor, queryCallForwardingCommand,
+                                subId, phoneNum[i]);
+
+                mSlotUTData[i] = new SlotUTData(subId, phoneNum[i],
+                        queryCallWaitingCommand,
+                        queryCallForwardingCommand,
+                        updateCallWaitingCommand,
+                        updateCallForwardingCommand);
+            }
+            return true;
+        }
+
+        private void initSteps() {
+            // 1. Query call waiting for each slots
+            for (SlotUTData slotUTData : mSlotUTData) {
+                mSteps.add(slotUTData.getQueryCallWaitingCommand());
+            }
+
+            // 2. Query call forwarding for each slots
+            for (SlotUTData slotUTData : mSlotUTData) {
+                mSteps.add(slotUTData.getQueryCallForwardingCommand());
+            }
+
+            // 3. Enable call waiting for each slots
+            for (SlotUTData slotUTData : mSlotUTData) {
+                mSteps.add(slotUTData.getUpdateCallWaitingCommand());
+            }
+
+            // 4. Set call forwarding for each slots
+            for (SlotUTData slotUTData : mSlotUTData) {
+                mSteps.add(slotUTData.getUpdateCallForwardingCommand());
+            }
+        }
+
+        public void startProcess() {
+            int index = 0;
+            boolean result = true;
+
+            // go through all steps
+            while (index < mSteps.size() && result) {
+                Command currentStep = mSteps.get(index);
+                Log.d(TAG, "processing : " + currentStep);
+
+                try {
+                    result = currentStep.process();
+                } catch (Exception e) {
+                    Log.d(TAG, "Failed on : " + currentStep, e);
+                    result = false;
+                }
+
+                if (result) {
+                    index++;
+                } else {
+                    Log.d(TAG, "Failed on : " + currentStep);
+                }
+            }
+
+            if (result) {
+                // No more steps need to perform, return successful to UI.
+                mResult.result = true;
+                mResult.slotUTData = mSlotUTData;
+                Log.d(TAG, "Smart forwarding successful");
+                client.set(mResult);
+            } else {
+                restoreAllSteps(index);
+                client.set(mResult);
+            }
+        }
+
+        private void restoreAllSteps(int index) {
+            List<Command> restoreCommands = mSteps.subList(0, index);
+            Collections.reverse(restoreCommands);
+            for (Command currentStep : restoreCommands) {
+                Log.d(TAG, "restoreStep: " + currentStep);
+                // Only restore update steps
+                if (currentStep instanceof UpdateCommand) {
+                    ((UpdateCommand) currentStep).onRestore();
+                }
+            }
+        }
+    }
+
+    final class SlotUTData {
+        int subId;
+        String mCallForwardingNumber;
+
+        QueryCallWaitingCommand mQueryCallWaiting;
+        QueryCallForwardingCommand mQueryCallForwarding;
+        UpdateCallWaitingCommand mUpdateCallWaiting;
+        UpdateCallForwardingCommand mUpdateCallForwarding;
+
+        public SlotUTData(int subId,
+                String callForwardingNumber,
+                QueryCallWaitingCommand queryCallWaiting,
+                QueryCallForwardingCommand queryCallForwarding,
+                UpdateCallWaitingCommand updateCallWaiting,
+                UpdateCallForwardingCommand updateCallForwarding) {
+            this.subId = subId;
+            this.mCallForwardingNumber = callForwardingNumber;
+            this.mQueryCallWaiting = queryCallWaiting;
+            this.mQueryCallForwarding = queryCallForwarding;
+            this.mUpdateCallWaiting = updateCallWaiting;
+            this.mUpdateCallForwarding = updateCallForwarding;
+        }
+
+        public QueryCallWaitingCommand getQueryCallWaitingCommand() {
+            return mQueryCallWaiting;
+        }
+
+        public QueryCallForwardingCommand getQueryCallForwardingCommand() {
+            return mQueryCallForwarding;
+        }
+
+        public UpdateCallWaitingCommand getUpdateCallWaitingCommand() {
+            return mUpdateCallWaiting;
+        }
+
+        public UpdateCallForwardingCommand getUpdateCallForwardingCommand() {
+            return mUpdateCallForwarding;
+        }
+    }
+
+    interface Command {
+        boolean process() throws Exception;
+    }
+
+    abstract static class QueryCommand<T> implements Command {
+        int subId;
+        TelephonyManager tm;
+        Executor executor;
+
+        public QueryCommand(TelephonyManager tm, Executor executor, int subId) {
+            this.subId = subId;
+            this.tm = tm;
+            this.executor = executor;
+        }
+
+        @Override
+        public String toString() {
+            return this.getClass().getSimpleName() + "[SubId " + subId + "]";
+        }
+
+        abstract T getResult();
+    }
+
+    abstract static class UpdateCommand<T> implements Command {
+        int subId;
+        TelephonyManager tm;
+        Executor executor;
+
+        public UpdateCommand(TelephonyManager tm, Executor executor, int subId) {
+            this.subId = subId;
+            this.tm = tm;
+            this.executor = executor;
+        }
+
+        @Override
+        public String toString() {
+            return this.getClass().getSimpleName() + "[SubId " + subId + "] ";
+        }
+
+        abstract void onRestore();
+    }
+
+    static class QueryCallWaitingCommand extends QueryCommand<Integer> {
+        int result;
+        SettableFuture<Boolean> resultFuture = SettableFuture.create();
+
+        public QueryCallWaitingCommand(TelephonyManager tm, Executor executor, int subId) {
+            super(tm, executor, subId);
+        }
+
+        @Override
+        public boolean process() throws Exception {
+            tm.createForSubscriptionId(subId)
+                    .getCallWaitingStatus(executor, this::queryStatusCallBack);
+            return resultFuture.get();
+        }
+
+        @Override
+        Integer getResult() {
+            return result;
+        }
+
+        public void queryStatusCallBack(int result) {
+            this.result = result;
+
+            if (result == TelephonyManager.CALL_WAITING_STATUS_ENABLED
+                    || result == TelephonyManager.CALL_WAITING_STATUS_DISABLED) {
+                Log.d(TAG, "Call Waiting result: " + result);
+                resultFuture.set(true);
+            } else {
+                resultFuture.set(false);
+            }
+        }
+    }
+
+    static class QueryCallForwardingCommand extends QueryCommand<CallForwardingInfo> {
+        CallForwardingInfo result;
+        SettableFuture<Boolean> resultFuture = SettableFuture.create();
+
+        public QueryCallForwardingCommand(TelephonyManager tm, Executor executor, int subId) {
+            super(tm, executor, subId);
+        }
+
+        @Override
+        public boolean process() throws Exception{
+            tm.createForSubscriptionId(subId)
+                    .getCallForwarding(REASON_NOT_REACHABLE, executor,
+                            new TelephonyManager.CallForwardingInfoCallback() {
+                                @Override
+                                public void onCallForwardingInfoAvailable(CallForwardingInfo info) {
+                                    Log.d(TAG, "Call Forwarding result: " + info);
+                                    result = info;
+                                    resultFuture.set(true);
+                                }
+
+                                @Override
+                                public void onError(int error) {
+                                    Log.d(TAG, "Query Call Forwarding failed.");
+                                    resultFuture.set(false);
+                                }
+                            });
+            return resultFuture.get();
+        }
+
+        @Override
+        CallForwardingInfo getResult() {
+            return result;
+        }
+    }
+
+    static class UpdateCallWaitingCommand extends UpdateCommand<Integer> {
+        SettableFuture<Boolean> resultFuture = SettableFuture.create();
+        QueryCallWaitingCommand queryResult;
+
+        public UpdateCallWaitingCommand(TelephonyManager tm, Executor executor,
+                QueryCallWaitingCommand queryCallWaitingCommand, int subId) {
+            super(tm, executor, subId);
+            this.queryResult = queryCallWaitingCommand;
+        }
+
+        @Override
+        public boolean process() throws Exception {
+            tm.createForSubscriptionId(subId)
+                    .setCallWaitingEnabled(true, executor, this::updateStatusCallBack);
+            return resultFuture.get();
+        }
+
+        public void updateStatusCallBack(int result) {
+            Log.d(TAG, "UpdateCallWaitingCommand updateStatusCallBack result: " + result);
+            if (result == TelephonyManager.CALL_WAITING_STATUS_ENABLED
+                    || result == TelephonyManager.CALL_WAITING_STATUS_DISABLED) {
+                resultFuture.set(true);
+            } else {
+                resultFuture.set(false);
+            }
+        }
+
+        @Override
+        void onRestore() {
+            Log.d(TAG, "onRestore: " + this);
+            if (queryResult.getResult() != TelephonyManager.CALL_WAITING_STATUS_ENABLED) {
+                tm.createForSubscriptionId(subId)
+                        .setCallWaitingEnabled(false, null, null);
+            }
+        }
+    }
+
+    static class UpdateCallForwardingCommand extends UpdateCommand<Integer> {
+        String phoneNum;
+        SettableFuture<Boolean> resultFuture = SettableFuture.create();
+        QueryCallForwardingCommand queryResult;
+
+        public UpdateCallForwardingCommand(TelephonyManager tm, Executor executor,
+                QueryCallForwardingCommand queryCallForwardingCommand,
+                int subId, String phoneNum) {
+            super(tm, executor, subId);
+            this.phoneNum = phoneNum;
+            this.queryResult = queryCallForwardingCommand;
+        }
+
+        @Override
+        public boolean process() throws Exception {
+            CallForwardingInfo info = new CallForwardingInfo(
+                    true, REASON_NOT_REACHABLE, phoneNum, 3);
+            tm.createForSubscriptionId(subId)
+                    .setCallForwarding(info, executor, this::updateStatusCallBack);
+            return resultFuture.get();
+        }
+
+        public void updateStatusCallBack(int result) {
+            Log.d(TAG, "UpdateCallForwardingCommand updateStatusCallBack : " + result);
+            if (result == TelephonyManager.CallForwardingInfoCallback.RESULT_SUCCESS) {
+                resultFuture.set(true);
+            } else {
+                resultFuture.set(false);
+            }
+        }
+
+        @Override
+        void onRestore() {
+            Log.d(TAG, "onRestore: " + this);
+
+            tm.createForSubscriptionId(subId)
+                    .setCallForwarding(queryResult.getResult(), null, null);
+        }
+    }
+
+    public static class FeatureResult {
+        enum FailedReason {
+            NETWORK_ERROR,
+            SIM_NOT_ACTIVE
+        }
+
+        private boolean result;
+        private FailedReason reason;
+        private SlotUTData[] slotUTData;
+
+        public FeatureResult(boolean result, SlotUTData[] slotUTData) {
+            this.result = result;
+            this.slotUTData = slotUTData;
+        }
+
+        public boolean getResult() {
+            return result;
+        }
+
+        public SlotUTData[] getSlotUTData() {
+            return slotUTData;
+        }
+
+        public void setReason(FailedReason reason) {
+            this.reason = reason;
+        }
+
+        public FailedReason getReason() {
+            return reason;
+        }
+    }
+}
diff --git a/src/com/android/settings/sim/smartForwarding/MDNHandlerFragment.java b/src/com/android/settings/sim/smartForwarding/MDNHandlerFragment.java
new file mode 100644
index 0000000..cada66a
--- /dev/null
+++ b/src/com/android/settings/sim/smartForwarding/MDNHandlerFragment.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.sim.smartForwarding;
+
+import static com.android.settings.sim.smartForwarding.MDNHandlerHeaderFragment.KEY_SLOT0_PHONE_NUMBER;
+import static com.android.settings.sim.smartForwarding.MDNHandlerHeaderFragment.KEY_SLOT1_PHONE_NUMBER;
+
+import android.app.AlertDialog;
+import android.app.settings.SettingsEnums;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+
+import com.android.settings.R;
+import com.android.settingslib.core.instrumentation.Instrumentable;
+
+public class MDNHandlerFragment extends Fragment implements Instrumentable {
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        View view = inflater.inflate(R.xml.smart_forwarding_mdn_handler, container, false);
+        getActivity().getActionBar().setTitle(
+                getResources().getString(R.string.smart_forwarding_input_mdn_title));
+
+        Button processBtn = view.findViewById(R.id.process);
+        processBtn.setOnClickListener((View v)-> {
+            pressButtonOnClick();
+        });
+
+        Button cancelBtn = view.findViewById(R.id.cancel);
+        cancelBtn.setOnClickListener((View v)-> {
+            switchToMainFragment(true);
+        });
+        return view;
+    }
+
+    private void pressButtonOnClick() {
+        // Get the phone number from the UI
+        MDNHandlerHeaderFragment fragment = (MDNHandlerHeaderFragment) this
+                .getChildFragmentManager()
+                .findFragmentById(R.id.fragment_settings);
+
+        String slot0Number = "";
+        String slot1Number = "";
+        if (fragment != null) {
+            slot0Number = fragment.findPreference(KEY_SLOT0_PHONE_NUMBER)
+                    .getSummary().toString();
+            slot1Number = fragment.findPreference(KEY_SLOT1_PHONE_NUMBER)
+                    .getSummary().toString();
+        }
+        final String[] phoneNumber = {slot1Number, slot0Number};
+
+        // If phone number is empty, popup an alert dialog
+        if(TextUtils.isEmpty(phoneNumber[0])
+                || TextUtils.isEmpty(phoneNumber[1])) {
+            new AlertDialog.Builder(getActivity())
+                    .setTitle(R.string.smart_forwarding_failed_title)
+                    .setMessage(R.string.smart_forwarding_missing_mdn_text)
+                    .setPositiveButton(
+                            R.string.smart_forwarding_missing_alert_dialog_text,
+                            (dialog, which) -> { dialog.dismiss(); })
+                    .create()
+                    .show();
+        } else {
+            switchToMainFragment(false);
+            ((SmartForwardingActivity)getActivity()).enableSmartForwarding(phoneNumber);
+        }
+    }
+
+    private void switchToMainFragment(boolean turnoffSwitch) {
+        FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
+        fragmentManager.beginTransaction()
+                .replace(R.id.content_frame, new SmartForwardingFragment(turnoffSwitch))
+                .commit();
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.MOBILE_NETWORK;
+    }
+}
diff --git a/src/com/android/settings/sim/smartForwarding/MDNHandlerHeaderFragment.java b/src/com/android/settings/sim/smartForwarding/MDNHandlerHeaderFragment.java
new file mode 100644
index 0000000..5fd8049
--- /dev/null
+++ b/src/com/android/settings/sim/smartForwarding/MDNHandlerHeaderFragment.java
@@ -0,0 +1,78 @@
+/*
+ * 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.sim.smartForwarding;
+
+import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.getPhoneNumber;
+
+import android.app.settings.SettingsEnums;
+import android.os.Bundle;
+import android.text.InputType;
+import android.widget.EditText;
+
+import androidx.annotation.NonNull;
+import androidx.preference.EditTextPreference;
+import androidx.preference.EditTextPreference.OnBindEditTextListener;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+
+import com.android.settings.R;
+import com.android.settingslib.core.instrumentation.Instrumentable;
+
+public class MDNHandlerHeaderFragment extends PreferenceFragmentCompat
+        implements Preference.OnPreferenceChangeListener, OnBindEditTextListener, Instrumentable {
+
+    public static final String KEY_SLOT0_PHONE_NUMBER = "slot0_phone_number";
+    public static final String KEY_SLOT1_PHONE_NUMBER = "slot1_phone_number";
+
+    public MDNHandlerHeaderFragment() {}
+
+    @Override
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+        setPreferencesFromResource(R.xml.smart_forwarding_mdn_handler_header, rootKey);
+
+        EditTextPreference slot0EditText = findPreference(KEY_SLOT0_PHONE_NUMBER);
+        slot0EditText.setOnBindEditTextListener(this);
+        slot0EditText.setOnPreferenceChangeListener(this);
+        String slot0PhoneNumber = getPhoneNumber(getContext(), 0);
+        slot0EditText.setSummary(slot0PhoneNumber);
+        slot0EditText.setText(slot0PhoneNumber);
+
+        EditTextPreference slot1EditText = findPreference(KEY_SLOT1_PHONE_NUMBER);
+        slot1EditText.setOnPreferenceChangeListener(this);
+        slot1EditText.setOnBindEditTextListener(this);
+        String slot1PhoneNumber = getPhoneNumber(getContext(), 1);
+        slot1EditText.setSummary(slot1PhoneNumber);
+        slot1EditText.setText(slot1PhoneNumber);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        preference.setSummary(newValue.toString());
+        return true;
+    }
+
+    @Override
+    public void onBindEditText(@NonNull EditText editText) {
+        editText.setInputType(InputType.TYPE_CLASS_PHONE);
+        editText.setSingleLine(true);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.MOBILE_NETWORK;
+    }
+}
diff --git a/src/com/android/settings/sim/smartForwarding/SmartForwardingActivity.java b/src/com/android/settings/sim/smartForwarding/SmartForwardingActivity.java
new file mode 100644
index 0000000..217801e
--- /dev/null
+++ b/src/com/android/settings/sim/smartForwarding/SmartForwardingActivity.java
@@ -0,0 +1,169 @@
+/*
+ * 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.sim.smartForwarding;
+
+import static com.android.settings.sim.smartForwarding.EnableSmartForwardingTask.FeatureResult;
+import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.TAG;
+import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.backupPrevStatus;
+import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.clearAllBackupData;
+import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.getAllSlotCallForwardingStatus;
+import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.getAllSlotCallWaitingStatus;
+
+import android.app.ActionBar;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.os.Bundle;
+import android.telephony.CallForwardingInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toolbar;
+
+import androidx.core.content.ContextCompat;
+
+import com.android.settings.R;
+import com.android.settings.core.SettingsBaseActivity;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+import java.util.concurrent.Executors;
+
+public class SmartForwardingActivity extends SettingsBaseActivity {
+    final ListeningExecutorService service =
+            MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Toolbar toolbar = findViewById(R.id.action_bar);
+        toolbar.setVisibility(View.VISIBLE);
+        setActionBar(toolbar);
+
+        final ActionBar actionBar = getActionBar();
+        if (actionBar != null) {
+            actionBar.setDisplayHomeAsUpEnabled(true);
+        }
+
+        getSupportFragmentManager()
+                .beginTransaction()
+                .replace(R.id.content_frame, new SmartForwardingFragment())
+                .commit();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+    }
+
+    public void enableSmartForwarding(String[] phoneNumber) {
+        // Pop-up ongoing dialog
+        ProgressDialog dialog = new ProgressDialog(this);
+        dialog.setTitle(R.string.smart_forwarding_ongoing_title);
+        dialog.setIndeterminate(true);
+        dialog.setMessage(getText(R.string.smart_forwarding_ongoing_text));
+        dialog.setCancelable(false);
+        dialog.show();
+
+        // Enable feature
+        ListenableFuture<FeatureResult> enableTask =
+                service.submit(new EnableSmartForwardingTask(this, phoneNumber));
+        Futures.addCallback(enableTask, new FutureCallback<FeatureResult>() {
+            @Override
+            public void onSuccess(FeatureResult result) {
+                Log.e(TAG, "Enable Feature result: " + result.getResult());
+                if (result.getResult()) {
+                    backupPrevStatus(SmartForwardingActivity.this, result.getSlotUTData());
+
+                    // Turn on switch preference
+                    SmartForwardingFragment fragment =
+                            (SmartForwardingFragment) getSupportFragmentManager()
+                                    .findFragmentById(R.id.content_frame);
+                    if (fragment != null) {
+                        fragment.turnOnSwitchPreference();
+                    }
+                } else {
+                    onError(result);
+                }
+                dialog.dismiss();
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                Log.e(TAG, "Enable Feature exception", t);
+                dialog.dismiss();
+
+                // Pop-up error dialog
+                AlertDialog mDialog = new AlertDialog.Builder(SmartForwardingActivity.this)
+                        .setTitle(R.string.smart_forwarding_failed_title)
+                        .setMessage(R.string.smart_forwarding_failed_text)
+                        .setPositiveButton(
+                                R.string.smart_forwarding_missing_alert_dialog_text,
+                                (dialog, which) -> { dialog.dismiss(); })
+                        .create();
+                mDialog.show();
+            }
+        }, ContextCompat.getMainExecutor(this));
+    }
+
+    public void disableSmartForwarding() {
+        TelephonyManager tm = getSystemService(TelephonyManager.class);
+        SubscriptionManager sm = getSystemService(SubscriptionManager.class);
+
+        boolean[] callWaitingStatus = getAllSlotCallWaitingStatus(this, sm, tm);
+        CallForwardingInfo[] callForwardingInfo = getAllSlotCallForwardingStatus(this, sm, tm);
+
+        // Disable feature
+        ListenableFuture disableTask = service.submit(new DisableSmartForwardingTask(
+                tm, callWaitingStatus, callForwardingInfo));
+        Futures.addCallback(disableTask, new FutureCallback() {
+            @Override
+            public void onSuccess(Object result) {
+                clearAllBackupData(SmartForwardingActivity.this, sm, tm);
+            }
+
+            @Override
+            public void onFailure(Throwable t) {
+                Log.e(TAG, "Disable Feature exception" + t);
+            }
+        }, ContextCompat.getMainExecutor(this));
+    }
+
+    public void onError(FeatureResult result) {
+        int errorMsg;
+        if (result.getReason() == FeatureResult.FailedReason.SIM_NOT_ACTIVE) {
+            errorMsg = R.string.smart_forwarding_failed_not_activated_text;
+        } else {
+            errorMsg = R.string.smart_forwarding_failed_text;
+        }
+
+        // Pop-up error dialog
+        AlertDialog mDialog = new AlertDialog.Builder(SmartForwardingActivity.this)
+                .setTitle(R.string.smart_forwarding_failed_title)
+                .setMessage(errorMsg)
+                .setPositiveButton(
+                        R.string.smart_forwarding_missing_alert_dialog_text,
+                        (dialog, which) -> { dialog.dismiss(); })
+                .create();
+        mDialog.show();
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/sim/smartForwarding/SmartForwardingFragment.java b/src/com/android/settings/sim/smartForwarding/SmartForwardingFragment.java
new file mode 100644
index 0000000..76eaea1
--- /dev/null
+++ b/src/com/android/settings/sim/smartForwarding/SmartForwardingFragment.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.sim.smartForwarding;
+
+import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.TAG;
+import static com.android.settings.sim.smartForwarding.SmartForwardingUtils.getPhoneNumber;
+
+import android.app.settings.SettingsEnums;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.fragment.app.FragmentManager;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.R;
+import com.android.settingslib.core.instrumentation.Instrumentable;
+
+public class SmartForwardingFragment extends PreferenceFragmentCompat
+        implements Preference.OnPreferenceChangeListener, Instrumentable {
+
+    private static final String KEY_SMART_FORWARDING_SWITCH = "smart_forwarding_switch";
+    private boolean turnOffSwitch;
+
+    public SmartForwardingFragment() { }
+
+    public SmartForwardingFragment(boolean turnOffSwitch) {
+        this.turnOffSwitch = turnOffSwitch;
+    }
+
+    @Override
+    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+        setPreferencesFromResource(R.xml.smart_forwarding_switch, rootKey);
+
+        String title = getResources().getString(R.string.smart_forwarding_title);
+        getActivity().getActionBar().setTitle(title);
+
+        SwitchPreference smartForwardingSwitch = findPreference(KEY_SMART_FORWARDING_SWITCH);
+        if (turnOffSwitch) {
+            smartForwardingSwitch.setChecked(false);
+        }
+        smartForwardingSwitch.setOnPreferenceChangeListener(this);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        boolean value = (boolean) newValue;
+
+        Log.d(TAG, "onPreferenceChange. Update value to " + value);
+
+        if (value) {
+            String slot0PhoneNumber = getPhoneNumber(getContext(), 0);
+            String slot1PhoneNumber = getPhoneNumber(getContext(), 1);
+
+            String[] phoneNumber = new String[]{slot1PhoneNumber, slot0PhoneNumber};
+
+            if (TextUtils.isEmpty(slot0PhoneNumber) || TextUtils.isEmpty(slot1PhoneNumber)) {
+                Log.d(TAG, "Slot 0 or Slot 1 phone number missing.");
+                switchToMDNFragment();
+            } else {
+                ((SmartForwardingActivity) getActivity()).enableSmartForwarding(phoneNumber);
+            }
+            return false;
+        } else {
+            ((SmartForwardingActivity) getActivity()).disableSmartForwarding();
+        }
+
+        return true;
+    }
+
+
+    private void switchToMDNFragment() {
+        FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
+        fragmentManager.beginTransaction()
+                .replace(R.id.content_frame, new MDNHandlerFragment())
+                .commit();
+    }
+
+    public void turnOnSwitchPreference() {
+        SwitchPreference smartForwardingSwitch = findPreference(KEY_SMART_FORWARDING_SWITCH);
+        smartForwardingSwitch.setChecked(true);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.MOBILE_NETWORK;
+    }
+}
diff --git a/src/com/android/settings/sim/smartForwarding/SmartForwardingUtils.java b/src/com/android/settings/sim/smartForwarding/SmartForwardingUtils.java
new file mode 100644
index 0000000..5a82d8b
--- /dev/null
+++ b/src/com/android/settings/sim/smartForwarding/SmartForwardingUtils.java
@@ -0,0 +1,145 @@
+/*
+ * 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.sim.smartForwarding;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.telephony.CallForwardingInfo;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+public class SmartForwardingUtils {
+    public static final String TAG = "SmartForwarding";
+    public static final String SMART_FORWARDING_PREF = "smart_forwarding_pref_";
+
+    public static final String CALL_WAITING_KEY = "call_waiting_key";
+    public static final String CALL_FORWARDING_ENABLED_KEY = "call_forwarding_enabled_key";
+    public static final String CALL_FORWARDING_REASON_KEY = "call_forwarding_reason_key";
+    public static final String CALL_FORWARDING_NUMBER_KEY = "call_forwarding_number_key";
+    public static final String CALL_FORWARDING_TIME_KEY = "call_forwarding_timekey";
+
+    public static boolean getBackupCallWaitingStatus(Context context, int subId) {
+        SharedPreferences preferences = context.getSharedPreferences(
+                SMART_FORWARDING_PREF + subId, Context.MODE_PRIVATE);
+        return preferences.getBoolean(CALL_WAITING_KEY, false);
+    }
+
+    public static CallForwardingInfo getBackupCallForwardingStatus(Context context, int subId) {
+        SharedPreferences preferences = context.getSharedPreferences(
+                SMART_FORWARDING_PREF + subId, Context.MODE_PRIVATE);
+        if (preferences.contains(CALL_FORWARDING_ENABLED_KEY)) {
+            boolean enabled = preferences.getBoolean(CALL_FORWARDING_ENABLED_KEY, false);
+            int reason = preferences.getInt(CALL_FORWARDING_REASON_KEY,
+                    CallForwardingInfo.REASON_UNCONDITIONAL);
+            String number = preferences.getString(CALL_FORWARDING_NUMBER_KEY, "");
+            int time = preferences.getInt(CALL_FORWARDING_TIME_KEY, 1);
+
+            return new CallForwardingInfo(enabled, reason, number, time);
+        } else {
+            return null;
+        }
+    }
+
+    public static void saveCallWaitingStatus(Context context, int subId, boolean value) {
+        SharedPreferences.Editor preferences = context.getSharedPreferences(
+                SMART_FORWARDING_PREF + subId, Context.MODE_PRIVATE).edit();
+        preferences.putBoolean(CALL_WAITING_KEY, value).commit();
+    }
+
+    public static void saveCallForwardingStatus(Context context, int subId,
+            CallForwardingInfo callForwardingInfo) {
+        SharedPreferences.Editor preferences = context.getSharedPreferences(
+                SMART_FORWARDING_PREF + subId, Context.MODE_PRIVATE).edit();
+
+        preferences.putBoolean(CALL_FORWARDING_ENABLED_KEY, callForwardingInfo.isEnabled())
+                .commit();
+        preferences.putInt(CALL_FORWARDING_REASON_KEY, callForwardingInfo.getReason()).commit();
+        preferences.putString(CALL_FORWARDING_NUMBER_KEY, callForwardingInfo.getNumber()).commit();
+        preferences.putInt(CALL_FORWARDING_TIME_KEY, callForwardingInfo.getTimeoutSeconds())
+                .commit();
+    }
+
+    public static void clearBackupData(Context context, int subId) {
+        SharedPreferences.Editor preferences = context.getSharedPreferences(
+                SMART_FORWARDING_PREF + subId, Context.MODE_PRIVATE).edit();
+        preferences.clear().commit();
+    }
+
+    public static boolean[] getAllSlotCallWaitingStatus(Context context, SubscriptionManager sm,
+            TelephonyManager tm) {
+        int phoneCount = tm.getActiveModemCount();
+        boolean[] allStatus = new boolean[phoneCount];
+
+        for (int i = 0; i < phoneCount; i++) {
+            int subId = sm.getSubscriptionIds(i)[0];
+            boolean callWaitingStatus = getBackupCallWaitingStatus(context, subId);
+            allStatus[i] = callWaitingStatus;
+        }
+        return allStatus;
+    }
+
+    public static CallForwardingInfo[] getAllSlotCallForwardingStatus(
+            Context context, SubscriptionManager sm, TelephonyManager tm) {
+        int phoneCount = tm.getActiveModemCount();
+        CallForwardingInfo[] allStatus = new CallForwardingInfo[phoneCount];
+
+        for (int i = 0; i < phoneCount; i++) {
+            int subId = sm.getSubscriptionIds(i)[0];
+            CallForwardingInfo callWaitingStatus = getBackupCallForwardingStatus(context, subId);
+            allStatus[i] = callWaitingStatus;
+        }
+        return allStatus;
+    }
+
+    public static void clearAllBackupData(Context context, SubscriptionManager sm,
+            TelephonyManager tm) {
+        int phoneCount = tm.getActiveModemCount();
+        for (int i = 0; i < phoneCount; i++) {
+            int subId = sm.getSubscriptionIds(i)[0];
+            clearBackupData(context, subId);
+        }
+    }
+
+    public static void backupPrevStatus(Context context,
+            EnableSmartForwardingTask.SlotUTData[] slotUTData) {
+        for (int i = 0; i < slotUTData.length; i++) {
+            int callWaiting = slotUTData[i].mQueryCallWaiting.result;
+            saveCallWaitingStatus(
+                    context,
+                    slotUTData[i].subId,
+                    callWaiting == TelephonyManager.CALL_WAITING_STATUS_ENABLED);
+
+            saveCallForwardingStatus(
+                    context,
+                    slotUTData[i].subId,
+                    slotUTData[i].mQueryCallForwarding.result);
+        }
+    }
+
+    public static String getPhoneNumber(Context context, int slotId) {
+        SubscriptionManager subscriptionManager = context.getSystemService(
+                SubscriptionManager.class);
+        int[] subIdList = subscriptionManager.getSubscriptionIds(slotId);
+        if (subIdList != null) {
+            SubscriptionInfo subInfo = subscriptionManager.getActiveSubscriptionInfo(subIdList[0]);
+            return (subInfo != null) ? subInfo.getNumber() : "";
+        } else {
+            return "";
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/widget/HomepageAppBarScrollingViewBehavior.java b/src/com/android/settings/widget/HomepageAppBarScrollingViewBehavior.java
new file mode 100644
index 0000000..c8dbc65
--- /dev/null
+++ b/src/com/android/settings/widget/HomepageAppBarScrollingViewBehavior.java
@@ -0,0 +1,56 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+/**
+ * This scrolling view behavior will set the background of the {@link AppBarLayout} as
+ * transparent and without the elevation.
+ */
+public class HomepageAppBarScrollingViewBehavior extends AppBarLayout.ScrollingViewBehavior {
+    private boolean mInitialized;
+
+    public HomepageAppBarScrollingViewBehavior(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
+        boolean changed = super.onDependentViewChanged(parent, child, dependency);
+        if (!mInitialized && dependency instanceof AppBarLayout) {
+            mInitialized = true;
+            AppBarLayout appBarLayout = (AppBarLayout) dependency;
+            setAppBarLayoutTransparent(appBarLayout);
+        }
+        return changed;
+    }
+
+    @VisibleForTesting
+    void setAppBarLayoutTransparent(AppBarLayout appBarLayout) {
+        appBarLayout.setBackgroundColor(Color.TRANSPARENT);
+        appBarLayout.setTargetElevation(0);
+    }
+}
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index 4602bb4..cfee53c 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -69,6 +69,7 @@
 
 import com.android.settings.ProxySelector;
 import com.android.settings.R;
+import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.wifi.dpp.WifiDppUtils;
 import com.android.settingslib.Utils;
 import com.android.settingslib.utils.ThreadUtils;
@@ -1473,8 +1474,8 @@
         }
 
         // Shows display name of each active subscription.
-        final String[] displayNames = mActiveSubscriptionInfos.stream().map(
-                SubscriptionInfo::getDisplayName).toArray(String[]::new);
+        final String[] displayNames = SubscriptionUtil.getUniqueSubscriptionDisplayNames(
+                mContext).values().stream().toArray(String[]::new);
         mEapSimSpinner.setAdapter(getSpinnerAdapter(displayNames));
         mEapSimSpinner.setSelection(0 /* position */);
         if (displayNames.length == 1) {
diff --git a/src/com/android/settings/wifi/WifiConfigController2.java b/src/com/android/settings/wifi/WifiConfigController2.java
index f398f26..62f2352 100644
--- a/src/com/android/settings/wifi/WifiConfigController2.java
+++ b/src/com/android/settings/wifi/WifiConfigController2.java
@@ -67,6 +67,7 @@
 
 import com.android.settings.ProxySelector;
 import com.android.settings.R;
+import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.wifi.details2.WifiPrivacyPreferenceController2;
 import com.android.settings.wifi.dpp.WifiDppUtils;
 import com.android.settingslib.Utils;
@@ -1437,8 +1438,8 @@
         }
 
         // Shows display name of each active subscription.
-        final String[] displayNames = mActiveSubscriptionInfos.stream().map(
-                SubscriptionInfo::getDisplayName).toArray(String[]::new);
+        final String[] displayNames = SubscriptionUtil.getUniqueSubscriptionDisplayNames(
+                mContext).values().stream().toArray(String[]::new);
         mEapSimSpinner.setAdapter(getSpinnerAdapter(displayNames));
         mEapSimSpinner.setSelection(0 /* position */);
         if (displayNames.length == 1) {
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettings.java b/src/com/android/settings/wifi/calling/WifiCallingSettings.java
index 6cceb49..79f34c7 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettings.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettings.java
@@ -163,7 +163,8 @@
 
         @Override
         public CharSequence getPageTitle(int position) {
-            return String.valueOf(mSil.get(position).getDisplayName());
+            return String.valueOf(SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                    mSil.get(position), getContext()));
         }
 
         @Override
diff --git a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
index a2b143e..c9cddcc 100644
--- a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
+++ b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
@@ -69,6 +69,7 @@
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.datausage.WifiDataUsageSummaryPreferenceController;
+import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settings.wifi.WifiDialog2;
 import com.android.settings.wifi.WifiDialog2.WifiDialog2Listener;
@@ -696,8 +697,10 @@
         final int defaultDataSubscriptionId = SubscriptionManager.getDefaultDataSubscriptionId();
         if (activeSubscriptionInfos != null) {
             for (SubscriptionInfo subscriptionInfo : activeSubscriptionInfos) {
+                final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                        subscriptionInfo, mContext);
                 if (config.carrierId == subscriptionInfo.getCarrierId()) {
-                    mEapSimSubscriptionPref.setSummary(subscriptionInfo.getDisplayName());
+                    mEapSimSubscriptionPref.setSummary(displayName);
                     return;
                 }
 
@@ -705,7 +708,7 @@
                 // defaultDataSubscriptionId.
                 if (config.carrierId == TelephonyManager.UNKNOWN_CARRIER_ID
                         && defaultDataSubscriptionId == subscriptionInfo.getSubscriptionId()) {
-                    mEapSimSubscriptionPref.setSummary(subscriptionInfo.getDisplayName());
+                    mEapSimSubscriptionPref.setSummary(displayName);
                     return;
                 }
             }
diff --git a/tests/robotests/src/com/android/settings/development/SizeCompatFreeformPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/NonResizableMultiWindowPreferenceControllerTest.java
similarity index 74%
rename from tests/robotests/src/com/android/settings/development/SizeCompatFreeformPreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/development/NonResizableMultiWindowPreferenceControllerTest.java
index 7e37b26..7e7a258 100644
--- a/tests/robotests/src/com/android/settings/development/SizeCompatFreeformPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/NonResizableMultiWindowPreferenceControllerTest.java
@@ -16,10 +16,10 @@
 
 package com.android.settings.development;
 
-import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
 
-import static com.android.settings.development.SizeCompatFreeformPreferenceController.SETTING_VALUE_OFF;
-import static com.android.settings.development.SizeCompatFreeformPreferenceController.SETTING_VALUE_ON;
+import static com.android.settings.development.NonResizableMultiWindowPreferenceController.SETTING_VALUE_OFF;
+import static com.android.settings.development.NonResizableMultiWindowPreferenceController.SETTING_VALUE_ON;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -41,7 +41,7 @@
 import org.robolectric.RuntimeEnvironment;
 
 @RunWith(RobolectricTestRunner.class)
-public class SizeCompatFreeformPreferenceControllerTest {
+public class NonResizableMultiWindowPreferenceControllerTest {
 
     @Mock
     private SwitchPreference mPreference;
@@ -49,39 +49,39 @@
     private PreferenceScreen mScreen;
 
     private Context mContext;
-    private SizeCompatFreeformPreferenceController mController;
+    private NonResizableMultiWindowPreferenceController mController;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
-        mController = new SizeCompatFreeformPreferenceController(mContext);
+        mController = new NonResizableMultiWindowPreferenceController(mContext);
         when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
         mController.displayPreference(mScreen);
     }
 
     @Test
-    public void onPreferenceChange_switchEnabled_shouldEnableSizeCompatFreeform() {
+    public void onPreferenceChange_switchEnabled_shouldEnableNonResizableMultiWindow() {
         mController.onPreferenceChange(mPreference, true /* new value */);
 
         final int mode = Settings.Global.getInt(mContext.getContentResolver(),
-                DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, -1 /* default */);
+                DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, -1 /* default */);
         assertThat(mode).isEqualTo(SETTING_VALUE_ON);
     }
 
     @Test
-    public void onPreferenceChange_switchDisabled_shouldDisableSizeCompatFreeform() {
+    public void onPreferenceChange_switchDisabled_shouldDisableNonResizableMultiWindow() {
         mController.onPreferenceChange(mPreference, false /* new value */);
 
         final int mode = Settings.Global.getInt(mContext.getContentResolver(),
-                DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, -1 /* default */);
+                DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, -1 /* default */);
         assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
     }
 
     @Test
     public void updateState_settingEnabled_preferenceShouldBeChecked() {
         Settings.Global.putInt(mContext.getContentResolver(),
-                DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, SETTING_VALUE_ON);
+                DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, SETTING_VALUE_ON);
 
         mController.updateState(mPreference);
 
@@ -91,7 +91,7 @@
     @Test
     public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
         Settings.Global.putInt(mContext.getContentResolver(),
-                DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, SETTING_VALUE_OFF);
+                DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, SETTING_VALUE_OFF);
 
         mController.updateState(mPreference);
 
@@ -103,7 +103,7 @@
         mController.onDeveloperOptionsSwitchDisabled();
 
         final int mode = Settings.Global.getInt(mContext.getContentResolver(),
-                DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, -1 /* default */);
+                DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, -1 /* default */);
         assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
         verify(mPreference).setEnabled(false);
     }
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
index 4c7b4b5..bae4432 100644
--- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -26,7 +26,6 @@
 import static org.mockito.Mockito.when;
 
 import android.os.Build;
-import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
@@ -55,32 +54,6 @@
     }
 
     @Test
-    public void setDefaultHomepageContainerPaddingTop_shouldSetSearchBoxHeight() {
-        final SettingsHomepageActivity activity = Robolectric.buildActivity(
-                SettingsHomepageActivity.class).create().get();
-        final View view = activity.findViewById(R.id.homepage_container);
-
-        activity.setDefaultHomepageContainerPaddingTop();
-
-        final int actualPaddingTop = view.getPaddingTop();
-        assertThat(actualPaddingTop).isEqualTo(activity.getSearchBoxHeight());
-    }
-
-    @Test
-    public void setHomepageContainerTopOffset_shouldBeSetPaddingTop() {
-        final SettingsHomepageActivity activity = Robolectric.buildActivity(
-                SettingsHomepageActivity.class).create().get();
-        final View view = activity.findViewById(R.id.homepage_container);
-        final int offset = activity.getResources().getDimensionPixelSize(
-                R.dimen.suggestion_height);
-
-        activity.setHomepageContainerTopOffset(offset);
-
-        final int actualPaddingTop = view.getPaddingTop();
-        assertThat(actualPaddingTop).isEqualTo(activity.getSearchBoxHeight() + offset);
-    }
-
-    @Test
     public void launch_shouldHaveAnimationForIaFragment() {
         final SettingsHomepageActivity activity = Robolectric.buildActivity(
                 SettingsHomepageActivity.class).create().get();
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
index a32f981..6de83a6 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
@@ -155,6 +155,7 @@
         when(sub1.getSubscriptionId()).thenReturn(1);
         when(sub1.getDisplayName()).thenReturn("sub1");
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
+        SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(sub1));
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
         assertThat(mController.getSummary()).isEqualTo("sub1");
@@ -194,6 +195,7 @@
         when(sub1.getSubscriptionId()).thenReturn(1);
         when(sub1.getDisplayName()).thenReturn("sub1");
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
+        SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(sub1));
         when(mSubscriptionManager.isActiveSubscriptionId(eq(1))).thenReturn(false);
         when(mSubscriptionManager.canDisablePhysicalSubscription()).thenReturn(true);
 
@@ -238,6 +240,7 @@
         when(sub2.getDisplayName()).thenReturn("sub2");
 
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+        SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(sub1, sub2));
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
         assertThat(mController.getSummary()).isEqualTo("2 SIMs");
@@ -267,6 +270,7 @@
         when(sub2.getDisplayName()).thenReturn("sub2");
 
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
+        SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(sub1));
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
         assertThat(mController.getSummary()).isEqualTo("sub1");
@@ -295,6 +299,7 @@
         when(sub2.getDisplayName()).thenReturn("sub2");
 
         SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+        SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(sub1, sub2));
         FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL, true);
         mController.displayPreference(mPreferenceScreen);
         mController.onResume();
diff --git a/tests/robotests/src/com/android/settings/sim/PreferredSimDialogFragmentTest.java b/tests/robotests/src/com/android/settings/sim/PreferredSimDialogFragmentTest.java
index 0b85c37..62c2fc5 100644
--- a/tests/robotests/src/com/android/settings/sim/PreferredSimDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/sim/PreferredSimDialogFragmentTest.java
@@ -33,6 +33,7 @@
 
 import androidx.appcompat.app.AlertDialog;
 
+import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
 
 import org.junit.Test;
@@ -40,6 +41,8 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
 
+import java.util.Arrays;
+
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = ShadowAlertDialogCompat.class)
 public class PreferredSimDialogFragmentTest extends
@@ -72,6 +75,7 @@
 
     @Test
     public void onCreateDialog_twoSimsSelectFirst_correctMessage() {
+        SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(mSim1, mSim2));
         mIntent.putExtra(PREFERRED_SIM, 0);
 
         final AlertDialog alertDialog = startDialog();
@@ -83,6 +87,7 @@
 
     @Test
     public void onCreateDialog_twoSimsSelectSecond_correctMessage() {
+        SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(mSim1, mSim2));
         mIntent.putExtra(PREFERRED_SIM, 1);
 
         final AlertDialog alertDialog = startDialog();
diff --git a/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java b/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java
index e08893b..d6a1326 100644
--- a/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java
+++ b/tests/robotests/src/com/android/settings/sim/SimSelectNotificationTest.java
@@ -62,6 +62,7 @@
 import android.util.DisplayMetrics;
 
 import com.android.settings.R;
+import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
 
 import org.junit.Before;
@@ -73,6 +74,8 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.annotation.Config;
 
+import java.util.Arrays;
+
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = ShadowAlertDialogCompat.class)
 public class SimSelectNotificationTest {
@@ -117,6 +120,7 @@
                 .thenReturn(mNotificationManager);
         when(mContext.getSystemService(Context.TELEPHONY_SERVICE))
                 .thenReturn(mTelephonyManager);
+        when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
         when(mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE))
                 .thenReturn(mSubscriptionManager);
         when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
@@ -126,8 +130,10 @@
 
         when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
         when(mTelephonyManager.isDataEnabledForApn(TYPE_MMS)).thenReturn(false);
+        SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(mSubInfo));
         when(mSubscriptionManager.isActiveSubscriptionId(mSubId)).thenReturn(true);
         when(mSubscriptionManager.getActiveSubscriptionInfo(mSubId)).thenReturn(mSubInfo);
+        when(mSubInfo.getSubscriptionId()).thenReturn(mSubId);
         when(mSubInfo.getDisplayName()).thenReturn(mFakeDisplayName);
         when(mContext.getResources()).thenReturn(mResources);
 
diff --git a/tests/robotests/src/com/android/settings/widget/HomepageAppBarScrollingViewBehaviorTest.java b/tests/robotests/src/com/android/settings/widget/HomepageAppBarScrollingViewBehaviorTest.java
new file mode 100644
index 0000000..6be4c13
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/widget/HomepageAppBarScrollingViewBehaviorTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+
+import com.android.settings.R;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class HomepageAppBarScrollingViewBehaviorTest {
+
+    private HomepageAppBarScrollingViewBehavior mScrollingViewBehavior;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mScrollingViewBehavior = new HomepageAppBarScrollingViewBehavior(mContext,
+                Robolectric.buildAttributeSet().build());
+    }
+
+    @Test
+    public void setAppBarLayoutTransparent_backgroundDefaultAsWhite_shouldBeTransparent() {
+        mContext.setTheme(R.style.Theme_Settings_Home);
+        final AppBarLayout appBarLayout = new AppBarLayout(mContext);
+        appBarLayout.setBackgroundColor(Color.WHITE);
+        mScrollingViewBehavior.setAppBarLayoutTransparent(appBarLayout);
+        assertThat(((ColorDrawable) appBarLayout.getBackground()).getColor()).isEqualTo(
+                Color.TRANSPARENT);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
index 5689b9f..80091e6 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
@@ -830,6 +830,8 @@
         when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_EAP);
         final SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
         final int carrierId = 6;
+        when(subscriptionInfo.getSubscriptionId()).thenReturn(carrierId);
+        when(subscriptionInfo.getDisplayName()).thenReturn("FAKE-CARRIER");
         when(subscriptionInfo.getCarrierId()).thenReturn(carrierId);
         when(subscriptionInfo.getCarrierName()).thenReturn("FAKE-CARRIER");
         mShadowSubscriptionManager.setActiveSubscriptionInfoList(Arrays.asList(subscriptionInfo));
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java
index e5017bd..305f41d 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java
@@ -625,6 +625,8 @@
         when(mAccessPoint.getSecurity()).thenReturn(AccessPoint.SECURITY_EAP);
         final SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
         final int carrierId = 6;
+        when(subscriptionInfo.getSubscriptionId()).thenReturn(carrierId);
+        when(subscriptionInfo.getDisplayName()).thenReturn("FAKE-CARRIER");
         when(subscriptionInfo.getCarrierId()).thenReturn(carrierId);
         when(subscriptionInfo.getCarrierName()).thenReturn("FAKE-CARRIER");
         mShadowSubscriptionManager.setActiveSubscriptionInfoList(Arrays.asList(subscriptionInfo));
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsTest.java
index 1ba8e7a..0159f49 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsTest.java
@@ -54,6 +54,8 @@
 public class WifiCallingSettingsTest {
     private static final int SUB_ID1 = 111;
     private static final int SUB_ID2 = 222;
+    private static final CharSequence DISPLAY_NAME1 = "Carrier1";
+    private static final CharSequence DISPLAY_NAME2 = "Carrier2";
 
     private Context mContext;
 
@@ -87,6 +89,7 @@
 
     @Test
     public void setupFragment_noSubscriptions_noCrash() {
+        SubscriptionUtil.setActiveSubscriptionsForTesting(null);
         FragmentController.setupFragment(mFragment, FragmentActivity.class, 0 /* containerViewId*/,
                 null /* bundle */);
     }
@@ -119,6 +122,8 @@
         final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
         when(info1.getSubscriptionId()).thenReturn(SUB_ID1);
         when(info2.getSubscriptionId()).thenReturn(SUB_ID2);
+        when(info1.getDisplayName()).thenReturn(DISPLAY_NAME1);
+        when(info2.getDisplayName()).thenReturn(DISPLAY_NAME2);
 
         SubscriptionUtil.setActiveSubscriptionsForTesting(new ArrayList<>(
                 Arrays.asList(info1, info2)));
diff --git a/tests/unit/src/com/android/settings/network/ConnectedEthernetNetworkControllerTest.java b/tests/unit/src/com/android/settings/network/ConnectedEthernetNetworkControllerTest.java
new file mode 100644
index 0000000..b5acdc5
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/ConnectedEthernetNetworkControllerTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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 com.android.settings.network.InternetUpdater.INTERNET_APM;
+import static com.android.settings.network.InternetUpdater.INTERNET_APM_NETWORKS;
+import static com.android.settings.network.InternetUpdater.INTERNET_CELLULAR;
+import static com.android.settings.network.InternetUpdater.INTERNET_ETHERNET;
+import static com.android.settings.network.InternetUpdater.INTERNET_WIFI;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+import android.os.Looper;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.preference.Preference;
+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.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class ConnectedEthernetNetworkControllerTest {
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    private Context mContext;
+    private ConnectedEthernetNetworkController mController;
+    private PreferenceScreen mScreen;
+    private Preference mPreference;
+
+    @Before
+    public void setUp() {
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(
+                mock(ConnectivityManager.class));
+        when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mock(WifiManager.class));
+
+        mController = new ConnectedEthernetNetworkController(mContext, mock(Lifecycle.class));
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+        mScreen = preferenceManager.createPreferenceScreen(mContext);
+        mPreference = new Preference(mContext);
+        mPreference.setKey(ConnectedEthernetNetworkController.KEY);
+        mScreen.addPreference(mPreference);
+    }
+
+    @Test
+    public void isAvailable_internetApm_shouldBeFalse() {
+        mController.onInternetTypeChanged(INTERNET_APM);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_internetApmNetworks_shouldBeFalse() {
+        mController.onInternetTypeChanged(INTERNET_APM_NETWORKS);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_internetWifi_shouldBeFalse() {
+        mController.onInternetTypeChanged(INTERNET_WIFI);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_internetCellular_shouldBeFalse() {
+        mController.onInternetTypeChanged(INTERNET_CELLULAR);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_internetEthernet_shouldBeTrue() {
+        mController.onInternetTypeChanged(INTERNET_ETHERNET);
+
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void isVisible_internetWifiToEthernet_shouldBeFalseThenTrue() {
+        mController.displayPreference(mScreen);
+        mController.onInternetTypeChanged(INTERNET_WIFI);
+
+        assertThat(mPreference.isVisible()).isFalse();
+
+        mController.onInternetTypeChanged(INTERNET_ETHERNET);
+
+        assertThat(mPreference.isVisible()).isTrue();
+    }
+
+    @Test
+    public void isVisible_internetEthernetToCellular_shouldBeTrueThenFalse() {
+        mController.displayPreference(mScreen);
+        mController.onInternetTypeChanged(INTERNET_ETHERNET);
+
+        assertThat(mPreference.isVisible()).isTrue();
+
+        mController.onInternetTypeChanged(INTERNET_CELLULAR);
+
+        assertThat(mPreference.isVisible()).isFalse();
+    }
+}
diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
index be008d6..bee48d1 100644
--- a/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
+++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
@@ -61,10 +61,13 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
 public class ProviderModelSliceHelperTest {
+    private static final int DEFAULT_SUBID = 1;
+
     private Context mContext;
     private MockProviderModelSliceHelper mProviderModelSliceHelper;
     private PersistableBundle mBundle;
@@ -168,10 +171,15 @@
         String expectDisplayName = "Name1";
         String expectedSubtitle = "5G";
         String networkType = "5G";
-        int defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+
+        final int defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+        when(mDefaultDataSubscriptionInfo.getSubscriptionId()).thenReturn(defaultDataSubId);
+        when(mDefaultDataSubscriptionInfo.getDisplayName()).thenReturn(expectDisplayName);
         when(mSubscriptionManager.getActiveSubscriptionInfo(defaultDataSubId)).thenReturn(
                 mDefaultDataSubscriptionInfo);
-        when(mDefaultDataSubscriptionInfo.getDisplayName()).thenReturn(expectDisplayName);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(
+                Arrays.asList(mDefaultDataSubscriptionInfo));
+
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
         mBundle.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false);
         addNetworkTransportType(NetworkCapabilities.TRANSPORT_WIFI);
@@ -194,10 +202,13 @@
         String expectedSubtitle = ResourcesUtils.getResourcesString(mContext,
                 "preference_summary_default_combination", connectedText, networkType);
 
-        int defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+        final int defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+        when(mDefaultDataSubscriptionInfo.getSubscriptionId()).thenReturn(defaultDataSubId);
+        when(mDefaultDataSubscriptionInfo.getDisplayName()).thenReturn(expectDisplayName);
         when(mSubscriptionManager.getActiveSubscriptionInfo(defaultDataSubId)).thenReturn(
                 mDefaultDataSubscriptionInfo);
-        when(mDefaultDataSubscriptionInfo.getDisplayName()).thenReturn(expectDisplayName);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(
+                Arrays.asList(mDefaultDataSubscriptionInfo));
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
         mBundle.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false);
         addNetworkTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
index fcca1c2..9f70bcf 100644
--- a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
+++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
@@ -263,6 +263,30 @@
     }
 
     @Test
+    @UiThreadTest
+    public void getSlice_connectedEthernet_getOneEthernetAndOneCarrierAndTwoWiFi() {
+        mWifiList.clear();
+        mockWifiItemCondition(mMockWifiSliceItem1, "wifi1", "wifi1",
+                WifiEntry.CONNECTED_STATE_DISCONNECTED, "wifi1_key", true);
+        mWifiList.add(mMockWifiSliceItem1);
+        mockWifiItemCondition(mMockWifiSliceItem2, "wifi2", "wifi2",
+                WifiEntry.CONNECTED_STATE_DISCONNECTED, "wifi2_key", true);
+        mWifiList.add(mMockWifiSliceItem2);
+        mMockNetworkProviderWorker.updateSelfResults(mWifiList);
+        when(mProviderModelSliceHelper.isAirplaneModeEnabled()).thenReturn(false);
+        when(mProviderModelSliceHelper.hasCarrier()).thenReturn(true);
+        when(mProviderModelSliceHelper.isDataSimActive()).thenReturn(true);
+        when(mMockNetworkProviderWorker.isEthernetConnected()).thenReturn(true);
+
+        final Slice slice = mMockProviderModelSlice.getSlice();
+
+        assertThat(slice).isNotNull();
+        assertThat(mMockProviderModelSlice.hasCreateEthernetRow()).isTrue();
+        verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild);
+        verify(mListBuilder, times(4)).addRow(any(ListBuilder.RowBuilder.class));
+    }
+
+    @Test
     public void providerModelSlice_hasCorrectUri() {
         assertThat(mMockProviderModelSlice.getUri()).isEqualTo(PROVIDER_MODEL_SLICE_URI);
     }
@@ -333,6 +357,7 @@
 
     public class MockProviderModelSlice extends ProviderModelSlice {
         private MockNetworkProviderWorker mNetworkProviderWorker;
+        private boolean mHasCreateEthernetRow;
 
         MockProviderModelSlice(Context context, MockNetworkProviderWorker networkProviderWorker) {
             super(context);
@@ -348,6 +373,16 @@
         NetworkProviderWorker getWorker() {
             return mNetworkProviderWorker;
         }
+
+        @Override
+        ListBuilder.RowBuilder createEthernetRow() {
+            mHasCreateEthernetRow = true;
+            return super.createEthernetRow();
+        }
+
+        public boolean hasCreateEthernetRow() {
+            return mHasCreateEthernetRow;
+        }
     }
 
     @Test
diff --git a/tests/unit/src/com/android/settings/network/telephony/NetworkProviderWorkerTest.java b/tests/unit/src/com/android/settings/network/telephony/NetworkProviderWorkerTest.java
index a48a62a..1905e44 100644
--- a/tests/unit/src/com/android/settings/network/telephony/NetworkProviderWorkerTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/NetworkProviderWorkerTest.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.network.telephony;
 
+import static com.android.settings.network.InternetUpdater.INTERNET_CELLULAR;
+import static com.android.settings.network.InternetUpdater.INTERNET_ETHERNET;
+import static com.android.settings.network.InternetUpdater.INTERNET_WIFI;
 import static com.android.settings.slices.CustomSliceRegistry.PROVIDER_MODEL_SLICE_URI;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -225,6 +228,47 @@
         assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
     }
 
+    @Test
+    public void onInternetTypeChanged_connectedFromWifiToEthernet_callUpdateSlice() {
+        mMockNetworkProviderWorker.receiveNotification(false);
+        mMockNetworkProviderWorker.onInternetTypeChanged(INTERNET_WIFI);
+
+        mMockNetworkProviderWorker.onInternetTypeChanged(INTERNET_ETHERNET);
+
+        assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
+    }
+
+    @Test
+    public void onInternetTypeChanged_connectedFromEthernetToCarrier_callUpdateSlice() {
+        mMockNetworkProviderWorker.receiveNotification(false);
+        mMockNetworkProviderWorker.onInternetTypeChanged(INTERNET_ETHERNET);
+
+        mMockNetworkProviderWorker.onInternetTypeChanged(INTERNET_CELLULAR);
+
+        assertThat(mMockNetworkProviderWorker.hasNotification()).isTrue();
+    }
+
+    @Test
+    public void isEthernetConnected_connectedEthernet_shouldBeTrue() {
+        mMockNetworkProviderWorker.onInternetTypeChanged(INTERNET_ETHERNET);
+
+        assertThat(mMockNetworkProviderWorker.isEthernetConnected()).isTrue();
+    }
+
+    @Test
+    public void isEthernetConnected_connectedWifi_shouldBeFalse() {
+        mMockNetworkProviderWorker.onInternetTypeChanged(INTERNET_WIFI);
+
+        assertThat(mMockNetworkProviderWorker.isEthernetConnected()).isFalse();
+    }
+
+    @Test
+    public void isEthernetConnected_connectedCarrier_shouldBeFalse() {
+        mMockNetworkProviderWorker.onInternetTypeChanged(INTERNET_CELLULAR);
+
+        assertThat(mMockNetworkProviderWorker.isEthernetConnected()).isFalse();
+    }
+
     public class MockNetworkProviderWorker extends NetworkProviderWorker {
         private boolean mHasNotification = false;
         private int mDefaultDataSubId = 1;