refactor: Use DI techniques for EuiccChannel's as well
This commit is contained in:
parent
7c6b4ebee5
commit
1a69c5294b
|
@ -0,0 +1,43 @@
|
|||
package im.angry.openeuicc.core
|
||||
|
||||
import android.content.Context
|
||||
import android.se.omapi.SEService
|
||||
import android.util.Log
|
||||
import im.angry.openeuicc.util.*
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccChannelFactory {
|
||||
private var seService: SEService? = null
|
||||
|
||||
private suspend fun ensureSEService() {
|
||||
if (seService == null) {
|
||||
seService = connectSEService(context)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat): EuiccChannel? {
|
||||
if (port.portIndex != 0) {
|
||||
Log.w(DefaultEuiccChannelManager.TAG, "OMAPI channel attempted on non-zero portId, this may or may not work.")
|
||||
}
|
||||
|
||||
ensureSEService()
|
||||
|
||||
Log.i(DefaultEuiccChannelManager.TAG, "Trying OMAPI for physical slot ${port.card.physicalSlotIndex}")
|
||||
try {
|
||||
return OmapiChannel(seService!!, port)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
// Failed
|
||||
Log.w(
|
||||
DefaultEuiccChannelManager.TAG,
|
||||
"OMAPI APDU interface unavailable for physical slot ${port.card.physicalSlotIndex}."
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun cleanup() {
|
||||
seService?.shutdown()
|
||||
seService = null
|
||||
}
|
||||
}
|
|
@ -1,69 +1,41 @@
|
|||
package im.angry.openeuicc.core
|
||||
|
||||
import android.content.Context
|
||||
import android.se.omapi.SEService
|
||||
import android.telephony.SubscriptionManager
|
||||
import android.util.Log
|
||||
import im.angry.openeuicc.OpenEuiccApplication
|
||||
import im.angry.openeuicc.di.AppContainer
|
||||
import im.angry.openeuicc.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
open class DefaultEuiccChannelManager(protected val context: Context) : EuiccChannelManager {
|
||||
open class DefaultEuiccChannelManager(
|
||||
protected val appContainer: AppContainer,
|
||||
protected val context: Context
|
||||
) : EuiccChannelManager {
|
||||
companion object {
|
||||
const val TAG = "EuiccChannelManager"
|
||||
}
|
||||
|
||||
private val channels = mutableListOf<EuiccChannel>()
|
||||
|
||||
private var seService: SEService? = null
|
||||
|
||||
private val lock = Mutex()
|
||||
|
||||
protected val tm by lazy {
|
||||
(context.applicationContext as OpenEuiccApplication).appContainer.telephonyManager
|
||||
appContainer.telephonyManager
|
||||
}
|
||||
|
||||
private val euiccChannelFactory by lazy {
|
||||
appContainer.euiccChannelFactory
|
||||
}
|
||||
|
||||
protected open val uiccCards: Collection<UiccCardInfoCompat>
|
||||
get() = (0..<tm.activeModemCountCompat).map { FakeUiccCardInfoCompat(it) }
|
||||
|
||||
private suspend fun ensureSEService() {
|
||||
if (seService == null) {
|
||||
seService = connectSEService(context)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun tryOpenEuiccChannelPrivileged(port: UiccPortInfoCompat): EuiccChannel? {
|
||||
// No-op when unprivileged
|
||||
return null
|
||||
}
|
||||
|
||||
protected fun tryOpenEuiccChannelUnprivileged(port: UiccPortInfoCompat): EuiccChannel? {
|
||||
if (port.portIndex != 0) {
|
||||
Log.w(TAG, "OMAPI channel attempted on non-zero portId, this may or may not work.")
|
||||
}
|
||||
|
||||
Log.i(TAG, "Trying OMAPI for physical slot ${port.card.physicalSlotIndex}")
|
||||
try {
|
||||
return OmapiChannel(seService!!, port)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
// Failed
|
||||
Log.w(
|
||||
TAG,
|
||||
"OMAPI APDU interface unavailable for physical slot ${port.card.physicalSlotIndex}."
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat): EuiccChannel? {
|
||||
lock.withLock {
|
||||
ensureSEService()
|
||||
val existing =
|
||||
channels.find { it.slotId == port.card.physicalSlotIndex && it.portId == port.portIndex }
|
||||
if (existing != null) {
|
||||
|
@ -80,17 +52,9 @@ open class DefaultEuiccChannelManager(protected val context: Context) : EuiccCha
|
|||
return null
|
||||
}
|
||||
|
||||
var euiccChannel: EuiccChannel? = tryOpenEuiccChannelPrivileged(port)
|
||||
|
||||
if (euiccChannel == null) {
|
||||
euiccChannel = tryOpenEuiccChannelUnprivileged(port)
|
||||
return euiccChannelFactory.tryOpenEuiccChannel(port)?.also {
|
||||
channels.add(it)
|
||||
}
|
||||
|
||||
if (euiccChannel != null) {
|
||||
channels.add(euiccChannel)
|
||||
}
|
||||
|
||||
return euiccChannel
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,8 +108,6 @@ open class DefaultEuiccChannelManager(protected val context: Context) : EuiccCha
|
|||
|
||||
override suspend fun enumerateEuiccChannels() {
|
||||
withContext(Dispatchers.IO) {
|
||||
ensureSEService()
|
||||
|
||||
for (uiccInfo in uiccCards) {
|
||||
for (port in uiccInfo.ports) {
|
||||
if (tryOpenEuiccChannel(port) != null) {
|
||||
|
@ -168,7 +130,6 @@ open class DefaultEuiccChannelManager(protected val context: Context) : EuiccCha
|
|||
}
|
||||
|
||||
channels.clear()
|
||||
seService?.shutdown()
|
||||
seService = null
|
||||
euiccChannelFactory.cleanup()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package im.angry.openeuicc.core
|
||||
|
||||
import im.angry.openeuicc.util.*
|
||||
|
||||
// This class is here instead of inside DI because it contains a bit more logic than just
|
||||
// "dumb" dependency injection.
|
||||
interface EuiccChannelFactory {
|
||||
suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat): EuiccChannel?
|
||||
|
||||
/**
|
||||
* Release all resources used by this EuiccChannelFactory
|
||||
* Note that the same instance may be reused; any resources allocated must be automatically
|
||||
* re-acquired when this happens
|
||||
*/
|
||||
fun cleanup()
|
||||
}
|
|
@ -2,6 +2,7 @@ package im.angry.openeuicc.di
|
|||
|
||||
import android.telephony.SubscriptionManager
|
||||
import android.telephony.TelephonyManager
|
||||
import im.angry.openeuicc.core.EuiccChannelFactory
|
||||
import im.angry.openeuicc.core.EuiccChannelManager
|
||||
import im.angry.openeuicc.util.*
|
||||
|
||||
|
@ -11,4 +12,5 @@ interface AppContainer {
|
|||
val subscriptionManager: SubscriptionManager
|
||||
val preferenceRepository: PreferenceRepository
|
||||
val uiComponentFactory: UiComponentFactory
|
||||
val euiccChannelFactory: EuiccChannelFactory
|
||||
}
|
|
@ -3,6 +3,7 @@ package im.angry.openeuicc.di
|
|||
import android.content.Context
|
||||
import android.telephony.SubscriptionManager
|
||||
import android.telephony.TelephonyManager
|
||||
import im.angry.openeuicc.core.DefaultEuiccChannelFactory
|
||||
import im.angry.openeuicc.core.DefaultEuiccChannelManager
|
||||
import im.angry.openeuicc.core.EuiccChannelManager
|
||||
import im.angry.openeuicc.util.*
|
||||
|
@ -13,7 +14,7 @@ open class DefaultAppContainer(context: Context) : AppContainer {
|
|||
}
|
||||
|
||||
override val euiccChannelManager: EuiccChannelManager by lazy {
|
||||
DefaultEuiccChannelManager(context)
|
||||
DefaultEuiccChannelManager(this, context)
|
||||
}
|
||||
|
||||
override val subscriptionManager by lazy {
|
||||
|
@ -27,4 +28,8 @@ open class DefaultAppContainer(context: Context) : AppContainer {
|
|||
override val uiComponentFactory by lazy {
|
||||
DefaultUiComponentFactory()
|
||||
}
|
||||
|
||||
override val euiccChannelFactory by lazy {
|
||||
DefaultEuiccChannelFactory(context)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package im.angry.openeuicc.core
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import im.angry.openeuicc.OpenEuiccApplication
|
||||
import im.angry.openeuicc.util.*
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFactory(context) {
|
||||
private val tm by lazy {
|
||||
(context.applicationContext as OpenEuiccApplication).appContainer.telephonyManager
|
||||
}
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
override suspend fun tryOpenEuiccChannel(port: UiccPortInfoCompat): EuiccChannel? {
|
||||
val port = port as RealUiccPortInfoCompat
|
||||
if (port.card.isRemovable) {
|
||||
// Attempt unprivileged (OMAPI) before TelephonyManager
|
||||
// but still try TelephonyManager in case OMAPI is broken
|
||||
super.tryOpenEuiccChannel(port)?.let { return it }
|
||||
}
|
||||
|
||||
if (port.card.isEuicc) {
|
||||
Log.i(
|
||||
DefaultEuiccChannelManager.TAG,
|
||||
"Trying TelephonyManager for slot ${port.card.physicalSlotIndex} port ${port.portIndex}"
|
||||
)
|
||||
try {
|
||||
return TelephonyManagerChannel(
|
||||
port, tm
|
||||
)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
// Failed
|
||||
Log.w(
|
||||
DefaultEuiccChannelManager.TAG,
|
||||
"TelephonyManager APDU interface unavailable for slot ${port.card.physicalSlotIndex} port ${port.portIndex}, falling back"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return super.tryOpenEuiccChannel(port)
|
||||
}
|
||||
}
|
|
@ -1,37 +1,15 @@
|
|||
package im.angry.openeuicc.core
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import im.angry.openeuicc.OpenEuiccApplication
|
||||
import im.angry.openeuicc.di.AppContainer
|
||||
import im.angry.openeuicc.util.*
|
||||
import java.lang.Exception
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
class PrivilegedEuiccChannelManager(context: Context): DefaultEuiccChannelManager(context) {
|
||||
class PrivilegedEuiccChannelManager(appContainer: AppContainer, context: Context) :
|
||||
DefaultEuiccChannelManager(appContainer, context) {
|
||||
override val uiccCards: Collection<UiccCardInfoCompat>
|
||||
get() = tm.uiccCardsInfoCompat
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
override fun tryOpenEuiccChannelPrivileged(port: UiccPortInfoCompat): EuiccChannel? {
|
||||
val port = port as RealUiccPortInfoCompat
|
||||
if (port.card.isRemovable) {
|
||||
// Attempt unprivileged (OMAPI) before TelephonyManager
|
||||
// but still try TelephonyManager in case OMAPI is broken
|
||||
super.tryOpenEuiccChannelUnprivileged(port)?.let { return it }
|
||||
}
|
||||
|
||||
if (port.card.isEuicc) {
|
||||
Log.i(TAG, "Trying TelephonyManager for slot ${port.card.physicalSlotIndex} port ${port.portIndex}")
|
||||
try {
|
||||
return TelephonyManagerChannel(port, tm)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
// Failed
|
||||
Log.w(TAG, "TelephonyManager APDU interface unavailable for slot ${port.card.physicalSlotIndex} port ${port.portIndex}, falling back")
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// Clean up channels left open in TelephonyManager
|
||||
// due to a (potentially) forced restart
|
||||
// This should be called every time the application is restarted
|
||||
|
@ -48,7 +26,7 @@ class PrivilegedEuiccChannelManager(context: Context): DefaultEuiccChannelManage
|
|||
}
|
||||
|
||||
override fun notifyEuiccProfilesChanged(logicalSlotId: Int) {
|
||||
(context.applicationContext as OpenEuiccApplication).appContainer.subscriptionManager.apply {
|
||||
appContainer.subscriptionManager.apply {
|
||||
findEuiccChannelBySlotBlocking(logicalSlotId)?.let {
|
||||
tryRefreshCachedEuiccInfo(it.cardId)
|
||||
}
|
||||
|
|
|
@ -2,14 +2,19 @@ package im.angry.openeuicc.di
|
|||
|
||||
import android.content.Context
|
||||
import im.angry.openeuicc.core.EuiccChannelManager
|
||||
import im.angry.openeuicc.core.PrivilegedEuiccChannelFactory
|
||||
import im.angry.openeuicc.core.PrivilegedEuiccChannelManager
|
||||
|
||||
class PrivilegedAppContainer(context: Context) : DefaultAppContainer(context) {
|
||||
override val euiccChannelManager: EuiccChannelManager by lazy {
|
||||
PrivilegedEuiccChannelManager(context)
|
||||
PrivilegedEuiccChannelManager(this, context)
|
||||
}
|
||||
|
||||
override val uiComponentFactory by lazy {
|
||||
PrivilegedUiComponentFactory()
|
||||
}
|
||||
|
||||
override val euiccChannelFactory by lazy {
|
||||
PrivilegedEuiccChannelFactory(context)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue