From d4b875c808cc2ae96299dadc544202681422bcdc Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Mon, 25 Dec 2023 21:33:19 -0500 Subject: [PATCH] SlotMappingFragment: Disable profiles on unmapped slots --- .../angry/openeuicc/ui/SlotMappingFragment.kt | 4 ++- .../util/PrivilegedTelephonyUtils.kt | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/im/angry/openeuicc/ui/SlotMappingFragment.kt b/app/src/main/java/im/angry/openeuicc/ui/SlotMappingFragment.kt index 2816153..57d39c7 100644 --- a/app/src/main/java/im/angry/openeuicc/ui/SlotMappingFragment.kt +++ b/app/src/main/java/im/angry/openeuicc/ui/SlotMappingFragment.kt @@ -98,7 +98,9 @@ class SlotMappingFragment: DialogFragment(), OnMenuItemClickListener { lifecycleScope.launch(Dispatchers.Main) { try { withContext(Dispatchers.IO) { - tm.simSlotMapping = adapter.mappings + // Use the utility method from PrivilegedTelephonyUtils to ensure + // unmapped ports have all profiles disabled + tm.updateSimSlotMapping(openEuiccApplication.euiccChannelManager, adapter.mappings) } } catch (e: Exception) { Toast.makeText(requireContext(), R.string.slot_mapping_failure, Toast.LENGTH_LONG).show() diff --git a/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyUtils.kt b/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyUtils.kt index 28b9623..a875d8a 100644 --- a/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyUtils.kt +++ b/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyUtils.kt @@ -2,6 +2,9 @@ package im.angry.openeuicc.util import android.telephony.SubscriptionManager import android.telephony.TelephonyManager +import android.telephony.UiccSlotMapping +import im.angry.openeuicc.core.EuiccChannelManager +import net.typeblog.lpac_jni.LocalProfileInfo import java.lang.Exception val TelephonyManager.supportsDSDS: Boolean @@ -13,6 +16,34 @@ var TelephonyManager.dsdsEnabled: Boolean switchMultiSimConfig(if (value) { 2 } else {1}) } +// Disable eSIM profiles before switching the slot mapping +// This ensures that unmapped eSIM ports never have "ghost" profiles enabled +fun TelephonyManager.updateSimSlotMapping(euiccManager: EuiccChannelManager, newMapping: Collection) { + val unmapped = simSlotMapping.filterNot { mapping -> + // If the same physical slot + port pair is not found in the new mapping, it is unmapped + newMapping.any { + it.physicalSlotIndex == mapping.physicalSlotIndex && it.portIndex == mapping.portIndex + } + } + + val undo = unmapped.mapNotNull { mapping -> + euiccManager.findEuiccChannelByPortBlocking(mapping.physicalSlotIndex, mapping.portIndex)?.let { channel -> + channel.lpa.profiles.find { it.state == LocalProfileInfo.State.Enabled }?.let { profile -> + channel.lpa.disableProfile(profile.iccid) + return@mapNotNull { channel.lpa.enableProfile(profile.iccid) } + } + } + } + + try { + simSlotMapping = newMapping + } catch (e: Exception) { + e.printStackTrace() + undo.forEach { it() } // Undo what we just did + throw e // Rethrow for caller to handle + } +} + fun SubscriptionManager.tryRefreshCachedEuiccInfo(cardId: Int) { if (cardId != 0) { try {