diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelManager.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelManager.kt index 0657c98..135cac6 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelManager.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelManager.kt @@ -121,20 +121,6 @@ open class EuiccChannelManager(protected val context: Context) { } } - fun findEuiccChannelByPhysicalSlotBlocking(physicalSlotId: Int): EuiccChannel? = runBlocking { - if (!checkPrivileges()) return@runBlocking null - withContext(Dispatchers.IO) { - for (card in tm.uiccCardsInfoCompat) { - if (card.physicalSlotIndex != physicalSlotId) continue - for (port in card.ports) { - tryOpenEuiccChannel(port)?.let { return@withContext it } - } - } - - null - } - } - fun findEuiccChannelByPortBlocking(physicalSlotId: Int, portId: Int): EuiccChannel? = runBlocking { if (!checkPrivileges()) return@runBlocking null withContext(Dispatchers.IO) { diff --git a/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt b/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt index d98fca8..4824fbd 100644 --- a/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt +++ b/app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt @@ -1,31 +1,20 @@ package im.angry.openeuicc.service import android.service.euicc.* -import android.telephony.UiccSlotMapping import android.telephony.euicc.DownloadableSubscription import android.telephony.euicc.EuiccInfo -import android.util.Log import net.typeblog.lpac_jni.LocalProfileInfo import im.angry.openeuicc.OpenEuiccApplication import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.util.* -import java.lang.IllegalStateException class OpenEuiccService : EuiccService() { - companion object { - const val TAG = "OpenEuiccService" - } - private val openEuiccApplication get() = application as OpenEuiccApplication - private fun findChannel(physicalSlotId: Int): EuiccChannel? = + private fun findChannel(slotId: Int): EuiccChannel? = openEuiccApplication.euiccChannelManager - .findEuiccChannelByPhysicalSlotBlocking(physicalSlotId) - - private fun findChannel(slotId: Int, portId: Int): EuiccChannel? = - openEuiccApplication.euiccChannelManager - .findEuiccChannelByPortBlocking(slotId, portId) + .findEuiccChannelBySlotBlocking(slotId) override fun onGetEid(slotId: Int): String? = findChannel(slotId)?.lpa?.eID @@ -36,47 +25,6 @@ class OpenEuiccService : EuiccService() { private fun EuiccChannel.profileExists(iccid: String?) = lpa.profiles.any { it.iccid == iccid } - private fun ensurePortIsMapped(slotId: Int, portId: Int) { - val mappings = openEuiccApplication.telephonyManager.simSlotMapping.toMutableList() - - mappings.firstOrNull { it.physicalSlotIndex == slotId && it.portIndex == portId }?.let { - throw IllegalStateException("Slot $slotId port $portId has already been mapped") - } - - val idx = mappings.indexOfFirst { it.physicalSlotIndex != slotId || it.portIndex != portId } - if (idx >= 0) { - mappings[idx] = UiccSlotMapping(portId, slotId, mappings[idx].logicalSlotIndex) - } - - mappings.firstOrNull { it.physicalSlotIndex == slotId && it.portIndex == portId } ?: run { - throw IllegalStateException("Cannot map slot $slotId port $portId") - } - - try { - openEuiccApplication.telephonyManager.simSlotMapping = mappings - return - } catch (_: Exception) { - - } - - // Sometimes hardware supports one ordering but not the reverse - openEuiccApplication.telephonyManager.simSlotMapping = mappings.reversed() - } - - private fun retryWithTimeout(timeoutMillis: Int, backoff: Int = 1000, f: () -> T?): T? { - val startTimeMillis = System.currentTimeMillis() - do { - try { - f()?.let { return@retryWithTimeout it } - } catch (_: Exception) { - // Ignore - } finally { - Thread.sleep(backoff.toLong()) - } - } while (System.currentTimeMillis() - startTimeMillis < timeoutMillis) - return null - } - override fun onGetOtaStatus(slotId: Int): Int { // Not implemented return 5 // EUICC_OTA_STATUS_UNAVAILABLE @@ -108,7 +56,6 @@ class OpenEuiccService : EuiccService() { } override fun onGetEuiccProfileInfoList(slotId: Int): GetEuiccProfileInfoListResult? { - Log.i(TAG, "onGetEuiccProfileInfoList slotId=$slotId") val channel = findChannel(slotId) ?: return null val profiles = channel.lpa.profiles.operational.map { EuiccProfileInfo.Builder(it.iccid).apply { @@ -139,7 +86,6 @@ class OpenEuiccService : EuiccService() { } override fun onDeleteSubscription(slotId: Int, iccid: String): Int { - Log.i(TAG, "onDeleteSubscription slotId=$slotId iccid=$iccid") try { val channel = findChannel(slotId) ?: return RESULT_FIRST_USER @@ -153,7 +99,6 @@ class OpenEuiccService : EuiccService() { if (profile.state == LocalProfileInfo.State.Enabled) { // Must disable the profile first - // TODO: Need to check "other port" as well for MEP return RESULT_FIRST_USER } @@ -167,63 +112,40 @@ class OpenEuiccService : EuiccService() { } } + // TODO: on some devices we need to update the mapping (and potentially disable a pSIM) + // for eSIM to be usable, in which case we will have to respect forceDeactivateSim. + // This is the same for our custom LUI. Both have to take this into consideration. @Deprecated("Deprecated in Java") override fun onSwitchToSubscription( slotId: Int, iccid: String?, forceDeactivateSim: Boolean - ): Int = - // -1 = any port - onSwitchToSubscriptionWithPort(slotId, -1, iccid, forceDeactivateSim) - - override fun onSwitchToSubscriptionWithPort( - slotId: Int, - portIndex: Int, - iccid: String?, - forceDeactivateSim: Boolean ): Int { - Log.i(TAG,"onSwitchToSubscriptionWithPort slotId=$slotId portIndex=$portIndex iccid=$iccid forceDeactivateSim=$forceDeactivateSim") try { - // retryWithTimeout is needed here because this function may be called just after - // AOSP has switched slot mappings, in which case the slots may not be ready yet. - val channel = if (portIndex == -1) { - retryWithTimeout(5000) { findChannel(slotId) } - } else { - retryWithTimeout(5000) { findChannel(slotId, portIndex) } - } ?: run { - if (!forceDeactivateSim) { - // The user must select which SIM to deactivate - return@onSwitchToSubscriptionWithPort RESULT_MUST_DEACTIVATE_SIM - } else { - try { - // If we are allowed to deactivate any SIM we like, try mapping the indicated port first - ensurePortIsMapped(slotId, portIndex) - retryWithTimeout(5000) { findChannel(slotId, portIndex) } - } catch (e: Exception) { - // We cannot map the port (or it is already mapped) - // but we can also use any port available on the card - retryWithTimeout(5000) { findChannel(slotId) } - } ?: return@onSwitchToSubscriptionWithPort RESULT_FIRST_USER - } - } + val channel = findChannel(slotId) ?: return RESULT_FIRST_USER - if (iccid != null && !channel.profileExists(iccid)) { - Log.i(TAG, "onSwitchToSubscriptionWithPort iccid=$iccid not found") + if (!channel.profileExists(iccid)) { return RESULT_FIRST_USER } - // Disable any active profile first if present - channel.lpa.profiles.find { - it.state == LocalProfileInfo.State.Enabled - }?.let { if (!channel.lpa.disableProfile(it.iccid)) return RESULT_FIRST_USER } + if (iccid == null) { + // Disable active profile + val activeProfile = channel.lpa.profiles.find { + it.state == LocalProfileInfo.State.Enabled + } ?: return RESULT_OK - if (iccid != null) { - if (!channel.lpa.enableProfile(iccid)) { - return RESULT_FIRST_USER + return if (channel.lpa.disableProfile(activeProfile.iccid)) { + RESULT_OK + } else { + RESULT_FIRST_USER + } + } else { + return if (channel.lpa.enableProfile(iccid)) { + RESULT_OK + } else { + RESULT_FIRST_USER } } - - return RESULT_OK } catch (e: Exception) { return RESULT_FIRST_USER } finally { @@ -232,7 +154,6 @@ class OpenEuiccService : EuiccService() { } override fun onUpdateSubscriptionNickname(slotId: Int, iccid: String, nickname: String?): Int { - Log.i(TAG, "onUpdateSubscriptionNickname slotId=$slotId iccid=$iccid nickname=$nickname") val channel = findChannel(slotId) ?: return RESULT_FIRST_USER if (!channel.profileExists(iccid)) { return RESULT_FIRST_USER diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 3fc55e7..c62e3af 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -20,10 +20,11 @@ class LocalProfileAssistantImpl( } override val profiles: List - get() = LpacJni.es10cGetProfilesInfo(contextHandle)!!.asList() + get() = LpacJni.es10cGetProfilesInfo(contextHandle)!!.asList() // TODO: Maybe we need better error handling - override val eID: String - get() = LpacJni.es10cGetEid(contextHandle)!! + override val eID: String by lazy { + LpacJni.es10cGetEid(contextHandle)!! + } override val euiccInfo2: EuiccInfo2? get() = LpacJni.es10cexGetEuiccInfo2(contextHandle)