Compare commits

...

2 commits

Author SHA1 Message Date
7c0be54fd7 cleanup: Move connectSEService to Utils instead of TelephonyCompat 2024-02-04 16:13:14 -05:00
64c1fa93d3 DirectProfileDownloadActivity: Handle more potential cases
e.g. we can skip the slot selection dialog if there is only one chip in
the device.
2024-02-04 16:12:06 -05:00
3 changed files with 56 additions and 32 deletions

View file

@ -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.openEuiccApplication
import im.angry.openeuicc.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -16,8 +16,21 @@ class DirectProfileDownloadActivity : AppCompatActivity(), SlotSelectFragment.Sl
openEuiccApplication.euiccChannelManager.enumerateEuiccChannels()
}
SlotSelectFragment.newInstance()
.show(supportFragmentManager, SlotSelectFragment.TAG)
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)
}
}
}
}

View file

@ -27,34 +27,6 @@ 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.

View file

@ -2,8 +2,16 @@ 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() =
@ -15,4 +23,35 @@ val Context.selfAppVersion: String
}
val LocalProfileInfo.isEnabled: Boolean
get() = state == LocalProfileInfo.State.Enabled
get() = state == LocalProfileInfo.State.Enabled
val List<EuiccChannel>.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)
}
}
}
}