forked from PeterCxy/OpenEUICC
Refactor OMAPI SEService creation
This commit is contained in:
parent
1e2e3f044c
commit
5926a6601d
|
@ -1,8 +1,6 @@
|
||||||
package im.angry.openeuicc.core
|
package im.angry.openeuicc.core
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Handler
|
|
||||||
import android.os.HandlerThread
|
|
||||||
import android.se.omapi.SEService
|
import android.se.omapi.SEService
|
||||||
import android.telephony.SubscriptionManager
|
import android.telephony.SubscriptionManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
@ -14,8 +12,6 @@ import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.lang.IllegalArgumentException
|
import java.lang.IllegalArgumentException
|
||||||
import kotlin.coroutines.resume
|
|
||||||
import kotlin.coroutines.suspendCoroutine
|
|
||||||
|
|
||||||
open class EuiccChannelManager(protected val context: Context) {
|
open class EuiccChannelManager(protected val context: Context) {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -32,23 +28,12 @@ open class EuiccChannelManager(protected val context: Context) {
|
||||||
(context.applicationContext as OpenEuiccApplication).telephonyManager
|
(context.applicationContext as OpenEuiccApplication).telephonyManager
|
||||||
}
|
}
|
||||||
|
|
||||||
private val handler = Handler(HandlerThread("BaseEuiccChannelManager").also { it.start() }.looper)
|
|
||||||
|
|
||||||
protected open val uiccCards: Collection<UiccCardInfoCompat>
|
protected open val uiccCards: Collection<UiccCardInfoCompat>
|
||||||
get() = (0..<tm.activeModemCountCompat).map { FakeUiccCardInfoCompat(it) }
|
get() = (0..<tm.activeModemCountCompat).map { FakeUiccCardInfoCompat(it) }
|
||||||
|
|
||||||
private suspend fun connectSEService(): SEService = suspendCoroutine { cont ->
|
|
||||||
handler.post {
|
|
||||||
var service: SEService? = null
|
|
||||||
service = SEService(context, { handler.post(it) }) {
|
|
||||||
cont.resume(service!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun ensureSEService() {
|
private suspend fun ensureSEService() {
|
||||||
if (seService == null) {
|
if (seService == null) {
|
||||||
seService = connectSEService()
|
seService = connectSEService(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
package im.angry.openeuicc.util
|
package im.angry.openeuicc.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.se.omapi.Reader
|
import android.se.omapi.Reader
|
||||||
import android.se.omapi.SEService
|
import android.se.omapi.SEService
|
||||||
import android.telephony.TelephonyManager
|
import android.telephony.TelephonyManager
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.resumeWithException
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
val TelephonyManager.activeModemCountCompat: Int
|
val TelephonyManager.activeModemCountCompat: Int
|
||||||
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
@ -20,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
|
* In the privileged version, the EuiccChannelManager should work
|
||||||
* based on real Uicc{Card,Port}Info reported by TelephonyManager.
|
* based on real Uicc{Card,Port}Info reported by TelephonyManager.
|
||||||
|
|
|
@ -3,14 +3,11 @@ package im.angry.openeuicc.util
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.se.omapi.SEService
|
|
||||||
import android.telephony.TelephonyManager
|
import android.telephony.TelephonyManager
|
||||||
import im.angry.easyeuicc.R
|
import im.angry.easyeuicc.R
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlin.coroutines.resume
|
|
||||||
import kotlin.coroutines.suspendCoroutine
|
|
||||||
|
|
||||||
fun getCompatibilityChecks(context: Context): List<CompatibilityCheck> =
|
fun getCompatibilityChecks(context: Context): List<CompatibilityCheck> =
|
||||||
listOf(
|
listOf(
|
||||||
|
@ -95,22 +92,8 @@ internal class OmapiConnCheck(private val context: Context): CompatibilityCheck(
|
||||||
override val defaultDescription: String
|
override val defaultDescription: String
|
||||||
get() = context.getString(R.string.compatibility_check_omapi_connectivity_desc)
|
get() = context.getString(R.string.compatibility_check_omapi_connectivity_desc)
|
||||||
|
|
||||||
private suspend fun getSEService(): SEService = suspendCoroutine { cont ->
|
|
||||||
var service: SEService? = null
|
|
||||||
var resumed = false
|
|
||||||
val resume = {
|
|
||||||
if (!resumed && service != null) {
|
|
||||||
cont.resume(service!!)
|
|
||||||
resumed = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
service = SEService(context, { it.run() }, { resume() })
|
|
||||||
Thread.sleep(1000)
|
|
||||||
resume()
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun doCheck(): Boolean {
|
override suspend fun doCheck(): Boolean {
|
||||||
val seService = getSEService()
|
val seService = connectSEService(context)
|
||||||
if (!seService.isConnected) {
|
if (!seService.isConnected) {
|
||||||
failureDescription = context.getString(R.string.compatibility_check_omapi_connectivity_fail)
|
failureDescription = context.getString(R.string.compatibility_check_omapi_connectivity_fail)
|
||||||
return false
|
return false
|
||||||
|
|
Loading…
Reference in a new issue