Merge "In E+E, the user can't enable the PSIM" into tm-dev
diff --git a/src/com/android/settings/network/UiccSlotUtil.java b/src/com/android/settings/network/UiccSlotUtil.java
index c4f495c..9a157d6 100644
--- a/src/com/android/settings/network/UiccSlotUtil.java
+++ b/src/com/android/settings/network/UiccSlotUtil.java
@@ -20,6 +20,7 @@
 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;
@@ -47,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;
 
@@ -115,24 +117,27 @@
         }
         TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
         int inactiveRemovableSlot = getInactiveRemovableSlot(telMgr.getUiccSlotsInfo(), slotId);
-        Log.i(TAG, "The InactiveRemovableSlot: " + inactiveRemovableSlot);
-
-        Collection<UiccSlotMapping> uiccSlotMappings = telMgr.getSimSlotMapping();
-        Log.i(TAG, "The SimSlotMapping: " + uiccSlotMappings);
-
+        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,
                 prepareUiccSlotMappings(uiccSlotMappings,
                         /*slot is psim*/ true,
                         inactiveRemovableSlot,
                         /*removable sim's port Id*/ TelephonyManager.DEFAULT_PORT_INDEX,
-                        removedSubInfo,
-                        telMgr.isMultiSimEnabled()),
+                        excludedLogicalSlotIndex),
                 context);
     }
 
@@ -156,16 +161,21 @@
         }
         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, physicalSlotId, port)) {
-            Log.i(TAG, "The slot is active, then the sim can enable directly.");
+            Log.d(TAG, "The slot is active, then the sim can enable directly.");
             return;
         }
 
+        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, removedSubInfo, telMgr.isMultiSimEnabled()),
+                        physicalSlotId, port, excludedLogicalSlotIndex),
                 context);
     }
 
@@ -276,74 +286,91 @@
     @VisibleForTesting
     static Collection<UiccSlotMapping> prepareUiccSlotMappings(
             Collection<UiccSlotMapping> uiccSlotMappings, boolean isPsim, int physicalSlotId,
-            int port, SubscriptionInfo removedSubInfo, boolean isMultiSimEnabled) {
+            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(port, physicalSlotId, 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 subId%d(LogicalSlot%d-Port%d) to "
-                                    + "PhysicalSlotId%d-Port%d",
-                            removedSubInfo.getSubscriptionId(), removedSubInfo.getSimSlotIndex(),
-                            removedSubInfo.getPortIndex(), physicalSlotId, port));
-
-            int logicalSlotIndex = 0;
-            if (isPsim) {
-                // The target slot is psim
-                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 (isSubInfoMappingIntoUiccSlotMapping(uiccSlotMapping, removedSubInfo)) {
-                    if (!isPsim) {
-                        // Replace this uiccSlotMapping
-                        newUiccSlotMappings.add(new UiccSlotMapping(port, physicalSlotId,
-                                uiccSlotMapping.getLogicalSlotIndex()));
-                    }
-                    continue;
+        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()));
                 }
-
-                // If the psim is inserted, then change the
-                // logicalSlotIndex for another uiccSlotMappings.
-                newUiccSlotMappings.add(isPsim
-                        ? new UiccSlotMapping(
-                                uiccSlotMapping.getPortIndex(),
-                                uiccSlotMapping.getPhysicalSlotIndex(),
-                                logicalSlotIndex++
-                        ) : uiccSlotMapping);
+                continue;
             }
-        } else {
-            // For no inserted psim case in DSDS+MEP, there is only one esim in device and
-            // then user inserts another esim in DSDS+MEP.
-            // If the target is esim, then replace the psim.
-            Log.i(TAG, "The removedSubInfo is null");
-            newUiccSlotMappings =
-                    uiccSlotMappings.stream().map(uiccSlotMapping -> {
-                        if (!isPsim && uiccSlotMapping.getPhysicalSlotIndex() != physicalSlotId) {
-                            return new UiccSlotMapping(port, physicalSlotId,
-                                    uiccSlotMapping.getLogicalSlotIndex());
-                        }
-                        return uiccSlotMapping;
-                    }).collect(Collectors.toList());
+
+            // 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;
     }
 
-    private static boolean isSubInfoMappingIntoUiccSlotMapping(UiccSlotMapping uiccSlotMapping,
-            SubscriptionInfo subscriptionInfo) {
-        return uiccSlotMapping != null
-                && uiccSlotMapping.getLogicalSlotIndex() == subscriptionInfo.getSimSlotIndex()
-                && uiccSlotMapping.getPortIndex() == subscriptionInfo.getPortIndex();
+    /**
+     * 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;
+                })
+                .mapToInt(uiccSlotMapping -> uiccSlotMapping.getLogicalSlotIndex())
+                .findFirst()
+                .orElse(INVALID_LOGICAL_SLOT_ID);
     }
 }
diff --git a/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java b/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java
index 8a0a4b0..cc9bdfc 100644
--- a/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java
+++ b/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java
@@ -116,9 +116,10 @@
         Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingSsModePsimActive();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingSsModeEsimPort0Active();
+        int removedLogicalSlotIndex = 0;
 
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 0, null, false);
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
 
         compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
     }
@@ -129,9 +130,10 @@
                 createUiccSlotMappingSsModeEsimPort0Active();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingSsModePsimActive();
+        int removedLogicalSlotIndex = 0;
 
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, null, false);
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
 
         compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
     }
@@ -141,9 +143,10 @@
         Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort0();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingPsimAndPort1();
-        SubscriptionInfo subInfo = createSubscriptionInfo(1, 0);
+        int removedLogicalSlotIndex = 1;
+
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 1, subInfo, true);
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 1, removedLogicalSlotIndex);
 
         compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
     }
@@ -153,10 +156,10 @@
         Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort1();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingPsimAndPort0();
+        int removedLogicalSlotIndex = 1;
 
-        SubscriptionInfo subInfo = createSubscriptionInfo(1, 1);
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 0, subInfo, true);
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
 
         compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
     }
@@ -166,10 +169,10 @@
         Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort0();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingDualPortsB();
+        int removedLogicalSlotIndex = 0;
 
-        SubscriptionInfo subInfo = createSubscriptionInfo(0, 0);
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 1, subInfo, true);
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 1, removedLogicalSlotIndex);
 
         compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
     }
@@ -179,10 +182,10 @@
         Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort1();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingDualPortsA();
+        int removedLogicalSlotIndex = 0;
 
-        SubscriptionInfo subInfo = createSubscriptionInfo(0, 0);
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 0, subInfo, true);
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
 
         compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
     }
@@ -192,9 +195,10 @@
         Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort0();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingDualPortsB();
+        int removedLogicalSlotIndex = 0;
 
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 1, null, true);
+                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 1, removedLogicalSlotIndex);
 
         compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
     }
@@ -204,9 +208,66 @@
         Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingPsimAndPort1();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingDualPortsA();
+        int removedLogicalSlotIndex = 0;
 
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, false, ESIM_PHYSICAL_SLOT, 0, null, true);
+                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);
     }
@@ -216,10 +277,10 @@
         Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsA();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingPsimAndPort1();
+        int removedLogicalSlotIndex = 0;
 
-        SubscriptionInfo subInfo = createSubscriptionInfo(0, 0);
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, subInfo, true);
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
 
         compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
     }
@@ -229,10 +290,10 @@
         Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsA();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingPsimAndPort0();
+        int removedLogicalSlotIndex = 1;
 
-        SubscriptionInfo subInfo = createSubscriptionInfo(1, 1);
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, subInfo, true);
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
 
         compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
     }
@@ -242,10 +303,10 @@
         Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsB();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingPsimAndPort1();
+        int removedLogicalSlotIndex = 1;
 
-        SubscriptionInfo subInfo = createSubscriptionInfo(1, 0);
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, subInfo, true);
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
 
         compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
     }
@@ -255,20 +316,240 @@
         Collection<UiccSlotMapping> uiccSlotMappings = createUiccSlotMappingDualPortsB();
         Collection<UiccSlotMapping> verifyUiccSlotMappings =
                 createUiccSlotMappingPsimAndPort0();
+        int removedLogicalSlotIndex = 0;
 
-        SubscriptionInfo subInfo = createSubscriptionInfo(0, 1);
         Collection<UiccSlotMapping> testUiccSlotMappings = UiccSlotUtil.prepareUiccSlotMappings(
-                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, subInfo, true);
+                uiccSlotMappings, true, PSIM_PHYSICAL_SLOT, 0, removedLogicalSlotIndex);
 
         compareTwoUiccSlotMappings(testUiccSlotMappings, verifyUiccSlotMappings);
     }
 
-    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);
+    @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 = createUiccSlotMappingPsimAndPort1();
+        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 = createUiccSlotMappingPsimAndPort1();
+        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 = createUiccSlotMappingPsimAndPort1();
+        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);
     }
 
     private void compareTwoUiccSlotMappings(Collection<UiccSlotMapping> testUiccSlotMappings,
@@ -288,6 +569,30 @@
         }
     }
 
+    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