switch SIM refactor to support MEP

1. Using new telephony API and doing the code refactor
2. To support multi esim profiles case

Bug: 199902896
Test: local build pass.
Change-Id: I8580022793e5c3fc14159f14b406f864353477f8
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 17a1ece..49f2d27 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8122,11 +8122,17 @@
     <!-- Checkbox to always use for calls.  [CHAR LIMIT=40] -->
     <string name="sim_calls_always_use">Always use this for calls</string>
     <!-- Message for selecting sim for data in settings.  [CHAR LIMIT=40] -->
-    <string name="select_sim_for_data">Select a SIM for data</string>
+    <string name="select_sim_for_data">Choose SIM for mobile data</string>
     <!-- Message for selecting sim for SMS in settings.  [CHAR LIMIT=40] -->
     <string name="select_sim_for_sms">Select a SIM for SMS</string>
     <!-- Message for switching data SIM; switching takes a while -->
     <string name="data_switch_started">Switching data SIM, this may take up to a minute\u2026</string>
+    <!-- Title for selecting specific sim for data in settings.  [CHAR LIMIT=40] -->
+    <string name="select_specific_sim_for_data_title">Use <xliff:g id="new_sim" example="carrierA">%1$s</xliff:g> for mobile data?</string>
+    <!-- Message for selecting specific sim for data in settings.  [CHAR LIMIT=NONE] -->
+    <string name="select_specific_sim_for_data_msg">If you switch to <xliff:g id="new_sim" example="carrierA">%1$s</xliff:g>, <xliff:g id="old_sim" example="carrierB">%2$s</xliff:g> will no longer be used for mobile data.</string>
+    <!-- Button on a selecting specific sim dialog to confirm data in settings.  [CHAR LIMIT=40] -->
+    <string name="select_specific_sim_for_data_button">Use <xliff:g id="new_sim" example="carrierA">%1$s</xliff:g></string>
     <!-- Message for selecting sim for call in settings.  [CHAR LIMIT=40] -->
     <string name="select_sim_for_calls">Call with</string>
     <!-- Title for selecting a SIM card.  [CHAR LIMIT=40] -->
@@ -12936,14 +12942,22 @@
     <string name="sim_action_switch_sub_dialog_title">Switch to <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>?</string>
     <!-- Title of confirmation dialog asking the user if they want to switch to the SIM card. [CHAR_LIMIT=NONE] -->
     <string name="sim_action_switch_psim_dialog_title">Switch to using SIM card?</string>
+    <!-- Title of confirmation dialog asking the user if they want to switch subscription. [CHAR_LIMIT=NONE] -->
+    <string name="sim_action_switch_sub_dialog_mep_title">Use <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>?</string>
     <!-- Body text of confirmation dialog for switching subscription that involves switching SIM slots. Indicates that only one SIM can be active at a time. Also that switching will not cancel the user's mobile service plan. [CHAR_LIMIT=NONE] -->
     <string name="sim_action_switch_sub_dialog_text">Only one SIM can be active at a time.\n\nSwitching to <xliff:g id="to_carrier_name" example="Google Fi">%1$s</xliff:g> won\u2019t cancel your <xliff:g id="from_carrier_name" example="Sprint">%2$s</xliff:g> service.</string>
     <!-- Body text of confirmation dialog for switching subscription between two eSIM profiles. Indicates that only one downloaded SIM can be active at a time. Also that switching will not cancel the user's mobile service plan. [CHAR_LIMIT=NONE] -->
     <string name="sim_action_switch_sub_dialog_text_downloaded">Only one downloaded SIM can be active at a time.\n\nSwitching to <xliff:g id="to_carrier_name" example="Google Fi">%1$s</xliff:g> won\u2019t cancel your <xliff:g id="from_carrier_name" example="Sprint">%2$s</xliff:g> service.</string>
     <!-- Body text of confirmation dialog for switching subscription between two eSIM profiles. Indicates that only one SIM can be active at a time. Also that switching will not cancel the user's mobile service plan. [CHAR_LIMIT=NONE] -->
     <string name="sim_action_switch_sub_dialog_text_single_sim">Only one SIM can be active at a time.\n\nSwitching won\u2019t cancel your <xliff:g id="to_carrier_name" example="Google Fi">%1$s</xliff:g> service.</string>
+    <!-- Body text of confirmation dialog for switching subscription between two eSIM profiles. Indicates that only one downloaded SIM can be active at a time. Also that switching will not cancel the user's mobile service plan. [CHAR_LIMIT=NONE] -->
+    <string name="sim_action_switch_sub_dialog_mep_text">You can use 2 SIMs at a time. To use <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>, turn off another SIM.</string>
     <!-- Text of confirm button in the confirmation dialog asking the user if they want to switch subscription. [CHAR_LIMIT=NONE] -->
     <string name="sim_action_switch_sub_dialog_confirm">Switch to <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g></string>
+    <!-- Text of carrier list item in the mep confirmation dialog asking the user if they want to turn off the carrier. [CHAR_LIMIT=NONE] -->
+    <string name="sim_action_switch_sub_dialog_carrier_list_item_for_turning_off">Turn off <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g></string>
+    <!-- Text of carrier list item in the mep confirmation dialog asking the user if they want to turn off the carrier. [CHAR_LIMIT=NONE] -->
+    <string name="sim_action_switch_sub_dialog_info_outline_for_turning_off">Turning off a SIM won\u2019t cancel your service</string>
     <!-- Status message indicating the device is in the process of disconnecting from one mobile network and immediately connecting to another. [CHAR_LIMIT=NONE] -->
     <string name="sim_action_enabling_sim_without_carrier_name">Connecting to network&#8230;</string>
     <!-- Text of progress dialog indicating the subscription switch is in progress. [CHAR_LIMIT=NONE] -->
diff --git a/src/com/android/settings/network/SwitchSlotSidecar.java b/src/com/android/settings/network/SwitchSlotSidecar.java
index cffb23f..abf8842 100644
--- a/src/com/android/settings/network/SwitchSlotSidecar.java
+++ b/src/com/android/settings/network/SwitchSlotSidecar.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.app.FragmentManager;
 import android.os.Bundle;
+import android.telephony.SubscriptionInfo;
 import android.util.Log;
 
 import com.android.settings.AsyncTaskSidecar;
@@ -41,11 +42,14 @@
     })
     private @interface Command {
         int SWITCH_TO_REMOVABLE_SIM = 0;
+        int SWITCH_TO_EUICC_SIM = 1;
     }
 
     static class Param {
         @Command int command;
         int slotId;
+        int port;
+        SubscriptionInfo removedSubInfo;
     }
 
     static class Result {
@@ -65,13 +69,24 @@
     }
 
     /** Starts switching to the removable slot. */
-    public void runSwitchToRemovableSlot(int id) {
+    public void runSwitchToRemovableSlot(int id, SubscriptionInfo removedSubInfo) {
         Param param = new Param();
         param.command = Command.SWITCH_TO_REMOVABLE_SIM;
         param.slotId = id;
+        param.removedSubInfo = removedSubInfo;
+        param.port = 0;
         super.run(param);
     }
 
+    /** Starts switching to the removable slot. */
+    public void runSwitchToEuiccSlot(int id, int port, SubscriptionInfo removedSubInfo) {
+        Param param = new Param();
+        param.command = Command.SWITCH_TO_EUICC_SIM;
+        param.slotId = id;
+        param.removedSubInfo = removedSubInfo;
+        param.port = port;
+        super.run(param);
+    }
     /**
      * Returns the exception thrown during the execution of a command. Will be null in any state
      * other than {@link State#SUCCESS}, and may be null in that state if there was not an error.
@@ -91,7 +106,14 @@
         try {
             switch (param.command) {
                 case Command.SWITCH_TO_REMOVABLE_SIM:
-                    UiccSlotUtil.switchToRemovableSlot(param.slotId, getContext());
+                    Log.i(TAG, "Start to switch to removable slot.");
+                    UiccSlotUtil.switchToRemovableSlot(getContext(), param.slotId,
+                            param.removedSubInfo);
+                    break;
+                case Command.SWITCH_TO_EUICC_SIM:
+                    Log.i(TAG, "Start to switch to euicc slot.");
+                    UiccSlotUtil.switchToEuiccSlot(getContext(), param.slotId, param.port,
+                            param.removedSubInfo);
                     break;
                 default:
                     Log.e(TAG, "Wrong command.");
diff --git a/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java b/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java
index 6e6142f..d88a189 100644
--- a/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java
+++ b/src/com/android/settings/network/SwitchToEuiccSubscriptionSidecar.java
@@ -18,17 +18,30 @@
 
 import android.app.FragmentManager;
 import android.app.PendingIntent;
+import android.content.Intent;
+import android.telephony.SubscriptionInfo;
+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.List;
+import java.util.stream.Collectors;
+
 /** A headless fragment encapsulating long-running eSIM enabling/disabling operations. */
 public class SwitchToEuiccSubscriptionSidecar extends EuiccOperationSidecar {
     private static final String TAG = "SwitchToEuiccSubscriptionSidecar";
     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;
+    private int mPort;
 
     /** Returns a SwitchToEuiccSubscriptionSidecar sidecar instance. */
     public static SwitchToEuiccSubscriptionSidecar get(FragmentManager fm) {
@@ -46,10 +59,119 @@
         return mCallbackIntent;
     }
 
+    @Override
+    public void onStateChange(SidecarFragment fragment) {
+        if (fragment == mSwitchSlotSidecar) {
+            onSwitchSlotSidecarStateChange();
+        } else {
+            Log.wtf(TAG, "Received state change from a sidecar not expected.");
+        }
+    }
+
     /** 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 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.
+     */
+    public void run(int subscriptionId, int port, SubscriptionInfo removedSubInfo) {
+        setState(State.RUNNING, Substate.UNUSED);
+        mCallbackIntent = createCallbackIntent();
+        mSubId = subscriptionId;
+        // 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;
+        Log.i(TAG, "The SubId is " + mSubId + "The port is " + mPort);
+
+        mSwitchSlotSidecar.runSwitchToEuiccSlot(getTargetSlot(), mPort, removedSubInfo);
+    }
+
+    private int getTargetPortId(SubscriptionInfo removedSubInfo) {
+        if (!mTelephonyManager.isMultiSimEnabled() || !isMultipleEnabledProfilesSupported()) {
+            // In the 'SS mode' or 'DSDS+no MEP', the port is 0.
+            return 0;
+        }
+
+        // In the 'DSDS+MEP', if the removedSubInfo is esim, then the port is
+        // removedSubInfo's port.
+        if (removedSubInfo != null && removedSubInfo.isEmbedded()) {
+            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;
+        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) {
+                port++;
+            }
+        }
+        return port;
+    }
+
+    private int getTargetSlot() {
+        return ESIM_SLOT_ID;
+    }
+
+    private void onSwitchSlotSidecarStateChange() {
+        switch (mSwitchSlotSidecar.getState()) {
+            case State.SUCCESS:
+                mSwitchSlotSidecar.reset();
+                Log.i(TAG,
+                        "Successfully SimSlotMapping. Start to enable/disable esim");
+                switchToSubscription();
+                break;
+            case State.ERROR:
+                mSwitchSlotSidecar.reset();
+                Log.i(TAG, "Failed to set SimSlotMapping");
+                setState(State.ERROR, Substate.UNUSED);
+                break;
+        }
+    }
+
+    private boolean isMultipleEnabledProfilesSupported() {
+        List<UiccCardInfo> cardInfos = mTelephonyManager.getUiccCardsInfo();
+        if (cardInfos == null) {
+            Log.w(TAG, "UICC cards info list is empty.");
+            return false;
+        }
+        return cardInfos.stream().anyMatch(
+                cardInfo -> cardInfo.isMultipleEnabledProfilesSupported());
+    }
+
+    private void switchToSubscription() {
+        // The SimSlotMapping is ready, then to execute activate/inactivate esim.
+        EuiccManager.ResultListener callback = new EuiccManager.ResultListener() {
+            @Override
+            public void onComplete(int resultCode, Intent resultIntent) {
+                Log.i(TAG, String.format("Result code : %d;", resultCode));
+                if (resultCode == EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK) {
+                    setState(State.SUCCESS, Substate.UNUSED);
+                } else {
+                    setState(State.ERROR, resultCode);
+                }
+            }
+        };
+        mEuiccManager.switchToSubscription(mSubId, mPort, getContext().getMainExecutor(),
+                callback);
+    }
 }
diff --git a/src/com/android/settings/network/SwitchToRemovableSlotSidecar.java b/src/com/android/settings/network/SwitchToRemovableSlotSidecar.java
index 132a2fd..2c184c6 100644
--- a/src/com/android/settings/network/SwitchToRemovableSlotSidecar.java
+++ b/src/com/android/settings/network/SwitchToRemovableSlotSidecar.java
@@ -38,8 +38,8 @@
 
     // Stateless members.
     private SwitchToEuiccSubscriptionSidecar mSwitchToSubscriptionSidecar;
-    private SwitchSlotSidecar mSwitchSlotSidecar;
     private int mPhysicalSlotId;
+    private SubscriptionInfo mRemovedSubInfo;
 
     /** Returns a SwitchToRemovableSlotSidecar sidecar instance. */
     public static SwitchToRemovableSlotSidecar get(FragmentManager fm) {
@@ -51,20 +51,17 @@
         super.onCreate(savedInstanceState);
         mSwitchToSubscriptionSidecar =
                 SwitchToEuiccSubscriptionSidecar.get(getChildFragmentManager());
-        mSwitchSlotSidecar = SwitchSlotSidecar.get(getChildFragmentManager());
     }
 
     @Override
     public void onResume() {
         super.onResume();
         mSwitchToSubscriptionSidecar.addListener(this);
-        mSwitchSlotSidecar.addListener(this);
     }
 
     @Override
     public void onPause() {
         mSwitchToSubscriptionSidecar.removeListener(this);
-        mSwitchSlotSidecar.removeListener(this);
         super.onPause();
     }
 
@@ -90,29 +87,46 @@
      *
      * @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);
+            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);
+            mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId, null);
         }
     }
 
+    /**
+     * Starts switching to the removable slot.
+     *
+     * @param physicalSlotId removable physical SIM slot 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 removable physical SIM slot and portId 0.
+     */
+    public void run(int physicalSlotId, SubscriptionInfo removedSubInfo) {
+        mPhysicalSlotId = physicalSlotId;
+        mRemovedSubInfo = removedSubInfo;
+
+        Log.i(TAG, "Start to switch to removable slot.");
+        mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId, mRemovedSubInfo);
+    }
+
     private void onSwitchToSubscriptionSidecarStateChange() {
         switch (mSwitchToSubscriptionSidecar.getState()) {
             case State.SUCCESS:
                 mSwitchToSubscriptionSidecar.reset();
-                Log.i(
-                        TAG,
+                Log.i(TAG,
                         "Successfully disabled eSIM profile. Start to switch to Removable slot.");
-                mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId);
+                mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId, mRemovedSubInfo);
                 break;
             case State.ERROR:
                 mSwitchToSubscriptionSidecar.reset();
diff --git a/src/com/android/settings/network/UiccSlotUtil.java b/src/com/android/settings/network/UiccSlotUtil.java
index ccf3f91..8938cdb 100644
--- a/src/com/android/settings/network/UiccSlotUtil.java
+++ b/src/com/android/settings/network/UiccSlotUtil.java
@@ -19,8 +19,10 @@
 import android.annotation.IntDef;
 import android.content.Context;
 import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
 import android.telephony.TelephonyManager;
 import android.telephony.UiccSlotInfo;
+import android.telephony.UiccSlotMapping;
 import android.util.Log;
 
 import com.android.settingslib.utils.ThreadUtils;
@@ -29,17 +31,21 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
+// ToDo: to do the refactor for renaming
 public class UiccSlotUtil {
 
     private static final String TAG = "UiccSlotUtil";
 
     private static final long DEFAULT_WAIT_AFTER_SWITCH_TIMEOUT_MILLIS = 25 * 1000L;
-    ;
 
     public static final int INVALID_PHYSICAL_SLOT_ID = -1;
+    public static final int INVALID_PORT_ID = -1;
 
     /**
      * Mode for switching to eSIM slot which decides whether there is cleanup process, e.g.
@@ -47,9 +53,9 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
-        SwitchingEsimMode.NO_CLEANUP,
-        SwitchingEsimMode.ASYNC_CLEANUP,
-        SwitchingEsimMode.SYNC_CLEANUP
+            SwitchingEsimMode.NO_CLEANUP,
+            SwitchingEsimMode.ASYNC_CLEANUP,
+            SwitchingEsimMode.SYNC_CLEANUP
     })
     public @interface SwitchingEsimMode {
         /** No cleanup process after switching to eSIM slot */
@@ -76,44 +82,108 @@
      * Switches to the removable slot. It waits for SIM_STATE_LOADED after switch. If slotId is
      * INVALID_PHYSICAL_SLOT_ID, the method will use the first detected inactive removable slot.
      *
-     * @param slotId the physical removable slot id.
+     * @param slotId  the physical removable slot id.
      * @param context the application context.
      * @throws UiccSlotsException if there is an error.
      */
+    //ToDo: delete this api and refactor the related code.
     public static synchronized void switchToRemovableSlot(int slotId, Context context)
             throws UiccSlotsException {
+        switchToRemovableSlot(context, slotId, null);
+    }
+
+    /**
+     * Switches to the removable slot. It waits for SIM_STATE_LOADED after switch. If slotId is
+     * INVALID_PHYSICAL_SLOT_ID, the method will use the first detected inactive removable slot.
+     *
+     * @param slotId  the physical removable slot id.
+     * @param context the application context.
+     * @param removedSubInfo In the DSDS+MEP mode, 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.
+     * @throws UiccSlotsException if there is an error.
+     */
+    public static synchronized void switchToRemovableSlot(Context context, int slotId,
+            SubscriptionInfo removedSubInfo) throws UiccSlotsException {
         if (ThreadUtils.isMainThread()) {
             throw new IllegalThreadStateException(
                     "Do not call switchToRemovableSlot on the main thread.");
         }
         TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
-        if (telMgr.isMultiSimEnabled()) {
-            // If this device supports multiple active slots, don't mess with TelephonyManager.
-            Log.i(TAG, "Multiple active slots supported. Not calling switchSlots.");
-            return;
-        }
-        UiccSlotInfo[] slots = telMgr.getUiccSlotsInfo();
-        if (slotId == INVALID_PHYSICAL_SLOT_ID) {
-            for (int i = 0; i < slots.length; i++) {
-                if (slots[i].isRemovable()
-                        && !slots[i].getPorts().stream().findFirst().get().isActive()
-                        && slots[i].getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_ERROR
-                        && slots[i].getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_RESTRICTED) {
-                    performSwitchToRemovableSlot(i, context);
-                    return;
-                }
-            }
-        } else {
-            if (slotId >= slots.length || !slots[slotId].isRemovable()) {
-                throw new UiccSlotsException("The given slotId is not a removable slot: " + slotId);
-            }
-            if (!slots[slotId].getPorts().stream().findFirst().get().isActive()) {
-                performSwitchToRemovableSlot(slotId, context);
-            }
-        }
+        int inactiveRemovableSlot = getInactiveRemovableSlot(telMgr.getUiccSlotsInfo(), slotId);
+        performSwitchToSlot(telMgr,
+                prepareUiccSlotMappingsForRemovableSlot(telMgr.getSimSlotMapping(),
+                        inactiveRemovableSlot, removedSubInfo, telMgr.isMultiSimEnabled()),
+                context);
     }
 
-    private static void performSwitchToRemovableSlot(int slotId, Context context)
+    /**
+     * 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 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.
+     *                       If the removedSubInfo is null, then it uses the default value.
+     *                       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,
+            SubscriptionInfo removedSubInfo) throws UiccSlotsException {
+        if (ThreadUtils.isMainThread()) {
+            throw new IllegalThreadStateException(
+                    "Do not call switchToRemovableSlot on the main thread.");
+        }
+        TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
+        Collection<UiccSlotMapping> uiccSlotMappings = telMgr.getSimSlotMapping();
+        Log.i(TAG, "The SimSlotMapping: " + uiccSlotMappings);
+
+        if (isTargetSlotActive(uiccSlotMappings, slotId, port)) {
+            Log.i(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());
+        }
+
+        Log.i(TAG, "The SimSlotMapping: " + newUiccSlotMappings);
+        performSwitchToSlot(telMgr, newUiccSlotMappings, context);
+    }
+
+    private static boolean isTargetSlotActive(Collection<UiccSlotMapping> uiccSlotMappings,
+            int slotId, int port) {
+        return uiccSlotMappings.stream()
+                .anyMatch(
+                        uiccSlotMapping -> uiccSlotMapping.getPhysicalSlotIndex() == slotId
+                                && uiccSlotMapping.getPortIndex() == port);
+    }
+
+    private static void performSwitchToSlot(TelephonyManager telMgr,
+            Collection<UiccSlotMapping> uiccSlotMappings, Context context)
             throws UiccSlotsException {
         CarrierConfigChangedReceiver receiver = null;
         long waitingTimeMillis =
@@ -125,7 +195,7 @@
             CountDownLatch latch = new CountDownLatch(1);
             receiver = new CarrierConfigChangedReceiver(latch);
             receiver.registerOn(context);
-            switchSlots(context, slotId);
+            telMgr.setSimSlotMapping(uiccSlotMappings);
             latch.await(waitingTimeMillis, TimeUnit.MILLISECONDS);
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
@@ -138,22 +208,80 @@
     }
 
     /**
-     * Changes the logical slot to physical slot mapping. OEM should override this to provide
-     * device-specific implementation if the device supports switching slots.
-     *
-     * @param context the application context.
-     * @param physicalSlots List of physical slot ids in the order of logical slots.
+     * @param slots  The UiccSlotInfo list.
+     * @param slotId The physical removable slot id.
+     * @return The inactive physical removable slot id. If the physical removable slot id is
+     * active, then return -1.
+     * @throws UiccSlotsException if there is an error.
      */
-    private static void switchSlots(Context context, int... physicalSlots)
+    private static int getInactiveRemovableSlot(UiccSlotInfo[] slots, int slotId)
             throws UiccSlotsException {
-        TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
-        if (telMgr.isMultiSimEnabled()) {
-            // If this device supports multiple active slots, don't mess with TelephonyManager.
-            Log.i(TAG, "Multiple active slots supported. Not calling switchSlots.");
-            return;
+        if (slots == null) {
+            throw new UiccSlotsException("UiccSlotInfo is null");
         }
-        if (!telMgr.switchSlots(physicalSlots)) {
-            throw new UiccSlotsException("Failed to switch slots");
+        if (slotId == INVALID_PHYSICAL_SLOT_ID) {
+            for (int i = 0; i < slots.length; i++) {
+                if (slots[i].isRemovable()
+                        && !slots[i].getPorts().stream().findFirst().get().isActive()
+                        && slots[i].getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_ERROR
+                        && slots[i].getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_RESTRICTED) {
+                    return i;
+                }
+            }
+        } else {
+            if (slotId >= slots.length || !slots[slotId].isRemovable()) {
+                throw new UiccSlotsException("The given slotId is not a removable slot: " + slotId);
+            }
+            if (!slots[slotId].getPorts().stream().findFirst().get().isActive()) {
+                return slotId;
+            }
         }
+        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.
+            return uiccSlotMappings;
+        }
+
+        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");
+        }
+
+        Log.i(TAG, "The SimSlotMapping: " + newUiccSlotMappings);
+        return newUiccSlotMappings;
     }
 }
diff --git a/src/com/android/settings/network/telephony/ConfirmDialogFragment.java b/src/com/android/settings/network/telephony/ConfirmDialogFragment.java
index 1ba99c5..04382da 100644
--- a/src/com/android/settings/network/telephony/ConfirmDialogFragment.java
+++ b/src/com/android/settings/network/telephony/ConfirmDialogFragment.java
@@ -38,11 +38,15 @@
      */
     public interface OnConfirmListener {
         /**
-         * @param tag The tag in the caller.
-         * @param confirmed True if the user has clicked the positive button. False if the user has
-         *     clicked the negative button or cancel the dialog.
+         * @param tag          The tag in the caller.
+         * @param confirmed    True if the user has clicked the positive button. False if the
+         *                     user has
+         *                     clicked the negative button or cancel the dialog.
+         * @param itemPosition It is the position of item, if user selects one of the list item.
+         *                     If the user select "cancel" or the dialog does not have list, then
+         *                     the value is -1.
          */
-        void onConfirm(int tag, boolean confirmed);
+        void onConfirm(int tag, boolean confirmed, int itemPosition);
     }
 
     /** Displays a confirmation dialog which has confirm and cancel buttons. */
@@ -89,19 +93,21 @@
 
     @Override
     public void onClick(DialogInterface dialog, int which) {
-        informCaller(which == DialogInterface.BUTTON_POSITIVE);
+        Log.i(TAG, "dialog onClick =" + which);
+
+        informCaller(which == DialogInterface.BUTTON_POSITIVE, -1);
     }
 
     @Override
     public void onCancel(DialogInterface dialog) {
-        informCaller(false);
+        informCaller(false, -1);
     }
 
-    private void informCaller(boolean confirmed) {
+    private void informCaller(boolean confirmed, int itemPosition) {
         OnConfirmListener listener = getListener(OnConfirmListener.class);
         if (listener == null) {
             return;
         }
-        listener.onConfirm(getTagInCaller(), confirmed);
+        listener.onConfirm(getTagInCaller(), confirmed, itemPosition);
     }
 }
diff --git a/src/com/android/settings/network/telephony/DeleteEuiccSubscriptionDialogActivity.java b/src/com/android/settings/network/telephony/DeleteEuiccSubscriptionDialogActivity.java
index f429f8b..8247f63 100644
--- a/src/com/android/settings/network/telephony/DeleteEuiccSubscriptionDialogActivity.java
+++ b/src/com/android/settings/network/telephony/DeleteEuiccSubscriptionDialogActivity.java
@@ -96,7 +96,7 @@
     }
 
     @Override
-    public void onConfirm(int tag, boolean confirmed) {
+    public void onConfirm(int tag, boolean confirmed, int itemPosition) {
         if (!confirmed) {
             finish();
             return;
diff --git a/src/com/android/settings/network/telephony/EuiccOperationSidecar.java b/src/com/android/settings/network/telephony/EuiccOperationSidecar.java
index 05c866e..d1d362b 100644
--- a/src/com/android/settings/network/telephony/EuiccOperationSidecar.java
+++ b/src/com/android/settings/network/telephony/EuiccOperationSidecar.java
@@ -24,10 +24,12 @@
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.os.SystemClock;
+import android.telephony.TelephonyManager;
 import android.telephony.euicc.EuiccManager;
 import android.util.Log;
 
 import com.android.settings.SidecarFragment;
+import com.android.settings.network.SwitchSlotSidecar;
 
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -37,7 +39,8 @@
  * should implement its own get() function to return an instance of that class, and implement the
  * functional class like run() to actually trigger the function in EuiccManager.
  */
-public abstract class EuiccOperationSidecar extends SidecarFragment {
+public abstract class EuiccOperationSidecar extends SidecarFragment
+        implements SidecarFragment.Listener{
     private static final String TAG = "EuiccOperationSidecar";
     private static final int REQUEST_CODE = 0;
     private static final String EXTRA_OP_ID = "op_id";
@@ -45,6 +48,9 @@
             new AtomicInteger((int) SystemClock.elapsedRealtime());
 
     protected EuiccManager mEuiccManager;
+    protected TelephonyManager mTelephonyManager;
+    protected SwitchSlotSidecar mSwitchSlotSidecar;
+
 
     private int mResultCode;
     private int mDetailedCode;
@@ -107,6 +113,8 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mEuiccManager = getContext().getSystemService(EuiccManager.class);
+        mTelephonyManager = getContext().getSystemService(TelephonyManager.class);
+        mSwitchSlotSidecar = SwitchSlotSidecar.get(getChildFragmentManager());
 
         getContext()
                 .getApplicationContext()
@@ -119,11 +127,41 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        mSwitchSlotSidecar.addListener(this);
+    }
+
+    @Override
+    public void onPause() {
+        mSwitchSlotSidecar.removeListener(this);
+        super.onPause();
+    }
+
+    @Override
     public void onDestroy() {
         getContext().getApplicationContext().unregisterReceiver(mReceiver);
         super.onDestroy();
     }
 
+    @Override
+    public void onStateChange(SidecarFragment fragment) {
+        if (fragment == mSwitchSlotSidecar) {
+            switch (mSwitchSlotSidecar.getState()) {
+                case State.SUCCESS:
+                    mSwitchSlotSidecar.reset();
+                    Log.i(TAG, "mSwitchSlotSidecar SUCCESS");
+                    break;
+                case State.ERROR:
+                    mSwitchSlotSidecar.reset();
+                    Log.i(TAG, "mSwitchSlotSidecar ERROR");
+                    break;
+            }
+        } else {
+            Log.wtf(TAG, "Received state change from a sidecar not expected.");
+        }
+    }
+
     public int getResultCode() {
         return mResultCode;
     }
diff --git a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
index 2f6e8a1..f8dee8b 100644
--- a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
+++ b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
@@ -23,6 +23,7 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.UiccCardInfo;
 import android.telephony.UiccSlotInfo;
 import android.text.TextUtils;
 import android.util.Log;
@@ -40,7 +41,9 @@
 
 import com.google.common.collect.ImmutableList;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /** This dialog activity handles both eSIM and pSIM subscriptions enabling and disabling. */
 public class ToggleSubscriptionDialogActivity extends SubscriptionActionDialogActivity
@@ -55,6 +58,8 @@
     private static final int DIALOG_TAG_ENABLE_SIM_CONFIRMATION = 2;
     private static final int DIALOG_TAG_ENABLE_DSDS_CONFIRMATION = 3;
     private static final int DIALOG_TAG_ENABLE_DSDS_REBOOT_CONFIRMATION = 4;
+    private static final int DIALOG_TAG_ENABLE_SIM_CONFIRMATION_MEP = 5;
+
     // Number of SIMs for DSDS
     private static final int NUM_OF_SIMS_FOR_DSDS = 2;
     // Support RTL mode
@@ -85,11 +90,11 @@
     private boolean mIsEsimOperation;
     private TelephonyManager mTelMgr;
     private boolean isRtlMode;
+    private List<SubscriptionInfo> mActiveSubInfos;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
         Intent intent = getIntent();
         int subId = intent.getIntExtra(ARG_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         mTelMgr = getSystemService(TelephonyManager.class);
@@ -107,6 +112,7 @@
             return;
         }
 
+        mActiveSubInfos = SubscriptionUtil.getActiveSubscriptions(mSubscriptionManager);
         mSubInfo = SubscriptionUtil.getSubById(mSubscriptionManager, subId);
         mIsEsimOperation = mSubInfo != null && mSubInfo.isEmbedded();
         mSwitchToEuiccSubscriptionSidecar =
@@ -116,6 +122,7 @@
         mEnable = intent.getBooleanExtra(ARG_enable, true);
         isRtlMode = getResources().getConfiguration().getLayoutDirection()
                 == View.LAYOUT_DIRECTION_RTL;
+        Log.i(TAG, "isMultipleEnabledProfilesSupported():" + isMultipleEnabledProfilesSupported());
 
         if (savedInstanceState == null) {
             if (mEnable) {
@@ -154,7 +161,7 @@
     }
 
     @Override
-    public void onConfirm(int tag, boolean confirmed) {
+    public void onConfirm(int tag, boolean confirmed, int itemPosition) {
         if (!confirmed
                 && tag != DIALOG_TAG_ENABLE_DSDS_CONFIRMATION
                 && tag != DIALOG_TAG_ENABLE_DSDS_REBOOT_CONFIRMATION) {
@@ -162,14 +169,16 @@
             return;
         }
 
+        SubscriptionInfo removedSubInfo = null;
         switch (tag) {
             case DIALOG_TAG_DISABLE_SIM_CONFIRMATION:
                 if (mIsEsimOperation) {
                     Log.i(TAG, "Disabling the eSIM profile.");
                     showProgressDialog(
                             getString(R.string.privileged_action_disable_sub_dialog_progress));
+                    int port = mSubInfo != null ? mSubInfo.getPortIndex() : 0;
                     mSwitchToEuiccSubscriptionSidecar.run(
-                            SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+                            SubscriptionManager.INVALID_SUBSCRIPTION_ID, port, null);
                     return;
                 }
                 Log.i(TAG, "Disabling the pSIM profile.");
@@ -201,6 +210,11 @@
                 SimActivationNotifier.setShowSimSettingsNotification(this, true);
                 mTelMgr.switchMultiSimConfig(NUM_OF_SIMS_FOR_DSDS);
                 break;
+            case DIALOG_TAG_ENABLE_SIM_CONFIRMATION_MEP:
+                if (itemPosition != -1) {
+                    removedSubInfo = (mActiveSubInfos != null) ? mActiveSubInfos.get(itemPosition)
+                            : null;
+                }
             case DIALOG_TAG_ENABLE_SIM_CONFIRMATION:
                 Log.i(TAG, "User confirmed to enable the subscription.");
                 if (mIsEsimOperation) {
@@ -209,12 +223,15 @@
                                     R.string.sim_action_switch_sub_dialog_progress,
                                     SubscriptionUtil.getUniqueSubscriptionDisplayName(
                                             mSubInfo, this)));
-                    mSwitchToEuiccSubscriptionSidecar.run(mSubInfo.getSubscriptionId());
+                    mSwitchToEuiccSubscriptionSidecar.run(mSubInfo.getSubscriptionId(),
+                            UiccSlotUtil.INVALID_PORT_ID,
+                            removedSubInfo);
                     return;
                 }
                 showProgressDialog(
                         getString(R.string.sim_action_enabling_sim_without_carrier_name));
-                mSwitchToRemovableSlotSidecar.run(UiccSlotUtil.INVALID_PHYSICAL_SLOT_ID);
+                mSwitchToRemovableSlotSidecar.run(UiccSlotUtil.INVALID_PHYSICAL_SLOT_ID,
+                        removedSubInfo);
                 break;
             default:
                 Log.e(TAG, "Unrecognized confirmation dialog tag: " + tag);
@@ -225,8 +242,7 @@
     private void handleSwitchToEuiccSubscriptionSidecarStateChange() {
         switch (mSwitchToEuiccSubscriptionSidecar.getState()) {
             case SidecarFragment.State.SUCCESS:
-                Log.i(
-                        TAG,
+                Log.i(TAG,
                         String.format(
                                 "Successfully %s the eSIM profile.",
                                 mEnable ? "enable" : "disable"));
@@ -235,8 +251,7 @@
                 finish();
                 break;
             case SidecarFragment.State.ERROR:
-                Log.i(
-                        TAG,
+                Log.i(TAG,
                         String.format(
                                 "Failed to %s the eSIM profile.", mEnable ? "enable" : "disable"));
                 mSwitchToEuiccSubscriptionSidecar.reset();
@@ -290,7 +305,8 @@
         if (mIsEsimOperation) {
             Log.i(TAG, "DSDS enabled, start to enable profile: " + mSubInfo.getSubscriptionId());
             // For eSIM operations, we simply switch to the selected eSIM profile.
-            mSwitchToEuiccSubscriptionSidecar.run(mSubInfo.getSubscriptionId());
+            mSwitchToEuiccSubscriptionSidecar.run(mSubInfo.getSubscriptionId(),
+                    UiccSlotUtil.INVALID_PORT_ID, null);
             return;
         }
 
@@ -305,10 +321,8 @@
             mSubscriptionManager.setUiccApplicationsEnabled(mSubInfo.getSubscriptionId(), mEnable);
             finish();
         } else {
-            Log.i(
-                    TAG,
-                    "The device does not support toggling pSIM. It is enough to just "
-                            + "enable the removable slot.");
+            Log.i(TAG, "The device does not support toggling pSIM. It is enough to just "
+                    + "enable the removable slot.");
         }
     }
 
@@ -319,7 +333,10 @@
             showEnableDsdsConfirmDialog();
             return;
         }
-        if (!mIsEsimOperation && mTelMgr.isMultiSimEnabled()) {
+        if (!mIsEsimOperation && mTelMgr.isMultiSimEnabled()
+                && isRemovableSimEnabled()) {
+            // This case is for switching on psim when device is not multiple enable profile
+            // supported.
             Log.i(TAG, "Toggle on pSIM, no dialog displayed.");
             handleTogglePsimAction();
             finish();
@@ -372,27 +389,55 @@
     }
 
     private void showEnableSimConfirmDialog() {
-        List<SubscriptionInfo> activeSubs =
-                SubscriptionUtil.getActiveSubscriptions(mSubscriptionManager);
-        SubscriptionInfo activeSub = activeSubs.isEmpty() ? null : activeSubs.get(0);
-        if (activeSub == null) {
+        if (mActiveSubInfos == null || mActiveSubInfos.isEmpty()) {
             Log.i(TAG, "No active subscriptions available.");
             showNonSwitchSimConfirmDialog();
             return;
         }
-        Log.i(TAG, "Found active subscription.");
-        boolean isBetweenEsim = mIsEsimOperation && activeSub.isEmbedded();
-        if (mTelMgr.isMultiSimEnabled() && !isBetweenEsim) {
+        Log.i(TAG, "mActiveSubInfos:" + mActiveSubInfos);
+
+        boolean isSwitchingBetweenEsims = mIsEsimOperation
+                && mActiveSubInfos.stream().anyMatch(activeSubInfo -> activeSubInfo.isEmbedded());
+        boolean isMultiSimEnabled = mTelMgr.isMultiSimEnabled();
+        if (isMultiSimEnabled
+                && !isMultipleEnabledProfilesSupported()
+                && !isSwitchingBetweenEsims) {
+            // Showing the "no switch dialog" for below cases.
+            // DSDS mode + no MEP +
+            //     (there is the active psim -> esim switch on => active (psim + esim))
             showNonSwitchSimConfirmDialog();
             return;
         }
 
+        if (isMultiSimEnabled && isMultipleEnabledProfilesSupported()) {
+            if (mActiveSubInfos.size() < NUM_OF_SIMS_FOR_DSDS) {
+                // The sim can add into device directly, so showing the "no switch dialog".
+                // DSDS + MEP + (active sim < NUM_OF_SIMS_FOR_DSDS)
+                showNonSwitchSimConfirmDialog();
+            } else {
+                // The all of slots have sim, it needs to show the "MEP switch dialog".
+                // DSDS + MEP + two active sims
+                showMepSwitchSimConfirmDialog();
+            }
+            return;
+        }
+
+        // Showing the "switch dialog" for below cases.
+        // case1: SS mode + psim switch on from esim.
+        // case2: SS mode + esim switch from psim.
+        // case3: DSDS mode + No MEP + esim switch on from another esim.
+        SubscriptionInfo activeSub =
+                (isMultiSimEnabled && isSwitchingBetweenEsims)
+                        ? mActiveSubInfos.stream()
+                                .filter(activeSubInfo -> activeSubInfo.isEmbedded())
+                                .findFirst().get()
+                        : mActiveSubInfos.get(0);
         ConfirmDialogFragment.show(
                 this,
                 ConfirmDialogFragment.OnConfirmListener.class,
                 DIALOG_TAG_ENABLE_SIM_CONFIRMATION,
                 getSwitchSubscriptionTitle(),
-                getSwitchDialogBodyMsg(activeSub, isBetweenEsim),
+                getSwitchDialogBodyMsg(activeSub, isSwitchingBetweenEsims),
                 getSwitchDialogPosBtnText(),
                 getString(R.string.sim_action_cancel));
     }
@@ -408,6 +453,10 @@
                 getString(R.string.sim_action_cancel));
     }
 
+    private void showMepSwitchSimConfirmDialog() {
+        Log.i(TAG, "showMepSwitchSimConfirmDialog");
+    }
+
     private String getSwitchDialogPosBtnText() {
         return mIsEsimOperation
                 ? getString(
@@ -468,6 +517,20 @@
         return switchDialogMsg.toString();
     }
 
+    private ArrayList<String> getSwitchDialogBodyList() {
+        ArrayList<String> list = new ArrayList<String>(mActiveSubInfos.stream()
+                .map(subInfo -> {
+                    CharSequence subInfoName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
+                            subInfo, this);
+                    return getString(
+                            R.string.sim_action_switch_sub_dialog_carrier_list_item_for_turning_off,
+                            subInfoName);
+                })
+                .collect(Collectors.toList()));
+        list.add(getString(R.string.sim_action_cancel));
+        return list;
+    }
+
     private boolean isDsdsConditionSatisfied() {
         if (mTelMgr.isMultiSimEnabled()) {
             Log.i(TAG, "DSDS is already enabled. Condition not satisfied.");
@@ -477,17 +540,7 @@
             Log.i(TAG, "Hardware does not support DSDS.");
             return false;
         }
-        ImmutableList<UiccSlotInfo> slotInfos = UiccSlotUtil.getSlotInfos(mTelMgr);
-        boolean isRemovableSimEnabled =
-                slotInfos.stream()
-                        .anyMatch(
-                                slot ->
-                                        slot != null
-                                                && slot.isRemovable()
-                                                && slot.getPorts().stream().anyMatch(
-                                                        port -> port.isActive())
-                                                && slot.getCardStateInfo()
-                                                        == UiccSlotInfo.CARD_STATE_INFO_PRESENT);
+        boolean isRemovableSimEnabled = isRemovableSimEnabled();
         if (mIsEsimOperation && isRemovableSimEnabled) {
             Log.i(TAG, "eSIM operation and removable SIM is enabled. DSDS condition satisfied.");
             return true;
@@ -496,13 +549,36 @@
                 SubscriptionUtil.getActiveSubscriptions(mSubscriptionManager).stream()
                         .anyMatch(SubscriptionInfo::isEmbedded);
         if (!mIsEsimOperation && isEsimProfileEnabled) {
-            Log.i(
-                    TAG,
-                    "Removable SIM operation and eSIM profile is enabled. DSDS condition"
-                            + " satisfied.");
+            Log.i(TAG, "Removable SIM operation and eSIM profile is enabled. DSDS condition"
+                    + " satisfied.");
             return true;
         }
         Log.i(TAG, "DSDS condition not satisfied.");
         return false;
     }
+
+    private boolean isRemovableSimEnabled() {
+        ImmutableList<UiccSlotInfo> slotInfos = UiccSlotUtil.getSlotInfos(mTelMgr);
+        boolean isRemovableSimEnabled =
+                slotInfos.stream()
+                        .anyMatch(
+                                slot -> slot != null
+                                        && slot.isRemovable()
+                                        && slot.getPorts().stream().anyMatch(
+                                                port -> port.isActive())
+                                        && slot.getCardStateInfo()
+                                                == UiccSlotInfo.CARD_STATE_INFO_PRESENT);
+        Log.i(TAG, "isRemovableSimEnabled: " + isRemovableSimEnabled);
+        return isRemovableSimEnabled;
+    }
+
+    private boolean isMultipleEnabledProfilesSupported() {
+        List<UiccCardInfo> cardInfos = mTelMgr.getUiccCardsInfo();
+        if (cardInfos == null) {
+            Log.w(TAG, "UICC cards info list is empty.");
+            return false;
+        }
+        return cardInfos.stream().anyMatch(
+                cardInfo -> cardInfo.isMultipleEnabledProfilesSupported());
+    }
 }
diff --git a/src/com/android/settings/sim/DsdsDialogActivity.java b/src/com/android/settings/sim/DsdsDialogActivity.java
index 62a6995..7d9a43b 100644
--- a/src/com/android/settings/sim/DsdsDialogActivity.java
+++ b/src/com/android/settings/sim/DsdsDialogActivity.java
@@ -85,7 +85,7 @@
     }
 
     @Override
-    public void onConfirm(int tag, boolean confirmed) {
+    public void onConfirm(int tag, boolean confirmed, int itemPosition) {
         if (!confirmed) {
             Log.i(TAG, "User cancel the dialog to enable DSDS.");
             startChooseSimActivity();
diff --git a/src/com/android/settings/sim/SwitchToEsimConfirmDialogActivity.java b/src/com/android/settings/sim/SwitchToEsimConfirmDialogActivity.java
index 385deff..be2fa2d 100644
--- a/src/com/android/settings/sim/SwitchToEsimConfirmDialogActivity.java
+++ b/src/com/android/settings/sim/SwitchToEsimConfirmDialogActivity.java
@@ -101,7 +101,7 @@
     }
 
     @Override
-    public void onConfirm(int tag, boolean confirmed) {
+    public void onConfirm(int tag, boolean confirmed, int itemPosition) {
         if (!confirmed) {
             AlertDialogFragment.show(
                     this,