OpenEUICC/app/src/main/java/im/angry/openeuicc/util/PrivilegedTelephonyUtils.kt
Peter Cai 770083523d
All checks were successful
/ build-debug (push) Successful in 4m45s
refactor: Extract an interface from EuiccChannelManager
Eventually, we would like EuiccChannelManager to become a Service
instead of just any random class.
2024-03-03 20:29:18 -05:00

84 lines
2.8 KiB
Kotlin

package im.angry.openeuicc.util
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import android.telephony.UiccSlotMapping
import im.angry.openeuicc.core.EuiccChannel
import im.angry.openeuicc.core.IEuiccChannelManager
import kotlinx.coroutines.runBlocking
import java.lang.Exception
val TelephonyManager.supportsDSDS: Boolean
get() = supportedModemCount == 2
val TelephonyManager.dsdsEnabled: Boolean
get() = activeModemCount >= 2
fun TelephonyManager.setDsdsEnabled(euiccManager: IEuiccChannelManager, enabled: Boolean) {
runBlocking {
euiccManager.enumerateEuiccChannels()
}
// Disable all eSIM profiles before performing a DSDS switch (only for internal eSIMs)
euiccManager.knownChannels.forEach {
if (!it.removable) {
it.lpa.disableActiveProfileWithUndo()
}
}
switchMultiSimConfig(if (enabled) { 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: IEuiccChannelManager, newMapping: Collection<UiccSlotMapping>,
currentMapping: Collection<UiccSlotMapping> = simSlotMapping
) {
val unmapped = currentMapping.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 ->
if (!channel.removable) {
return@mapNotNull channel.lpa.disableActiveProfileWithUndo()
} else {
// Do not do anything for external eUICCs -- we can't really trust them to work properly
// with no profile enabled.
return@mapNotNull null
}
}
}
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 {
requestEmbeddedSubscriptionInfoListRefresh(cardId)
} catch (e: Exception) {
// Ignore
}
}
}
// Every EuiccChannel we use here should be backed by a RealUiccPortInfoCompat
val EuiccChannel.removable
get() = (port as RealUiccPortInfoCompat).card.isRemovable
val EuiccChannel.cardId
get() = (port as RealUiccPortInfoCompat).card.cardId
val EuiccChannel.isMEP
get() = (port as RealUiccPortInfoCompat).card.isMultipleEnabledProfilesSupported