diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/DirectProfileDownloadActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/DirectProfileDownloadActivity.kt index 9c4011a..a7983a5 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/DirectProfileDownloadActivity.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/DirectProfileDownloadActivity.kt @@ -3,7 +3,7 @@ package im.angry.openeuicc.ui import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope -import im.angry.openeuicc.util.* +import im.angry.openeuicc.util.openEuiccApplication import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -16,21 +16,8 @@ class DirectProfileDownloadActivity : AppCompatActivity(), SlotSelectFragment.Sl openEuiccApplication.euiccChannelManager.enumerateEuiccChannels() } - val knownChannels = openEuiccApplication.euiccChannelManager.knownChannels - when { - knownChannels.isEmpty() -> { - finish() - } - knownChannels.hasMultipleChips -> { - SlotSelectFragment.newInstance() - .show(supportFragmentManager, SlotSelectFragment.TAG) - } - else -> { - // If the device has only one eSIM "chip" (but may be mapped to multiple slots), - // we can skip the slot selection dialog since there is only one chip to save to. - onSlotSelected(knownChannels[0].slotId, knownChannels[0].portId) - } - } + SlotSelectFragment.newInstance() + .show(supportFragmentManager, SlotSelectFragment.TAG) } } diff --git a/app-common/src/main/java/im/angry/openeuicc/util/TelephonyCompat.kt b/app-common/src/main/java/im/angry/openeuicc/util/TelephonyCompat.kt index 5c7d217..6636bc1 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/TelephonyCompat.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/TelephonyCompat.kt @@ -27,6 +27,34 @@ fun SEService.getUiccReaderCompat(slotNumber: Int): Reader { } } +// Create an instance of OMAPI SEService in a manner that "makes sense" without unpredictable callbacks +suspend fun connectSEService(context: Context): SEService = suspendCoroutine { cont -> + // Use a Mutex to make sure the continuation is run *after* the "service" variable is assigned + val lock = Mutex() + var service: SEService? = null + val callback = { + runBlocking { + lock.withLock { + cont.resume(service!!) + } + } + } + + runBlocking { + // If this were not protected by a Mutex, callback might be run before service is even assigned + // Yes, we are on Android, we could have used something like a Handler, but we cannot really + // assume the coroutine is run on a thread that has a Handler. We either use our own HandlerThread + // (and then cleanup becomes an issue), or we use a lock + lock.withLock { + try { + service = SEService(context, { it.run() }, callback) + } catch (e: Exception) { + cont.resumeWithException(e) + } + } + } +} + /* * In the privileged version, the EuiccChannelManager should work * based on real Uicc{Card,Port}Info reported by TelephonyManager. diff --git a/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt b/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt index 5d4221e..6e6f162 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt @@ -2,16 +2,8 @@ package im.angry.openeuicc.util import android.content.Context import android.content.pm.PackageManager -import android.se.omapi.SEService -import im.angry.openeuicc.core.EuiccChannel -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock import net.typeblog.lpac_jni.LocalProfileInfo import java.lang.RuntimeException -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.coroutines.suspendCoroutine val Context.selfAppVersion: String get() = @@ -23,35 +15,4 @@ val Context.selfAppVersion: String } val LocalProfileInfo.isEnabled: Boolean - get() = state == LocalProfileInfo.State.Enabled - -val List.hasMultipleChips: Boolean - get() = distinctBy { it.slotId }.size > 1 - -// Create an instance of OMAPI SEService in a manner that "makes sense" without unpredictable callbacks -suspend fun connectSEService(context: Context): SEService = suspendCoroutine { cont -> - // Use a Mutex to make sure the continuation is run *after* the "service" variable is assigned - val lock = Mutex() - var service: SEService? = null - val callback = { - runBlocking { - lock.withLock { - cont.resume(service!!) - } - } - } - - runBlocking { - // If this were not protected by a Mutex, callback might be run before service is even assigned - // Yes, we are on Android, we could have used something like a Handler, but we cannot really - // assume the coroutine is run on a thread that has a Handler. We either use our own HandlerThread - // (and then cleanup becomes an issue), or we use a lock - lock.withLock { - try { - service = SEService(context, { it.run() }, callback) - } catch (e: Exception) { - cont.resumeWithException(e) - } - } - } -} \ No newline at end of file + get() = state == LocalProfileInfo.State.Enabled \ No newline at end of file