Merge sc-v2-dev-plus-aosp-without-vendor@8433047

Bug: 226662282
Merged-In: I800f0f39a469a95eb36eeaaeb2aa60a39fd916d3
Change-Id: I71459583120f712298f47b4dbd2c791d8ef4e022
diff --git a/res/layout/select_account_list_item.xml b/res/layout/select_account_list_item.xml
index 716adff..dbc31be 100644
--- a/res/layout/select_account_list_item.xml
+++ b/res/layout/select_account_list_item.xml
@@ -20,7 +20,6 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:minHeight="?attr/listPreferredItemHeightSmall"
-    android:background="@drawable/sim_confirm_dialog_rounded_bg"
     android:gravity="center">
     <TextView android:id="@+id/title"
         android:textAppearance="@style/TextAppearance.SimConfirmDialogList"
@@ -36,6 +35,5 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_below="@id/title"
-        android:textColor="?android:attr/textColorSecondary"
         android:layout_alignStart="@id/title" />
 </LinearLayout>
diff --git a/res/layout/sim_confirm_dialog_item_multiple_enabled_profiles_supported.xml b/res/layout/sim_confirm_dialog_item_multiple_enabled_profiles_supported.xml
index 003cdbf..700fab3 100644
--- a/res/layout/sim_confirm_dialog_item_multiple_enabled_profiles_supported.xml
+++ b/res/layout/sim_confirm_dialog_item_multiple_enabled_profiles_supported.xml
@@ -25,6 +25,5 @@
     android:paddingBottom="?attr/listPreferredItemPaddingEnd"
     android:paddingLeft="?attr/listPreferredItemPaddingLeft"
     android:paddingRight="?attr/listPreferredItemPaddingRight"
-    android:background="@drawable/sim_confirm_dialog_rounded_bg"
     android:textAppearance="@style/TextAppearance.SimConfirmDialogList"
     />
diff --git a/res/layout/sim_confirm_dialog_multiple_enabled_profiles_supported.xml b/res/layout/sim_confirm_dialog_multiple_enabled_profiles_supported.xml
index 610bf3d..081efb3 100644
--- a/res/layout/sim_confirm_dialog_multiple_enabled_profiles_supported.xml
+++ b/res/layout/sim_confirm_dialog_multiple_enabled_profiles_supported.xml
@@ -26,15 +26,19 @@
             android:paddingEnd="24dp"
             android:paddingTop="16dp"
             android:paddingStart="24dp"
+            android:paddingBottom="32dp"
             android:gravity="center"
-            android:textAppearance="@style/TextAppearance.DialogMessage"/>
+            android:textAppearance="@style/TextAppearance.DialogMessage"
+            android:visibility="gone"/>
         <ListView
             android:id="@+id/carrier_list"
             android:layout_gravity="center"
-            android:paddingTop="16dp"
-            android:dividerHeight="1dp"
+            android:divider="?android:attr/colorBackgroundFloating"
+            android:dividerHeight="4dp"
+            android:background="@drawable/sim_confirm_dialog_rounded_bg"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
+            android:layout_height="wrap_content"
+            android:visibility="gone"/>
 
         <LinearLayout
             android:id="@+id/info_outline_layout"
@@ -46,7 +50,8 @@
             android:paddingTop="16dp"
             android:paddingStart="24dp"
             android:layout_marginBottom="16dp"
-            android:baselineAligned="true">
+            android:baselineAligned="true"
+            android:visibility="gone">
                 <ImageView
                     android:src="@drawable/ic_info_outline_24dp"
                     android:layout_width="wrap_content"
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index a388855..f69c952 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -28,6 +28,6 @@
     <style name="TextAppearance.SimConfirmDialogList.Summary">
         <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+        <item name="android:textColor">?android:attr/textColorSecondaryInverse</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/res/values-night/themes.xml b/res/values-night/themes.xml
index 4564827..946cd91 100644
--- a/res/values-night/themes.xml
+++ b/res/values-night/themes.xml
@@ -34,12 +34,6 @@
         <item name="android:colorBackground">@*android:color/surface_dark</item>
     </style>
 
-    <style name="Theme.AlertDialog.Base.Material3" parent="Theme.MaterialComponents.DayNight.Dialog.Alert">
-        <item name="colorPrimary">@*android:color/primary_device_default_settings</item>
-        <item name="colorAccent">@*android:color/accent_device_default_dark</item>
-        <item name="android:colorBackground">@*android:color/surface_dark</item>
-    </style>
-
     <!-- Material theme for the pages containing TabLayout and ViewPager -->
     <style name="Theme.TabTheme" parent="@style/Theme.MaterialComponents.DayNight">
         <item name="colorPrimary">@*android:color/edge_effect_device_default_dark</item>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 244f0fd..4f3d407 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -441,4 +441,8 @@
     <dimen name="chartview_trapezoid_radius">5dp</dimen>
     <dimen name="chartview_trapezoid_margin_start">1dp</dimen>
     <dimen name="chartview_trapezoid_margin_bottom">2dp</dimen>
+
+    <!-- Sims/Data mobile/Calls/SMS select dialog-->
+    <dimen name="sims_select_margin_bottom">24dp</dimen>
+    <dimen name="sims_select_margin_top">8dp</dimen>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index afa13a1..838d63b 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -919,6 +919,7 @@
 
     <style name="TextAppearance.SimConfirmDialogList.Summary">
         <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
 
     <style name="SimConfirmDialog.OutlineButton" parent="@android:style/Widget.Material.Button">
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index b57ea92..f0809ad 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -20,6 +20,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
+import android.provider.DeviceConfig;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -31,6 +32,7 @@
 import androidx.preference.SwitchPreference;
 
 import com.android.settings.R;
+import com.android.settings.core.SettingsUIDeviceConfig;
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LeAudioProfile;
@@ -70,6 +72,7 @@
     private List<CachedBluetoothDevice> mAllOfCachedDevices;
     private Map<String, List<CachedBluetoothDevice>> mProfileDeviceMap =
             new HashMap<String, List<CachedBluetoothDevice>>();
+    private boolean mIsLeContactSharingEnabled = false;
 
     @VisibleForTesting
     PreferenceCategory mProfilesContainer;
@@ -88,6 +91,8 @@
     protected void init(PreferenceScreen screen) {
         mProfilesContainer = (PreferenceCategory)screen.findPreference(getPreferenceKey());
         mProfilesContainer.setLayoutResource(R.layout.preference_bluetooth_profile_category);
+        mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
+                SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
         // Call refresh here even though it will get called later in onResume, to avoid the
         // list of switches appearing to "pop" into the page.
         refresh();
@@ -119,21 +124,11 @@
     private void refreshProfilePreference(SwitchPreference profilePref,
             LocalBluetoothProfile profile) {
         BluetoothDevice device = mCachedDevice.getDevice();
-        boolean isLeAudioEnabled = false;
+        boolean isLeAudioEnabled = isLeAudioEnabled();
         if (profile instanceof A2dpProfile || HEADSET_CLIENT.equals(profile.toString())) {
-            LocalBluetoothProfile leAudio = mProfileManager.getLeAudioProfile();
-            if (leAudio != null) {
-                List<CachedBluetoothDevice> leAudioDeviceList = mProfileDeviceMap.get(
-                        leAudio.toString());
-                if (leAudioDeviceList != null
-                        && leAudioDeviceList.stream()
-                        .anyMatch(item -> leAudio.isEnabled(item.getDevice()))) {
-                    isLeAudioEnabled = true;
-                }
-            }
             if (isLeAudioEnabled) {
                 // If the LeAudio profile is enabled on the LeAudio devices, then the
-                // SwitchPreferences of A2dp profile and Hfp profile are graied out.
+                // SwitchPreferences of A2dp profile and Hfp profile are grayed out.
                 profilePref.setEnabled(false);
             } else {
                 List<CachedBluetoothDevice> deviceList = mProfileDeviceMap.get(
@@ -145,12 +140,9 @@
         } else if (profile instanceof LeAudioProfile) {
             List<CachedBluetoothDevice> leAudioDeviceList = mProfileDeviceMap.get(
                     profile.toString());
-            boolean isLeAudioProfileEnable =
-                    leAudioDeviceList != null && leAudioDeviceList.stream().anyMatch(
-                            item -> profile.isEnabled(item.getDevice()));
             boolean isBusy = leAudioDeviceList != null
                     && leAudioDeviceList.stream().anyMatch(item -> item.isBusy());
-            if (isLeAudioProfileEnable && !isBusy) {
+            if (isLeAudioEnabled && !isBusy) {
                 LocalBluetoothProfile a2dp = mProfileManager.getA2dpProfile();
                 LocalBluetoothProfile hfp = mProfileManager.getHfpClientProfile();
                 // If the LeAudio profile is enabled on the LeAudio devices, then the
@@ -169,6 +161,10 @@
                 }
             }
             profilePref.setEnabled(!isBusy);
+        } else if (profile instanceof PbapServerProfile
+                && isLeAudioEnabled
+                && !mIsLeContactSharingEnabled) {
+            profilePref.setEnabled(false);
         } else {
             profilePref.setEnabled(!mCachedDevice.isBusy());
         }
@@ -203,6 +199,20 @@
         }
     }
 
+    private boolean isLeAudioEnabled(){
+        LocalBluetoothProfile leAudio = mProfileManager.getLeAudioProfile();
+        if (leAudio != null) {
+            List<CachedBluetoothDevice> leAudioDeviceList = mProfileDeviceMap.get(
+                    leAudio.toString());
+            if (leAudioDeviceList != null
+                    && leAudioDeviceList.stream()
+                    .anyMatch(item -> leAudio.isEnabled(item.getDevice()))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Helper method to enable a profile for a device.
      */
@@ -505,4 +515,4 @@
     public String getPreferenceKey() {
         return KEY_PROFILES_GROUP;
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/core/SettingsUIDeviceConfig.java b/src/com/android/settings/core/SettingsUIDeviceConfig.java
index 8c85c82..94074df 100644
--- a/src/com/android/settings/core/SettingsUIDeviceConfig.java
+++ b/src/com/android/settings/core/SettingsUIDeviceConfig.java
@@ -33,7 +33,11 @@
      * {@code true} if near by device suggestion is enabled in connected device page
      */
     public static final String BT_NEAR_BY_SUGGESTION_ENABLED = "bt_near_by_suggestion_enabled";
-
+    /**
+     * {@code true} if le audio contact sharing is enabled in BT device detail page
+     */
+    public static final String BT_LE_AUDIO_CONTACT_SHARING_ENABLED =
+            "bt_le_audio_contact_sharing_enabled";
     /**
      * {@code true} whether or not event_log for generic actions is enabled. Default is true.
      */
diff --git a/src/com/android/settings/network/SwitchSlotSidecar.java b/src/com/android/settings/network/SwitchSlotSidecar.java
index abf8842..7005452 100644
--- a/src/com/android/settings/network/SwitchSlotSidecar.java
+++ b/src/com/android/settings/network/SwitchSlotSidecar.java
@@ -78,11 +78,19 @@
         super.run(param);
     }
 
-    /** Starts switching to the removable slot. */
-    public void runSwitchToEuiccSlot(int id, int port, SubscriptionInfo removedSubInfo) {
+    /**
+     * Start the SimSlotMapping process if the euicc slot is not in SimSlotMapping list.
+     * @param physicalSlotId The physical slot id.
+     * @param port The port id.
+     * @param removedSubInfo The subscriptionInfo which is selected by the user to disable when all
+     *                      of sim slots are full in the device. If all of slots are not full in
+     *                       the device, then this is null.
+     */
+    public void runSwitchToEuiccSlot(int physicalSlotId, int port,
+            SubscriptionInfo removedSubInfo) {
         Param param = new Param();
         param.command = Command.SWITCH_TO_EUICC_SIM;
-        param.slotId = id;
+        param.slotId = physicalSlotId;
         param.removedSubInfo = removedSubInfo;
         param.port = port;
         super.run(param);
diff --git a/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java b/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java
index 888e5b2..0b39d6a 100644
--- a/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java
+++ b/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java
@@ -21,14 +21,13 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.UiccCardInfo;
-import android.telephony.UiccSlotMapping;
 import android.telephony.euicc.EuiccManager;
 import android.util.Log;
 
 import com.android.settings.SidecarFragment;
 import com.android.settings.network.telephony.EuiccOperationSidecar;
 
-import java.util.Collection;
+import java.util.Comparator;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -37,7 +36,6 @@
     private static final String TAG = "SwitchToEuiccSidecar";
     private static final String ACTION_SWITCH_TO_SUBSCRIPTION =
             "com.android.settings.network.SWITCH_TO_SUBSCRIPTION";
-    private static final int ESIM_SLOT_ID = 1;
 
     private PendingIntent mCallbackIntent;
     private int mSubId;
@@ -70,20 +68,15 @@
         }
     }
 
-    /** Starts calling EuiccManager#switchToSubscription to enable/disable the eSIM profile. */
-    // ToDo: delete this api and refactor the related code.
-    public void run(int subscriptionId) {
-        setState(State.RUNNING, Substate.UNUSED);
-        mCallbackIntent = createCallbackIntent();
-        mEuiccManager.switchToSubscription(subscriptionId, mCallbackIntent);
-    }
-
     /**
      * Starts calling EuiccManager#switchToSubscription to enable/disable the eSIM profile.
      *
      * @param subscriptionId the esim's subscriptionId.
-     * @param port the esim's portId. If user wants to inactivate esim, then user must to assign the
-     *             the port. If user wants to activate esim, then the port can be -1.
+     * @param port the esim's portId. If user wants to inactivate esim, then user must to assign
+     *             the corresponding port. If user wants to activate esim, then the port can be
+     *             {@link UiccSlotUtil#INVALID_PORT_ID}. When it is
+     *             {@link UiccSlotUtil#INVALID_PORT_ID}, the system will reassign a corresponding
+     *             port id.
      * @param removedSubInfo if the all of slots have sims, it should remove the one of active sim.
      *                       If the removedSubInfo is null, then use the default value.
      *                       The default value is the esim slot and portId 0.
@@ -92,11 +85,20 @@
         setState(State.RUNNING, Substate.UNUSED);
         mCallbackIntent = createCallbackIntent();
         mSubId = subscriptionId;
+        int targetSlot = getTargetSlot();
+        if (targetSlot < 0) {
+            Log.d(TAG, "There is no esim, the TargetSlot is " + targetSlot);
+            setState(State.ERROR, Substate.UNUSED);
+            return;
+        }
+
         // To check whether the esim slot's port is active. If yes, skip setSlotMapping. If no,
         // set this slot+port into setSimSlotMapping.
         mPort = (port < 0) ? getTargetPortId(removedSubInfo) : port;
         mRemovedSubInfo = removedSubInfo;
-        Log.i(TAG, "The SubId is " + mSubId + ". The port is " + mPort);
+        Log.d(TAG,
+                String.format("set esim into the SubId%d Slot%d:Port%d",
+                        mSubId, targetSlot, mPort));
 
         if (mTelephonyManager.isMultiSimEnabled() && removedSubInfo != null
                 && removedSubInfo.isEmbedded()) {
@@ -108,7 +110,7 @@
             mEuiccManager.switchToSubscription(SubscriptionManager.INVALID_SUBSCRIPTION_ID, mPort,
                     mCallbackIntent);
         } else {
-            mSwitchSlotSidecar.runSwitchToEuiccSlot(getTargetSlot(), mPort, removedSubInfo);
+            mSwitchSlotSidecar.runSwitchToEuiccSlot(targetSlot, mPort, removedSubInfo);
         }
     }
 
@@ -124,18 +126,26 @@
             return removedSubInfo.getPortIndex();
         }
 
-        // In DSDS+MEP mode, the removedSubInfo is psim or is null, it means the this esim need
-        // another port in the esim slot.
-        // To find another esim's port and value is from 0;
+        // In DSDS+MEP mode, the removedSubInfo is psim or is null, it means this esim needs
+        // a new corresponding port in the esim slot.
+        // For example:
+        // 1) If there is no enabled esim and the user add new esim. This new esim's port is 0.
+        // 2) If there is one enabled esim in port0 and the user add new esim. This new esim's
+        // port is 1.
+        // 3) If there is one enabled esim in port1 and the user add new esim. This new esim's
+        // port is 0.
+
         int port = 0;
-        Collection<UiccSlotMapping> uiccSlotMappings = mTelephonyManager.getSimSlotMapping();
-        for (UiccSlotMapping uiccSlotMapping :
-                uiccSlotMappings.stream()
-                        .filter(
-                                uiccSlotMapping -> uiccSlotMapping.getPhysicalSlotIndex()
-                                        == getTargetSlot())
-                        .collect(Collectors.toList())) {
-            if (uiccSlotMapping.getPortIndex() == port) {
+        SubscriptionManager subscriptionManager = getContext().getSystemService(
+                SubscriptionManager.class);
+        List<SubscriptionInfo> activeEsimSubInfos =
+                SubscriptionUtil.getActiveSubscriptions(subscriptionManager)
+                        .stream()
+                        .filter(i -> i.isEmbedded())
+                        .sorted(Comparator.comparingInt(SubscriptionInfo::getPortIndex))
+                        .collect(Collectors.toList());
+        for (SubscriptionInfo subscriptionInfo : activeEsimSubInfos) {
+            if (subscriptionInfo.getPortIndex() == port) {
                 port++;
             }
         }
@@ -143,7 +153,7 @@
     }
 
     private int getTargetSlot() {
-        return ESIM_SLOT_ID;
+        return UiccSlotUtil.getEsimSlotId(getContext());
     }
 
     private void onSwitchSlotSidecarStateChange() {
diff --git a/src/com/android/settings/network/SwitchToRemovableSlotSidecar.java b/src/com/android/settings/network/SwitchToRemovableSlotSidecar.java
index 9b9c0dd..a870f3b 100644
--- a/src/com/android/settings/network/SwitchToRemovableSlotSidecar.java
+++ b/src/com/android/settings/network/SwitchToRemovableSlotSidecar.java
@@ -81,29 +81,6 @@
     }
 
     /**
-     * Starts switching to the removable slot. It disables the active eSIM profile before switching
-     * if there is one.
-     *
-     * @param physicalSlotId removable physical SIM slot ID.
-     */
-    // ToDo: delete this api and refactor the related code.
-    public void run(int physicalSlotId) {
-        mPhysicalSlotId = physicalSlotId;
-        SubscriptionManager subscriptionManager =
-                getContext().getSystemService(SubscriptionManager.class);
-        if (SubscriptionUtil.getActiveSubscriptions(subscriptionManager).stream()
-                .anyMatch(SubscriptionInfo::isEmbedded)) {
-            // In SS mode, the esim is active, then inactivate the esim.
-            Log.i(TAG, "There is an active eSIM profile. Disable the profile first.");
-            // Use INVALID_SUBSCRIPTION_ID to disable the only active profile.
-            mSwitchToSubscriptionSidecar.run(SubscriptionManager.INVALID_SUBSCRIPTION_ID, 0, null);
-        } else {
-            Log.i(TAG, "There is no active eSIM profiles. Start to switch to removable slot.");
-            mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId, null);
-        }
-    }
-
-    /**
      * Starts switching to the removable slot.
      *
      * @param physicalSlotId removable physical SIM slot ID.
@@ -124,7 +101,7 @@
             // Use INVALID_SUBSCRIPTION_ID to disable the only active profile.
             mSwitchToSubscriptionSidecar.run(SubscriptionManager.INVALID_SUBSCRIPTION_ID, 0, null);
         } else if (mTelephonyManager.isMultiSimEnabled() && mRemovedSubInfo != null) {
-            // In DSDS mode+MEP, if the replaced esim is active, then it should be disabled esim
+            // In DSDS mode+MEP, if the replaced esim is active, then it should disable that esim
             // profile before changing SimSlotMapping process.
             // Use INVALID_SUBSCRIPTION_ID to disable the esim profile.
             mSwitchToSubscriptionSidecar.run(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
diff --git a/src/com/android/settings/network/TetherEnabler.java b/src/com/android/settings/network/TetherEnabler.java
index ef031f6..c83d971 100644
--- a/src/com/android/settings/network/TetherEnabler.java
+++ b/src/com/android/settings/network/TetherEnabler.java
@@ -31,6 +31,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
+import android.net.EthernetManager;
+import android.net.IpConfiguration;
 import android.net.TetheringManager;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
@@ -40,6 +42,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleObserver;
@@ -53,6 +56,7 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -81,6 +85,16 @@
     private static final String TAG = "TetherEnabler";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
+    private final class EthernetListener implements EthernetManager.InterfaceStateListener {
+        public void onInterfaceStateChanged(@NonNull String iface, int state, int role,
+                @NonNull IpConfiguration configuration) {
+            if (state == EthernetManager.STATE_LINK_UP) {
+                mAvailableInterfaces.put(iface, configuration);
+            } else {
+                mAvailableInterfaces.remove(iface, configuration);
+            }
+        }
+    }
 
     @Retention(SOURCE)
     @IntDef(
@@ -108,7 +122,6 @@
     private final ConnectivityManager mConnectivityManager;
     private final TetheringManager mTetheringManager;
     private final UserManager mUserManager;
-    private final String mEthernetRegex;
     private final DataSaverBackend mDataSaverBackend;
     private boolean mDataSaverEnabled;
     @VisibleForTesting
@@ -121,6 +134,10 @@
     private final AtomicReference<BluetoothPan> mBluetoothPan;
     private boolean mBluetoothEnableForTether;
     private final BluetoothAdapter mBluetoothAdapter;
+    private final EthernetManager mEthernetManager;
+    private final EthernetManager.InterfaceStateListener mEthernetListener = new EthernetListener();
+    private final ConcurrentHashMap<String, IpConfiguration> mAvailableInterfaces =
+            new ConcurrentHashMap<>();
 
     public TetherEnabler(Context context, SwitchWidgetController switchWidgetController,
             AtomicReference<BluetoothPan> bluetoothPan) {
@@ -134,11 +151,10 @@
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
         mBluetoothPan = bluetoothPan;
-        mEthernetRegex =
-                context.getString(com.android.internal.R.string.config_ethernet_iface_regex);
         mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled();
         mListeners = new ArrayList<>();
         mMainThreadHandler = new Handler(Looper.getMainLooper());
+        mEthernetManager = context.getSystemService(EthernetManager.class);
     }
 
     @OnLifecycleEvent(Lifecycle.Event.ON_START)
@@ -163,6 +179,10 @@
 
         mOnStartTetheringCallback = new OnStartTetheringCallback(this);
         updateState(null/*tethered*/);
+        if (mEthernetManager != null) {
+            mEthernetManager.addInterfaceStateListener(r -> mMainThreadHandler.post(r),
+                    mEthernetListener);
+        }
     }
 
     @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
@@ -173,6 +193,9 @@
         mContext.unregisterReceiver(mTetherChangeReceiver);
         mTetheringManager.unregisterTetheringEventCallback(mTetheringEventCallback);
         mTetheringEventCallback = null;
+        if (mEthernetManager != null) {
+            mEthernetManager.removeInterfaceStateListener(mEthernetListener);
+        }
     }
 
     public void addListener(OnTetherStateUpdateListener listener) {
@@ -246,7 +269,7 @@
                     tetherState |= TETHERING_USB_ON;
                 }
             }
-            if (s.matches(mEthernetRegex)) {
+            if (mAvailableInterfaces.containsKey(s)) {
                 tetherState |= TETHERING_ETHERNET_ON;
             }
         }
diff --git a/src/com/android/settings/network/UiccSlotUtil.java b/src/com/android/settings/network/UiccSlotUtil.java
index 8938cdb..8fdc370 100644
--- a/src/com/android/settings/network/UiccSlotUtil.java
+++ b/src/com/android/settings/network/UiccSlotUtil.java
@@ -20,11 +20,13 @@
 import android.content.Context;
 import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.UiccSlotInfo;
 import android.telephony.UiccSlotMapping;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.utils.ThreadUtils;
 
 import com.google.common.collect.ImmutableList;
@@ -33,9 +35,11 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 // ToDo: to do the refactor for renaming
 public class UiccSlotUtil {
@@ -44,6 +48,7 @@
 
     private static final long DEFAULT_WAIT_AFTER_SWITCH_TIMEOUT_MILLIS = 25 * 1000L;
 
+    public static final int INVALID_LOGICAL_SLOT_ID = -1;
     public static final int INVALID_PHYSICAL_SLOT_ID = -1;
     public static final int INVALID_PORT_ID = -1;
 
@@ -112,9 +117,27 @@
         }
         TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
         int inactiveRemovableSlot = getInactiveRemovableSlot(telMgr.getUiccSlotsInfo(), slotId);
+        Log.d(TAG, "The InactiveRemovableSlot: " + inactiveRemovableSlot);
+        if (inactiveRemovableSlot == INVALID_PHYSICAL_SLOT_ID) {
+            // The slot is invalid slot id, then to skip this.
+            // The slot is active, then the sim can enable directly.
+            return;
+        }
+
+        Collection<UiccSlotMapping> uiccSlotMappings = telMgr.getSimSlotMapping();
+        Log.d(TAG, "The SimSlotMapping: " + uiccSlotMappings);
+
+        SubscriptionManager subscriptionManager = context.getSystemService(
+                SubscriptionManager.class);
+        int excludedLogicalSlotIndex = getExcludedLogicalSlotIndex(uiccSlotMappings,
+                SubscriptionUtil.getActiveSubscriptions(subscriptionManager), removedSubInfo,
+                telMgr.isMultiSimEnabled());
         performSwitchToSlot(telMgr,
-                prepareUiccSlotMappingsForRemovableSlot(telMgr.getSimSlotMapping(),
-                        inactiveRemovableSlot, removedSubInfo, telMgr.isMultiSimEnabled()),
+                prepareUiccSlotMappings(uiccSlotMappings,
+                        /*slot is psim*/ true,
+                        inactiveRemovableSlot,
+                        /*removable sim's port Id*/ TelephonyManager.DEFAULT_PORT_INDEX,
+                        excludedLogicalSlotIndex),
                 context);
     }
 
@@ -122,7 +145,7 @@
      * Switches to the Euicc slot. It waits for SIM_STATE_LOADED after switch.
      *
      * @param context the application context.
-     * @param slotId the Euicc slot id.
+     * @param physicalSlotId the Euicc slot id.
      * @param port the Euicc slot port id.
      * @param removedSubInfo In the DSDS+MEP mode, if the all of slots have sims, it should
      *                       remove the one of active sim.
@@ -130,7 +153,7 @@
      *                       The default value is the esim slot and portId 0.
      * @throws UiccSlotsException if there is an error.
      */
-    public static synchronized void switchToEuiccSlot(Context context, int slotId, int port,
+    public static synchronized void switchToEuiccSlot(Context context, int physicalSlotId, int port,
             SubscriptionInfo removedSubInfo) throws UiccSlotsException {
         if (ThreadUtils.isMainThread()) {
             throw new IllegalThreadStateException(
@@ -138,47 +161,51 @@
         }
         TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
         Collection<UiccSlotMapping> uiccSlotMappings = telMgr.getSimSlotMapping();
-        Log.i(TAG, "The SimSlotMapping: " + uiccSlotMappings);
+        Log.d(TAG, "The SimSlotMapping: " + uiccSlotMappings);
 
-        if (isTargetSlotActive(uiccSlotMappings, slotId, port)) {
-            Log.i(TAG, "The slot is active, then the sim can enable directly.");
+        if (isTargetSlotActive(uiccSlotMappings, physicalSlotId, port)) {
+            Log.d(TAG, "The slot is active, then the sim can enable directly.");
             return;
         }
 
-        Collection<UiccSlotMapping> newUiccSlotMappings = new ArrayList<>();
-        if (!telMgr.isMultiSimEnabled()) {
-            // In the 'SS mode', the port is 0.
-            newUiccSlotMappings.add(new UiccSlotMapping(port, slotId, 0));
-        } else {
-            // DSDS+MEP
-            // The target slot+port is not active, but the all of logical slots are full. It
-            // needs to replace one of logical slots.
-            int removedSlot =
-                    (removedSubInfo != null) ? removedSubInfo.getSimSlotIndex() : slotId;
-            int removedPort = (removedSubInfo != null) ? removedSubInfo.getPortIndex() : 0;
-            Log.i(TAG,
-                    String.format("Start to set SimSlotMapping from slot%d-port%d to slot%d-port%d",
-                            slotId, port, removedSlot, removedPort));
-            newUiccSlotMappings =
-                    uiccSlotMappings.stream().map(uiccSlotMapping -> {
-                        if (uiccSlotMapping.getPhysicalSlotIndex() == removedSlot
-                                && uiccSlotMapping.getPortIndex() == removedPort) {
-                            return new UiccSlotMapping(port, slotId,
-                                    uiccSlotMapping.getLogicalSlotIndex());
-                        }
-                        return uiccSlotMapping;
-                    }).collect(Collectors.toList());
-        }
+        SubscriptionManager subscriptionManager = context.getSystemService(
+                SubscriptionManager.class);
+        int excludedLogicalSlotIndex = getExcludedLogicalSlotIndex(uiccSlotMappings,
+                SubscriptionUtil.getActiveSubscriptions(subscriptionManager), removedSubInfo,
+                telMgr.isMultiSimEnabled());
+        performSwitchToSlot(telMgr,
+                prepareUiccSlotMappings(uiccSlotMappings, /*slot is not psim*/ false,
+                        physicalSlotId, port, excludedLogicalSlotIndex),
+                context);
+    }
 
-        Log.i(TAG, "The SimSlotMapping: " + newUiccSlotMappings);
-        performSwitchToSlot(telMgr, newUiccSlotMappings, context);
+    /**
+     * @param context the application context.
+     * @return the esim slot. If the value is -1, there is not the esim.
+     */
+    public static int getEsimSlotId(Context context) {
+        TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
+        ImmutableList<UiccSlotInfo> slotInfos = UiccSlotUtil.getSlotInfos(telMgr);
+        int firstEsimSlot = IntStream.range(0, slotInfos.size())
+                .filter(
+                        index -> {
+                            UiccSlotInfo slotInfo = slotInfos.get(index);
+                            if (slotInfo == null) {
+                                return false;
+                            }
+                            return !slotInfo.isRemovable();
+                        })
+                .findFirst().orElse(-1);
+
+        Log.i(TAG, "firstEsimSlot: " + firstEsimSlot);
+        return firstEsimSlot;
     }
 
     private static boolean isTargetSlotActive(Collection<UiccSlotMapping> uiccSlotMappings,
-            int slotId, int port) {
+            int physicalSlotId, int port) {
         return uiccSlotMappings.stream()
                 .anyMatch(
-                        uiccSlotMapping -> uiccSlotMapping.getPhysicalSlotIndex() == slotId
+                        uiccSlotMapping -> uiccSlotMapping.getPhysicalSlotIndex() == physicalSlotId
                                 && uiccSlotMapping.getPortIndex() == port);
     }
 
@@ -239,49 +266,112 @@
         return INVALID_PHYSICAL_SLOT_ID;
     }
 
-    private static Collection<UiccSlotMapping> prepareUiccSlotMappingsForRemovableSlot(
-            Collection<UiccSlotMapping> uiccSlotMappings, int slotId,
-            SubscriptionInfo removedSubInfo, boolean isMultiSimEnabled) {
-        if (slotId == INVALID_PHYSICAL_SLOT_ID
-                || uiccSlotMappings.stream().anyMatch(uiccSlotMapping ->
-                        uiccSlotMapping.getPhysicalSlotIndex() == slotId
-                                && uiccSlotMapping.getPortIndex() == 0)) {
-            // The slot is invalid slot id, then to skip this.
-            // The slot is active, then the sim can enable directly.
+    // Device |                                        |Slot   |
+    // Working|                                        |Mapping|
+    // State  |Type                                    |Mode   |Friendly name
+    //--------------------------------------------------------------------------
+    // Single |SIM pSIM [RIL 0]                        |1      |pSIM active
+    // Single |SIM MEP Port #0 [RIL0]                  |2      |eSIM Port0 active
+    // Single |SIM MEP Port #1 [RIL0]                  |2.1    |eSIM Port1 active
+    // DSDS   |pSIM [RIL 0] + MEP Port #0 [RIL 1]      |3      |pSIM+Port0
+    // DSDS   |pSIM [RIL 0] + MEP Port #1 [RIL 1]      |3.1    |pSIM+Port1
+    // DSDS   |MEP Port #0 [RIL 0] + MEP Port #1 [RIL1]|3.2    |Dual-Ports-A
+    // DSDS   |MEP Port #1 [RIL 0] + MEP Port #0 [RIL1]|4      |Dual-Ports-B
+    //
+    // The rules are:
+    // 1. pSIM's logical slots always is [RIL 0].
+    // 2. assign the new active port to the same stack that will be de-activated
+    //    For example: mode#3->mode#4
+
+    @VisibleForTesting
+    static Collection<UiccSlotMapping> prepareUiccSlotMappings(
+            Collection<UiccSlotMapping> uiccSlotMappings, boolean isPsim, int physicalSlotId,
+            int port, int removedLogicalSlotId) {
+        if (removedLogicalSlotId == INVALID_LOGICAL_SLOT_ID) {
+            Log.d(TAG, "There is no removedLogicalSlotId. Do nothing.");
             return uiccSlotMappings;
         }
-
+        Log.d(TAG,
+                String.format(
+                        "Create new SimSlotMapping. Remove the UiccSlotMapping of logicalSlot%d"
+                                + ", and insert PhysicalSlotId%d-Port%d",
+                        removedLogicalSlotId, physicalSlotId, port));
         Collection<UiccSlotMapping> newUiccSlotMappings = new ArrayList<>();
-        if (!isMultiSimEnabled) {
-            // In the 'SS mode', the port is 0.
-            newUiccSlotMappings.add(new UiccSlotMapping(0, slotId, 0));
-        } else if (removedSubInfo != null) {
-            // DSDS+MEP
-            // The target slot+port is not active, but the all of logical slots are full. It
-            // needs to replace one of logical slots.
-            Log.i(TAG,
-                    String.format("Start to set SimSlotMapping from slot%d-port%d to slot%d-port%d",
-                            slotId, 0, removedSubInfo.getSimSlotIndex(),
-                            removedSubInfo.getPortIndex()));
-            newUiccSlotMappings =
-                    uiccSlotMappings.stream().map(uiccSlotMapping -> {
-                        if (uiccSlotMapping.getPhysicalSlotIndex()
-                                == removedSubInfo.getSimSlotIndex()
-                                && uiccSlotMapping.getPortIndex()
-                                == removedSubInfo.getPortIndex()) {
-                            return new UiccSlotMapping(0, slotId,
-                                    uiccSlotMapping.getLogicalSlotIndex());
-                        }
-                        return uiccSlotMapping;
-                    }).collect(Collectors.toList());
-        } else {
-            // DSDS+no MEP
-            // The removable slot should be in UiccSlotMapping.
-            newUiccSlotMappings = uiccSlotMappings;
-            Log.i(TAG, "The removedSubInfo is null");
+        int logicalSlotIndex = 0;
+        if (isPsim) {
+            // The target slot is psim. The psim is always the first index at LogicalSlot.
+            newUiccSlotMappings.add(
+                    new UiccSlotMapping(port, physicalSlotId, logicalSlotIndex++));
+        }
+        Collection<UiccSlotMapping> tempUiccSlotMappings =
+                uiccSlotMappings.stream()
+                        .sorted(Comparator.comparingInt(UiccSlotMapping::getLogicalSlotIndex))
+                        .collect(Collectors.toList());
+        for (UiccSlotMapping uiccSlotMapping : tempUiccSlotMappings) {
+            if (uiccSlotMapping.getLogicalSlotIndex() == removedLogicalSlotId) {
+                if (!isPsim) {
+                    // Replace this uiccSlotMapping
+                    newUiccSlotMappings.add(new UiccSlotMapping(port, physicalSlotId,
+                            uiccSlotMapping.getLogicalSlotIndex()));
+                }
+                continue;
+            }
+
+            // If the psim is inserted, then change the logicalSlotIndex for another
+            // uiccSlotMappings.
+            newUiccSlotMappings.add(isPsim
+                    ? new UiccSlotMapping(uiccSlotMapping.getPortIndex(),
+                    uiccSlotMapping.getPhysicalSlotIndex(), logicalSlotIndex++)
+                    : uiccSlotMapping);
         }
 
-        Log.i(TAG, "The SimSlotMapping: " + newUiccSlotMappings);
+        Log.d(TAG, "The new SimSlotMapping: " + newUiccSlotMappings);
         return newUiccSlotMappings;
     }
+
+    /**
+     * To get the excluded logical slot index from uiccSlotMapping list. If the sim which is
+     * enabled by user does not have the corresponding slot, then it needs to do the
+     * SimSlotMapping changed. This method can find the logical slot index of the corresponding slot
+     * before the Frameworks do the SimSlotMapping changed.
+     *
+     * @param uiccSlotMappings The uiccSlotMapping list from the Telephony Frameworks.
+     * @param activeSubInfos The active subscriptionInfo list.
+     * @param removedSubInfo The removed sim card which is selected by the user. If the user
+     *                       don't select removed sim , then the value is null.
+     * @param isMultiSimEnabled whether the device is in the DSDS mode or not.
+     * @return The logical slot index of removed slot. If it can't find the removed slot, it
+     * returns {@link #INVALID_LOGICAL_SLOT_ID}.
+     */
+    @VisibleForTesting
+    static int getExcludedLogicalSlotIndex(Collection<UiccSlotMapping> uiccSlotMappings,
+            Collection<SubscriptionInfo> activeSubInfos, SubscriptionInfo removedSubInfo,
+            boolean isMultiSimEnabled) {
+        if (!isMultiSimEnabled) {
+            Log.i(TAG, "In the ss mode.");
+            return 0;
+        }
+        if (removedSubInfo != null) {
+            // Use removedSubInfo's logicalSlotIndex
+            Log.i(TAG, "The removedSubInfo is not null");
+            return removedSubInfo.getSimSlotIndex();
+        }
+        // If it needs to do simSlotMapping when user enables sim and there is an empty slot which
+        // there is no enabled sim in this slot, then the empty slot can be removed.
+        Log.i(TAG, "The removedSubInfo is null");
+        return uiccSlotMappings.stream()
+                .filter(uiccSlotMapping -> {
+                    // find the empty slots.
+                    for (SubscriptionInfo subInfo : activeSubInfos) {
+                        if (subInfo.getSimSlotIndex() == uiccSlotMapping.getLogicalSlotIndex()) {
+                            return false;
+                        }
+                    }
+                    return true;
+                })
+                .sorted(Comparator.comparingInt(UiccSlotMapping::getLogicalSlotIndex))
+                .mapToInt(uiccSlotMapping -> uiccSlotMapping.getLogicalSlotIndex())
+                .findFirst()
+                .orElse(INVALID_LOGICAL_SLOT_ID);
+    }
 }
diff --git a/src/com/android/settings/network/telephony/ConfirmDialogFragment.java b/src/com/android/settings/network/telephony/ConfirmDialogFragment.java
index 6352180..dceaf1c 100644
--- a/src/com/android/settings/network/telephony/ConfirmDialogFragment.java
+++ b/src/com/android/settings/network/telephony/ConfirmDialogFragment.java
@@ -25,6 +25,7 @@
 import android.view.View;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.TextView;
 
@@ -115,13 +116,12 @@
         AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
                 .setPositiveButton(posBtnString, this)
                 .setNegativeButton(negBtnString, this);
+        View content = LayoutInflater.from(getContext()).inflate(
+                R.layout.sim_confirm_dialog_multiple_enabled_profiles_supported, null);
 
-        if (list != null && !list.isEmpty()) {
+        if (list != null && !list.isEmpty() && content != null) {
             Log.i(TAG, "list =" + list.toString());
 
-            View content = LayoutInflater.from(getContext()).inflate(
-                    R.layout.sim_confirm_dialog_multiple_enabled_profiles_supported, null);
-
             if (!TextUtils.isEmpty(title)) {
                 View titleView = LayoutInflater.from(getContext()).inflate(
                         R.layout.sim_confirm_dialog_title_multiple_enabled_profiles_supported,
@@ -133,6 +133,7 @@
             TextView dialogMessage = content.findViewById(R.id.msg);
             if (!TextUtils.isEmpty(message) && dialogMessage != null) {
                 dialogMessage.setText(message);
+                dialogMessage.setVisibility(View.VISIBLE);
             }
 
             final ArrayAdapter<String> arrayAdapterItems = new ArrayAdapter<String>(
@@ -140,8 +141,8 @@
                     R.layout.sim_confirm_dialog_item_multiple_enabled_profiles_supported, list);
             final ListView lvItems = content.findViewById(R.id.carrier_list);
             if (lvItems != null) {
+                lvItems.setVisibility(View.VISIBLE);
                 lvItems.setAdapter(arrayAdapterItems);
-                lvItems.setChoiceMode(ListView.CHOICE_MODE_NONE);
                 lvItems.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                     @Override
                     public void onItemClick(AdapterView<?> parent, View view, int position,
@@ -158,6 +159,10 @@
                     }
                 });
             }
+            final LinearLayout infoOutline = content.findViewById(R.id.info_outline_layout);
+            if (infoOutline != null) {
+                infoOutline.setVisibility(View.VISIBLE);
+            }
             builder.setView(content);
         } else {
             if (!TextUtils.isEmpty(title)) {
diff --git a/src/com/android/settings/sim/ChooseSimActivity.java b/src/com/android/settings/sim/ChooseSimActivity.java
index d0ccc4c..cebc1ba 100644
--- a/src/com/android/settings/sim/ChooseSimActivity.java
+++ b/src/com/android/settings/sim/ChooseSimActivity.java
@@ -159,11 +159,12 @@
         mSelectedItemIndex = subItem.getId();
         if (mSelectedItemIndex == INDEX_PSIM) {
             Log.i(TAG, "Ready to switch to pSIM slot.");
-            mSwitchToRemovableSlotSidecar.run(UiccSlotUtil.INVALID_PHYSICAL_SLOT_ID);
+            mSwitchToRemovableSlotSidecar.run(UiccSlotUtil.INVALID_PHYSICAL_SLOT_ID, null);
         } else {
             Log.i(TAG, "Ready to switch to eSIM subscription with index: " + mSelectedItemIndex);
             mSwitchToEuiccSubscriptionSidecar.run(
-                    mEmbeddedSubscriptions.get(mSelectedItemIndex).getSubscriptionId());
+                    mEmbeddedSubscriptions.get(mSelectedItemIndex).getSubscriptionId(),
+                    UiccSlotUtil.INVALID_PORT_ID, null);
         }
     }
 
diff --git a/src/com/android/settings/sim/PreferredSimDialogFragment.java b/src/com/android/settings/sim/PreferredSimDialogFragment.java
index 7786dd1..6b5e2b5 100644
--- a/src/com/android/settings/sim/PreferredSimDialogFragment.java
+++ b/src/com/android/settings/sim/PreferredSimDialogFragment.java
@@ -84,10 +84,11 @@
     private void updateDialog(AlertDialog dialog) {
         Log.d(TAG, "Dialog updated, dismiss status: " + mWasDismissed);
 
-        final SubscriptionInfo info = getPreferredSubscription();
         if (mWasDismissed) {
             return;
         }
+
+        final SubscriptionInfo info = getPreferredSubscription();
         if (info == null) {
             dismiss();
             return;
diff --git a/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java b/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java
index f5c2406..1f84177 100644
--- a/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java
+++ b/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java
@@ -26,8 +26,6 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.ListView;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
@@ -88,10 +86,11 @@
         if (subInfos == null || dds == null) {
             return null;
         }
-        return subInfos.stream().filter(subinfo -> subinfo != dds).findFirst().orElse(null);
+        return subInfos.stream().filter(subinfo -> subinfo.getSubscriptionId()
+                != dds.getSubscriptionId()).findFirst().orElse(null);
     }
 
-    private SubscriptionInfo getDefaultDataSubId() {
+    private SubscriptionInfo getDefaultDataSubInfo() {
         return getSubscriptionManager().getDefaultDataSubscriptionInfo();
     }
 
@@ -101,20 +100,22 @@
             return;
         }
 
-        SubscriptionInfo activeSubInfo = getDefaultDataSubId();
-        SubscriptionInfo newSubInfo = getNonDefaultDataSubscriptionInfo(activeSubInfo);
+        SubscriptionInfo currentDataSubInfo = getDefaultDataSubInfo();
+        SubscriptionInfo newSubInfo = getNonDefaultDataSubscriptionInfo(currentDataSubInfo);
 
-        if (newSubInfo == null || activeSubInfo == null) {
+        if (newSubInfo == null || currentDataSubInfo == null) {
+            Log.d(TAG, "one of target SubscriptionInfos is null");
             dismiss();
             return;
         }
-
+        Log.d(TAG, "newSubId: " + newSubInfo.getSubscriptionId()
+                + "currentDataSubID: " + currentDataSubInfo.getSubscriptionId());
         setTargetSubscriptionInfo(newSubInfo);
 
         CharSequence newDataCarrierName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
                 newSubInfo, getContext());
         CharSequence currentDataCarrierName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
-                activeSubInfo, getContext());
+                currentDataSubInfo, getContext());
 
         String positive = getContext().getString(
                 R.string.select_specific_sim_for_data_button, newDataCarrierName);
@@ -123,18 +124,10 @@
 
         View content = LayoutInflater.from(getContext()).inflate(
                 R.layout.sim_confirm_dialog_multiple_enabled_profiles_supported, null);
-        TextView dialogMessage = content.findViewById(R.id.msg);
+        TextView dialogMessage = content != null ? content.findViewById(R.id.msg) : null;
         if (!TextUtils.isEmpty(message) && dialogMessage != null) {
             dialogMessage.setText(message);
-        }
-
-        final ListView lvItems = content.findViewById(R.id.carrier_list);
-        if (lvItems != null) {
-            lvItems.setVisibility(View.GONE);
-        }
-        final LinearLayout infoOutline = content.findViewById(R.id.info_outline_layout);
-        if (infoOutline != null) {
-            infoOutline.setVisibility(View.GONE);
+            dialogMessage.setVisibility(View.VISIBLE);
         }
         dialog.setView(content);
 
diff --git a/src/com/android/settings/sim/SimDialogFragment.java b/src/com/android/settings/sim/SimDialogFragment.java
index 889f062..2e4fa49 100644
--- a/src/com/android/settings/sim/SimDialogFragment.java
+++ b/src/com/android/settings/sim/SimDialogFragment.java
@@ -83,6 +83,12 @@
         }
     }
 
+    @Override
+    public void dismiss() {
+        mChangeListener.stop();
+        super.dismiss();
+    }
+
     public abstract void updateDialog();
 
     @Override
diff --git a/src/com/android/settings/sim/SimListDialogFragment.java b/src/com/android/settings/sim/SimListDialogFragment.java
index 629a087..166d00a 100644
--- a/src/com/android/settings/sim/SimListDialogFragment.java
+++ b/src/com/android/settings/sim/SimListDialogFragment.java
@@ -19,7 +19,6 @@
 import android.app.Dialog;
 import android.app.settings.SettingsEnums;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.os.Bundle;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -28,6 +27,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.ListView;
 import android.widget.TextView;
@@ -47,12 +47,10 @@
  * Shows a dialog consisting of a list of SIMs (aka subscriptions), possibly including an additional
  * entry indicating "ask me every time".
  */
-public class SimListDialogFragment extends SimDialogFragment implements
-        DialogInterface.OnClickListener {
+public class SimListDialogFragment extends SimDialogFragment {
     private static final String TAG = "SimListDialogFragment";
     protected static final String KEY_INCLUDE_ASK_EVERY_TIME = "include_ask_every_time";
     protected static final String KEY_SHOW_CANCEL_ITEM = "show_cancel_item";
-    private static final int LIST_VIEW_DIVIDER_LINE_WEIGHT = 2;
 
     protected SelectSubscriptionAdapter mAdapter;
     @VisibleForTesting
@@ -79,21 +77,36 @@
         TextView titleTextView = titleView.findViewById(R.id.title);
         titleTextView.setText(getContext().getString(getTitleResId()));
         builder.setCustomTitle(titleTextView);
-
         mAdapter = new SelectSubscriptionAdapter(builder.getContext(), mSubscriptions);
-        setAdapter(builder);
 
         final AlertDialog dialog = builder.create();
-        ListView listView = dialog.getListView();
-        if (listView != null) {
-            listView.setDividerHeight(LIST_VIEW_DIVIDER_LINE_WEIGHT);
+
+        View content = LayoutInflater.from(getContext()).inflate(
+                R.layout.sim_confirm_dialog_multiple_enabled_profiles_supported, null);
+
+        final ListView lvItems = content != null ? content.findViewById(R.id.carrier_list) : null;
+        if (lvItems != null) {
+            setAdapter(lvItems);
+            lvItems.setVisibility(View.VISIBLE);
+            lvItems.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+                @Override
+                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                    onClick(position);
+                }
+            });
         }
+
+        dialog.setView(content);
         updateDialog();
+
         return dialog;
     }
 
-    @Override
-    public void onClick(DialogInterface dialog, int selectionIndex) {
+    /**
+     * If the user click the item at the list, then it sends the callback.
+     * @param selectionIndex the index of item in the list.
+     */
+    public void onClick(int selectionIndex) {
         if (selectionIndex >= 0 && selectionIndex < mSubscriptions.size()) {
             int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
             final SubscriptionInfo subscription = mSubscriptions.get(selectionIndex);
@@ -103,6 +116,7 @@
             final SimDialogActivity activity = (SimDialogActivity) getActivity();
             activity.onSubscriptionSelected(getDialogType(), subId);
         }
+        dismiss();
     }
 
     protected List<SubscriptionInfo> getCurrentSubscriptions() {
@@ -114,12 +128,13 @@
     @Override
     public void updateDialog() {
         Log.d(TAG, "Dialog updated, dismiss status: " + mWasDismissed);
+        if (mWasDismissed) {
+            return;
+        }
 
         List<SubscriptionInfo> currentSubscriptions = getCurrentSubscriptions();
         if (currentSubscriptions == null) {
-            if (!mWasDismissed) {
-                dismiss();
-            }
+            dismiss();
             return;
         }
         boolean includeAskEveryTime = getArguments().getBoolean(KEY_INCLUDE_ASK_EVERY_TIME);
@@ -143,14 +158,15 @@
         if (currentSubscriptions.equals(mSubscriptions)) {
             return;
         }
+
         mSubscriptions.clear();
         mSubscriptions.addAll(currentSubscriptions);
         mAdapter.notifyDataSetChanged();
     }
 
     @VisibleForTesting
-    void setAdapter(AlertDialog.Builder builder) {
-        builder.setAdapter(mAdapter, this);
+    void setAdapter(ListView lvItems) {
+        lvItems.setAdapter(mAdapter);
     }
 
     @Override
@@ -200,6 +216,16 @@
             final TextView title = convertView.findViewById(R.id.title);
             final TextView summary = convertView.findViewById(R.id.summary);
 
+            ViewGroup.MarginLayoutParams lp =
+                    (ViewGroup.MarginLayoutParams) parent.getLayoutParams();
+            if (lp != null) {
+                lp.setMargins(0, mContext.getResources().getDimensionPixelSize(
+                        R.dimen.sims_select_margin_top), 0,
+                        mContext.getResources().getDimensionPixelSize(
+                                R.dimen.sims_select_margin_bottom));
+                convertView.setLayoutParams(lp);
+            }
+
             if (sub == null) {
                 if (position == 0) {
                     title.setText(R.string.sim_calls_ask_first_prefs_title);
diff --git a/src/com/android/settings/sim/SwitchToEsimConfirmDialogActivity.java b/src/com/android/settings/sim/SwitchToEsimConfirmDialogActivity.java
index be2fa2d..db6e1b4 100644
--- a/src/com/android/settings/sim/SwitchToEsimConfirmDialogActivity.java
+++ b/src/com/android/settings/sim/SwitchToEsimConfirmDialogActivity.java
@@ -23,6 +23,7 @@
 import com.android.settings.R;
 import com.android.settings.SidecarFragment;
 import com.android.settings.network.SwitchToEuiccSubscriptionSidecar;
+import com.android.settings.network.UiccSlotUtil;
 import com.android.settings.network.telephony.AlertDialogFragment;
 import com.android.settings.network.telephony.ConfirmDialogFragment;
 import com.android.settings.network.telephony.SubscriptionActionDialogActivity;
@@ -110,7 +111,8 @@
             return;
         }
         Log.i(TAG, "User confirmed to switch to embedded slot.");
-        mSwitchToEuiccSubscriptionSidecar.run(mSubToEnabled.getSubscriptionId());
+        mSwitchToEuiccSubscriptionSidecar.run(mSubToEnabled.getSubscriptionId(),
+                UiccSlotUtil.INVALID_PORT_ID, null);
         showProgressDialog(
                 getString(
                         R.string.sim_action_switch_sub_dialog_progress,
diff --git a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
index e0bc9cd..4a6b96c 100644
--- a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
+++ b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
@@ -26,12 +26,14 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.UiccCardInfo;
 import android.telephony.UiccSlotInfo;
 import android.util.Log;
 
 import com.android.settings.network.SubscriptionUtil;
 import com.android.settings.network.UiccSlotUtil;
 import com.android.settings.network.UiccSlotsException;
+import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity;
 import com.android.settings.sim.ChooseSimActivity;
 import com.android.settings.sim.DsdsDialogActivity;
 import com.android.settings.sim.SimActivationNotifier;
@@ -40,6 +42,7 @@
 
 import com.google.common.collect.ImmutableList;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -83,8 +86,8 @@
             throw new IllegalStateException("Cannot be called from main thread.");
         }
 
-        if (mTelMgr.getActiveModemCount() > 1) {
-            Log.i(TAG, "The device is already in DSDS mode. Do nothing.");
+        if (mTelMgr.getActiveModemCount() > 1 && !isMultipleEnabledProfilesSupported()) {
+            Log.i(TAG, "The device is already in DSDS mode and no MEP. Do nothing.");
             return;
         }
 
@@ -96,17 +99,30 @@
 
         int lastRemovableSlotState = getLastRemovableSimSlotState(mContext);
         int currentRemovableSlotState = removableSlotInfo.getCardStateInfo();
+        boolean isRemovableSimInserted =
+                lastRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_ABSENT
+                        && currentRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_PRESENT;
+        boolean isRemovableSimRemoved =
+                lastRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_PRESENT
+                        && currentRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_ABSENT;
 
         // Sets the current removable slot state.
         setRemovableSimSlotState(mContext, currentRemovableSlotState);
 
-        if (lastRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_ABSENT
-                && currentRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_PRESENT) {
+        if (mTelMgr.getActiveModemCount() > 1 && isMultipleEnabledProfilesSupported()) {
+            if(!isRemovableSimInserted) {
+                Log.i(TAG, "Removable Sim is not inserted in DSDS mode and MEP. Do nothing.");
+                return;
+            }
+            handleRemovableSimInsertUnderDsdsMep(removableSlotInfo);
+            return;
+        }
+
+        if (isRemovableSimInserted) {
             handleSimInsert(removableSlotInfo);
             return;
         }
-        if (lastRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_PRESENT
-                && currentRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_ABSENT) {
+        if (isRemovableSimRemoved) {
             handleSimRemove(removableSlotInfo);
             return;
         }
@@ -210,10 +226,11 @@
         }
 
         List<SubscriptionInfo> groupedEmbeddedSubscriptions = getGroupedEmbeddedSubscriptions();
-
         if (groupedEmbeddedSubscriptions.size() == 0 || !removableSlotInfo.getPorts().stream()
                 .findFirst().get().isActive()) {
-            Log.i(TAG, "eSIM slot is active or no subscriptions exist. Do nothing.");
+            Log.i(TAG, "eSIM slot is active or no subscriptions exist. Do nothing."
+                            + " The removableSlotInfo: " + removableSlotInfo
+                            + ", groupedEmbeddedSubscriptions: " + groupedEmbeddedSubscriptions);
             return;
         }
 
@@ -231,6 +248,24 @@
         startChooseSimActivity(false);
     }
 
+    private void handleRemovableSimInsertUnderDsdsMep(UiccSlotInfo removableSlotInfo) {
+        Log.i(TAG, "Handle Removable SIM inserted under DSDS+Mep.");
+
+        if (removableSlotInfo.getPorts().stream().findFirst().get().isActive()) {
+            Log.i(TAG, "The removable slot is already active. Do nothing. removableSlotInfo: "
+                    + removableSlotInfo);
+            return;
+        }
+
+        List<SubscriptionInfo> subscriptionInfos = getAvailableRemovableSubscription();
+        if (subscriptionInfos == null || subscriptionInfos.get(0) == null) {
+            Log.e(TAG, "Unable to find the removable subscriptionInfo. Do nothing.");
+            return;
+        }
+        Log.d(TAG, "getAvailableRemovableSubscription:" + subscriptionInfos);
+        startSimConfirmDialogActivity(subscriptionInfos.get(0).getSubscriptionId());
+    }
+
     private int getLastRemovableSimSlotState(Context context) {
         final SharedPreferences prefs = context.getSharedPreferences(EUICC_PREFS, MODE_PRIVATE);
         return prefs.getInt(KEY_REMOVABLE_SLOT_STATE, UiccSlotInfo.CARD_STATE_INFO_ABSENT);
@@ -260,7 +295,6 @@
         }
         for (UiccSlotInfo slotInfo : slotInfos) {
             if (slotInfo != null && slotInfo.isRemovable()) {
-
                 return slotInfo;
             }
         }
@@ -296,6 +330,16 @@
                         .collect(Collectors.toList()));
     }
 
+    protected List<SubscriptionInfo> getAvailableRemovableSubscription() {
+        List<SubscriptionInfo> subList = new ArrayList<>();
+        for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mContext)) {
+            if (!info.isEmbedded()) {
+                subList.add(info);
+            }
+        }
+        return subList;
+    }
+
     private void startChooseSimActivity(boolean psimInserted) {
         Intent intent = ChooseSimActivity.getIntent(mContext);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -316,5 +360,26 @@
         mContext.startActivity(intent);
     }
 
+    private void startSimConfirmDialogActivity(int subId) {
+        if (!SubscriptionManager.isUsableSubscriptionId(subId)) {
+            Log.i(TAG, "Unable to enable subscription due to invalid subscription ID.");
+            return;
+        }
+        Log.d(TAG, "Start ToggleSubscriptionDialogActivity with " + subId + " under DSDS+Mep.");
+        Intent intent = ToggleSubscriptionDialogActivity.getIntent(mContext, subId, true);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(intent);
+    }
+
+    private boolean isMultipleEnabledProfilesSupported() {
+        List<UiccCardInfo> cardInfos = mTelMgr.getUiccCardsInfo();
+        if (cardInfos == null) {
+            Log.d(TAG, "UICC cards info list is empty.");
+            return false;
+        }
+        return cardInfos.stream().anyMatch(
+                cardInfo -> cardInfo.isMultipleEnabledProfilesSupported());
+    }
+
     private SimSlotChangeHandler() {}
 }
diff --git a/tests/robotests/src/com/android/settings/sim/SimListDialogFragmentTest.java b/tests/robotests/src/com/android/settings/sim/SimListDialogFragmentTest.java
index 070bcb1..7b17b74 100644
--- a/tests/robotests/src/com/android/settings/sim/SimListDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/sim/SimListDialogFragmentTest.java
@@ -77,7 +77,7 @@
         doReturn(activity).when(mFragment).getActivity();
         doNothing().when(activity).onSubscriptionSelected(anyInt(), anyInt());
 
-        mFragment.onClick(alertDialog, 1);
+        mFragment.onClick(1);
         verify(activity).onSubscriptionSelected(dialogType, SIM2_ID);
     }
 
@@ -117,7 +117,7 @@
         doReturn(activity).when(mFragment).getActivity();
         doNothing().when(activity).onSubscriptionSelected(anyInt(), anyInt());
 
-        mFragment.onClick(alertDialog, 0);
+        mFragment.onClick(0);
         verify(activity).onSubscriptionSelected(dialogType,
                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
     }
diff --git a/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java b/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java
new file mode 100644
index 0000000..2cf9845
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java
@@ -0,0 +1,794 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network;
+
+import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
+import android.telephony.UiccPortInfo;
+import android.telephony.UiccSlotInfo;
+import android.telephony.UiccSlotMapping;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class UiccSlotUtilTest {
+    private Context mContext;
+    @Mock
+    private TelephonyManager mTelephonyManager;
+
+    private static final int ESIM_PHYSICAL_SLOT = 0;
+    private static final int PSIM_PHYSICAL_SLOT = 1;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+    }
+
+    @Test
+    public void getSlotInfos_oneSimSlotDevice_returnTheCorrectSlotInfoList() {
+        when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(oneSimSlotDeviceActivePsim());
+        ImmutableList<UiccSlotInfo> testUiccSlotInfos =
+                UiccSlotUtil.getSlotInfos(mTelephonyManager);
+
+        assertThat(testUiccSlotInfos.size()).isEqualTo(1);
+    }
+
+    @Test
+    public void getSlotInfos_twoSimSlotsDevice_returnTheCorrectSlotInfoList() {
+        when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
+                twoSimSlotsDeviceActivePsimActiveEsim());
+        ImmutableList<UiccSlotInfo> testUiccSlotInfos =
+                UiccSlotUtil.getSlotInfos(mTelephonyManager);
+
+        assertThat(testUiccSlotInfos.size()).isEqualTo(2);
+    }
+
+    @Test
+    public void getEsimSlotId_twoSimSlotsDeviceAndEsimIsSlot0_returnTheCorrectEsimSlot() {
+        when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
+                twoSimSlotsDeviceActiveEsimActivePsim());
+        int testSlot = UiccSlotUtil.getEsimSlotId(mContext);
+
+        assertThat(testSlot).isEqualTo(0);
+    }
+
+    @Test
+    public void getEsimSlotId_twoSimSlotsDeviceAndEsimIsSlot1_returnTheCorrectEsimSlot() {
+        when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
+                twoSimSlotsDeviceActivePsimActiveEsim());
+        int testSlot = UiccSlotUtil.getEsimSlotId(mContext);
+
+        assertThat(testSlot).isEqualTo(1);
+    }
+
+    @Test
+    public void getEsimSlotId_noEimSlotDevice_returnTheCorrectEsimSlot() {
+        when(mTelephonyManager.getUiccSlotsInfo()).thenReturn(
+                oneSimSlotDeviceActivePsim());
+        int testSlot = UiccSlotUtil.getEsimSlotId(mContext);
+
+        assertThat(testSlot).isEqualTo(-1);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_fromPsimActiveToEsimPort0Active_esimPort0Active() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingSsModePsimActive();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingSsModeEsimPort0Active();
+        int removedLogicalSlotIndex = 0;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_fromEsimPort0ActiveToPsimActive_psimActive() {
+        Collection<UiccSlotMapping> uiccSlotMappings =
+                createUiccSlotMappingSsModeEsimPort0Active();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingSsModePsimActive();
+        int removedLogicalSlotIndex = 0;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_fromPsimAndPort0ToPsimAndPort1_psimAndPort1() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort0();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingPsimAndPort1();
+        int removedLogicalSlotIndex = 1;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 1, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_fromPsimAndPort1ToPsimAndPort0_psimAndPort0() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort1();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingPsimAndPort0();
+        int removedLogicalSlotIndex = 1;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_fromPsimAndPort0ToDualPortsB_dualPortsB() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort0();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingDualPortsB();
+        int removedLogicalSlotIndex = 0;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 1, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_fromPsimAndPort1ToDualPortsA_dualPortsA() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort1();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingDualPortsA();
+        int removedLogicalSlotIndex = 0;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_noPsimAndFromPsimAndPort0ToDualPortsB_dualPortsB() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort0();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingDualPortsB();
+        int removedLogicalSlotIndex = 0;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 1, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_noPsimAndFromPsimAndPort1ToDualPortsA_dualPortsA() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort1();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingDualPortsA();
+        int removedLogicalSlotIndex = 0;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_oneEsimAndFromDualPortsAToPsimAndPort1_psimAndPort1() {
+        // There is only one enabled esimPort1 before user enables the psim.
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsA();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingPsimAndPort1();
+        int removedLogicalSlotIndex = 0;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_oneEsimAndFromDualPortsAToPsimAndPort0_psimAndPort0() {
+        // There is only one enabled esimPort0 before user enables the psim.
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsA();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingPsimAndPort0();
+        int removedLogicalSlotIndex = 1;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_oneEsimAndFromDualPortsBToPsimAndPort1_psimAndPort1() {
+        // There is only one enabled esimPort1 before user enables the psim.
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsB();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingPsimAndPort1();
+        int removedLogicalSlotIndex = 1;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_oneEsimAndFromDualPortsBToPsimAndPort0_psimAndPort0() {
+        // There is only one enabled esimPort0 before user enables the psim.
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsB();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingPsimAndPort0();
+        int removedLogicalSlotIndex = 0;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_fromDualPortsAToPsimAndPort1_psimAndPort1() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsA();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingPsimAndPort1();
+        int removedLogicalSlotIndex = 0;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_fromDualPortsAToPsimAndPort0_psimAndPort0() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsA();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingPsimAndPort0();
+        int removedLogicalSlotIndex = 1;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_fromDualPortsBToPsimAndPort1_psimAndPort1() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsB();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingPsimAndPort1();
+        int removedLogicalSlotIndex = 1;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void prepareUiccSlotMappings_fromDualPortsBToPsimAndPort0_psimAndPort0() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsB();
+        Collection<UiccSlotMapping> verifyUiccSlotMappings =
+                createUiccSlotMappingPsimAndPort0();
+        int removedLogicalSlotIndex = 0;
+
+        Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
+
+        compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_fromPsimActiveToEsimPort0Active_logicalSlot0() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingSsModePsimActive();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListOneSim(0, 0);
+        SubscriptionInfo removedSubInfo = null;
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, false);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_fromEsimPort0ActiveToPsimActive_logicalSlot0() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingSsModeEsimPort0Active();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListOneSim(0, 0);
+        SubscriptionInfo removedSubInfo = null;
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, false);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_fromPsimAndPort0ToPsimAndPort1_logicalSlot1() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort0();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListTwoSims(0, 0, 1, 0);
+        SubscriptionInfo removedSubInfo = createSubscriptionInfo(1, 0);
+        int verifyExcludedLogicalSlotIndex = 1;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_fromPsimAndPort1ToPsimAndPort0_logicalSlot1() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort1();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListTwoSims(0, 0, 1, 1);
+        SubscriptionInfo removedSubInfo = createSubscriptionInfo(1, 1);
+        int verifyExcludedLogicalSlotIndex = 1;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_fromPsimAndPort0ToDualPortsB_logicalSlot0() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort0();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListTwoSims(0, 0, 1, 0);
+        SubscriptionInfo removedSubInfo = createSubscriptionInfo(0, 0);
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_fromPsimAndPort1ToDualPortsA_logicalSlot0() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort1();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListTwoSims(0, 0, 1, 1);
+        SubscriptionInfo removedSubInfo = createSubscriptionInfo(0, 0);
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_noPsimAndFromPsimAndPort0ToDualPortsB_logicalSlot0() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort0();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListOneSim(1, 0);
+        SubscriptionInfo removedSubInfo = null;
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_noPsimAndFromPsimAndPort1ToDualPortsA_logicalSlot0() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort1();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListOneSim(1, 1);
+        SubscriptionInfo removedSubInfo = null;
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_oneEsimAndFromDualPortsAToPsimAndPort1_logicalSlot0() {
+        // There is only one enabled esimPort1 before user enables the psim.
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsA();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListOneSim(1, 1);
+        SubscriptionInfo removedSubInfo = null;
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_oneEsimAndFromDualPortsAToPsimAndPort0_logicalSlot1() {
+        // There is only one enabled esimPort0 before user enables the psim.
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsA();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListOneSim(0, 0);
+        SubscriptionInfo removedSubInfo = null;
+        int verifyExcludedLogicalSlotIndex = 1;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_oneEsimAndFromDualPortsBToPsimAndPort1_logicalSlot1() {
+        // There is only one enabled esimPort1 before user enables the psim.
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsB();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListOneSim(0, 1);
+        SubscriptionInfo removedSubInfo = null;
+        int verifyExcludedLogicalSlotIndex = 1;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_oneEsimAndFromDualPortsBToPsimAndPort0_logicalSlot0() {
+        // There is only one enabled esimPort0 before user enables the psim.
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsB();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListOneSim(1, 0);
+        SubscriptionInfo removedSubInfo = null;
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_fromDualPortsAToPsimAndPort1_logicalSlot0() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsA();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListTwoSims(0, 0, 1, 1);
+        SubscriptionInfo removedSubInfo = createSubscriptionInfo(0, 0);
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_fromDualPortsAToPsimAndPort0_logicalSlot1() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsA();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListTwoSims(0, 0, 1, 1);
+        SubscriptionInfo removedSubInfo = createSubscriptionInfo(1, 1);
+        int verifyExcludedLogicalSlotIndex = 1;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_fromDualPortsBToPsimAndPort1_logicalSlot1() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsB();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListTwoSims(0, 1, 1, 0);
+        SubscriptionInfo removedSubInfo = createSubscriptionInfo(1, 0);
+        int verifyExcludedLogicalSlotIndex = 1;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_fromDualPortsBToPsimAndPort0_logicalSlot0() {
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsB();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList =
+                createActiveSubscriptionInfoListTwoSims(0, 1, 1, 0);
+        SubscriptionInfo removedSubInfo = createSubscriptionInfo(0, 1);
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_noEsimAndFromDualPortsAToPsimAndPort1_logicalSlot0() {
+        // There is no profiles enabled on either esim port before user enables the psim.
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsA();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<>();
+        SubscriptionInfo removedSubInfo = null;
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_noEsimAndFromDualPortsBToPsimAndPort0_logicalSlot0() {
+        // There is no profiles enabled on either esim port before user enables the psim.
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsB();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<>();
+        SubscriptionInfo removedSubInfo = null;
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    @Test
+    public void getExcludedLogicalSlotIndex_noEsimNoOrdingFromDualPortsBToPsimAndPort1_logical0() {
+        // There is no profiles enabled on either esim port before user enables the psim.
+        Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsBNoOrding();
+        Collection<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<>();
+        SubscriptionInfo removedSubInfo = null;
+        int verifyExcludedLogicalSlotIndex = 0;
+
+        int testExcludedLogicalSlotIndex = UiccSlotUtil.getExcludedLogicalSlotIndex(
+                uiccSlotMappings, activeSubscriptionInfoList, removedSubInfo, true);
+
+        assertThat(testExcludedLogicalSlotIndex).isEqualTo(verifyExcludedLogicalSlotIndex);
+    }
+
+    private void compareTwoUiccSlotMappings(Collection<UiccSlotMapping> testUiccSlotMappings,
+            Collection<UiccSlotMapping> verifyUiccSlotMappings) {
+        assertThat(testUiccSlotMappings.size()).isEqualTo(verifyUiccSlotMappings.size());
+        Iterator<UiccSlotMapping> testIterator = testUiccSlotMappings.iterator();
+        Iterator<UiccSlotMapping> verifyIterator = verifyUiccSlotMappings.iterator();
+        while (testIterator.hasNext()) {
+            UiccSlotMapping testUiccSlotMapping = testIterator.next();
+            UiccSlotMapping verifyUiccSlotMapping = verifyIterator.next();
+            assertThat(testUiccSlotMapping.getLogicalSlotIndex()).isEqualTo(
+                    verifyUiccSlotMapping.getLogicalSlotIndex());
+            assertThat(testUiccSlotMapping.getPortIndex()).isEqualTo(
+                    verifyUiccSlotMapping.getPortIndex());
+            assertThat(testUiccSlotMapping.getPhysicalSlotIndex()).isEqualTo(
+                    verifyUiccSlotMapping.getPhysicalSlotIndex());
+        }
+    }
+
+    private SubscriptionInfo createSubscriptionInfo(int logicalSlotIndex, int portIndex) {
+        return new SubscriptionInfo(
+                0, "", logicalSlotIndex, "", "", 0, 0, "", 0, null, "", "", "",
+                true /* isEmbedded */,
+                null, "", 25,
+                false, null, false, 0, 0, 0, null, null, true, portIndex);
+    }
+
+    private List<SubscriptionInfo> createActiveSubscriptionInfoListOneSim(int logicalSlotIndex,
+            int portIndex) {
+        List<SubscriptionInfo> subscriptionInfoList = new ArrayList<>();
+        subscriptionInfoList.add(createSubscriptionInfo(logicalSlotIndex, portIndex));
+
+        return subscriptionInfoList;
+    }
+
+    private List<SubscriptionInfo> createActiveSubscriptionInfoListTwoSims(int logicalSlotIndex1,
+            int portIndex1, int logicalSlotIndex2, int portIndex2) {
+        List<SubscriptionInfo> subscriptionInfoList = new ArrayList<>();
+        subscriptionInfoList.add(createSubscriptionInfo(logicalSlotIndex1, portIndex1));
+        subscriptionInfoList.add(createSubscriptionInfo(logicalSlotIndex2, portIndex2));
+        return subscriptionInfoList;
+    }
+
+    // Device |                                        |Slot   |
+    // Working|                                        |Mapping|
+    // State  |Type                                    |Mode   |Friendly name
+    //--------------------------------------------------------------------------
+    // Single |SIM pSIM [RIL 0]                        |1      |pSIM active
+    // Single |SIM MEP Port #0 [RIL0]                  |2      |eSIM Port0 active
+    // Single |SIM MEP Port #1 [RIL0]                  |2.1    |eSIM Port1 active
+    // DSDS   |pSIM [RIL 0] + MEP Port #0 [RIL 1]      |3      |pSIM+Port0
+    // DSDS   |pSIM [RIL 0] + MEP Port #1 [RIL 1]      |3.1    |pSIM+Port1
+    // DSDS   |MEP Port #0 [RIL 0] + MEP Port #1 [RIL1]|3.2    |Dual-Ports-A
+    // DSDS   |MEP Port #1 [RIL 0] + MEP Port #0 [RIL1]|4      |Dual-Ports-B
+    private List<UiccSlotMapping> createUiccSlotMappingSsModePsimActive() {
+        List<UiccSlotMapping> slotMap = new ArrayList<>();
+        slotMap.add(new UiccSlotMapping(0, PSIM_PHYSICAL_SLOT, 0));
+
+        return slotMap;
+    }
+
+    private List<UiccSlotMapping> createUiccSlotMappingSsModeEsimPort0Active() {
+        List<UiccSlotMapping> slotMap = new ArrayList<>();
+        slotMap.add(new UiccSlotMapping(0, ESIM_PHYSICAL_SLOT, 0));
+
+        return slotMap;
+    }
+
+    private List<UiccSlotMapping> createUiccSlotMappingSsModeEsimPort1Active() {
+        List<UiccSlotMapping> slotMap = new ArrayList<>();
+        slotMap.add(new UiccSlotMapping(1, ESIM_PHYSICAL_SLOT, 0));
+
+        return slotMap;
+    }
+
+    private List<UiccSlotMapping> createUiccSlotMappingPsimAndPort0() {
+        List<UiccSlotMapping> slotMap = new ArrayList<>();
+        slotMap.add(new UiccSlotMapping(0, PSIM_PHYSICAL_SLOT, 0));
+        slotMap.add(new UiccSlotMapping(0, ESIM_PHYSICAL_SLOT, 1));
+
+        return slotMap;
+    }
+
+    private List<UiccSlotMapping> createUiccSlotMappingPsimAndPort1() {
+        List<UiccSlotMapping> slotMap = new ArrayList<>();
+        slotMap.add(new UiccSlotMapping(0, PSIM_PHYSICAL_SLOT, 0));
+        slotMap.add(new UiccSlotMapping(1, ESIM_PHYSICAL_SLOT, 1));
+
+        return slotMap;
+    }
+
+    private List<UiccSlotMapping> createUiccSlotMappingDualPortsA() {
+        List<UiccSlotMapping> slotMap = new ArrayList<>();
+        slotMap.add(new UiccSlotMapping(0, ESIM_PHYSICAL_SLOT, 0));
+        slotMap.add(new UiccSlotMapping(1, ESIM_PHYSICAL_SLOT, 1));
+
+        return slotMap;
+    }
+
+    private List<UiccSlotMapping> createUiccSlotMappingDualPortsB() {
+        List<UiccSlotMapping> slotMap = new ArrayList<>();
+        slotMap.add(new UiccSlotMapping(1, ESIM_PHYSICAL_SLOT, 0));
+        slotMap.add(new UiccSlotMapping(0, ESIM_PHYSICAL_SLOT, 1));
+
+        return slotMap;
+    }
+    private List<UiccSlotMapping> createUiccSlotMappingDualPortsBNoOrding() {
+        List<UiccSlotMapping> slotMap = new ArrayList<>();
+        slotMap.add(new UiccSlotMapping(0, ESIM_PHYSICAL_SLOT, 1));
+        slotMap.add(new UiccSlotMapping(1, ESIM_PHYSICAL_SLOT, 0));
+
+        return slotMap;
+    }
+    /**
+     * The "oneSimSlotDevice" has below cases
+     * 1) The device is one psim slot and no esim slot
+     * 2) The device is no psim slot and one esim slot. like the watch.
+     *
+     * The "twoSimsSlotDevice" has below cases
+     * 1) The device is one psim slot and one esim slot
+     * 2) The device is two psim slots
+     */
+
+    private UiccSlotInfo[] oneSimSlotDeviceActivePsim() {
+        return new UiccSlotInfo[]{createUiccSlotInfo(false, true, 0, true)};
+    }
+
+    private UiccSlotInfo[] oneSimSlotDeviceActiveEsim() {
+        return new UiccSlotInfo[]{createUiccSlotInfo(true, false, 1, true)};
+    }
+
+    private UiccSlotInfo[] twoSimSlotsDeviceActivePsimActiveEsim() {
+        return new UiccSlotInfo[]{
+                createUiccSlotInfo(false, true, 0, true),
+                createUiccSlotInfo(true, false, 1, true)};
+    }
+
+    private UiccSlotInfo[] twoSimSlotsDeviceActiveEsimActivePsim() {
+        return new UiccSlotInfo[]{
+                createUiccSlotInfo(true, false, 0, true),
+                createUiccSlotInfo(false, true, 1, true)};
+    }
+
+    private UiccSlotInfo[] twoSimSlotsDeviceTwoActiveEsims() {
+        // device supports MEP, so device can enable two esims.
+        // If device has psim slot, the UiccSlotInfo of psim always be in UiccSlotInfo[].
+        return new UiccSlotInfo[]{
+                createUiccSlotInfo(false, true, -1, true),
+                createUiccSlotInfoForEsimMep(0, true, 1, true)};
+    }
+
+    private UiccSlotInfo[] twoSimSlotsDeviceActivePsimInactiveEsim() {
+        return new UiccSlotInfo[]{
+                createUiccSlotInfo(false, true, 0, true),
+                createUiccSlotInfo(true, false, -1, false)};
+    }
+
+    private UiccSlotInfo[] twoSimSlotsDeviceInactivePsimActiveEsim() {
+        return new UiccSlotInfo[]{
+                createUiccSlotInfo(false, true, 0, false),
+                createUiccSlotInfo(true, false, 1, true)};
+    }
+
+    private UiccSlotInfo[] twoSimSlotsDeviceNoInsertPsimActiveEsim() {
+        return new UiccSlotInfo[]{
+                createUiccSlotInfo(false, true, -1, false),
+                createUiccSlotInfo(true, false, 1, true)};
+    }
+    //ToDo: add more cases.
+
+    private UiccSlotInfo createUiccSlotInfo(boolean isEuicc, boolean isRemovable,
+            int logicalSlotIdx, boolean isActive) {
+        return new UiccSlotInfo(
+                isEuicc, /* isEuicc */
+                "123", /* cardId */
+                CARD_STATE_INFO_PRESENT, /* cardStateInfo */
+                true, /* isExtendApduSupported */
+                isRemovable, /* isRemovable */
+                Collections.singletonList(
+                        new UiccPortInfo("" /* iccId */, 0 /* portIdx */,
+                                logicalSlotIdx /* logicalSlotIdx */, isActive /* isActive */))
+        );
+    }
+
+    private UiccSlotInfo createUiccSlotInfoForEsimMep(int logicalSlotIdx1, boolean isActiveEsim1,
+            int logicalSlotIdx2, boolean isActiveEsim2) {
+        return new UiccSlotInfo(
+                true, /* isEuicc */
+                "123", /* cardId */
+                CARD_STATE_INFO_PRESENT, /* cardStateInfo */
+                true, /* isExtendApduSupported */
+                false, /* isRemovable */
+                Arrays.asList(
+                        new UiccPortInfo("" /* iccId */, 0 /* portIdx */,
+                                logicalSlotIdx1 /* logicalSlotIdx */, isActiveEsim1 /* isActive */),
+                        new UiccPortInfo("" /* iccId */, 1 /* portIdx */,
+                                logicalSlotIdx2 /* logicalSlotIdx */,
+                                isActiveEsim2 /* isActive */)));
+    }
+}