Implement TelephonyManagerApduChannel
This does not work yet because only the LPA which implements EuiccService can access the channel. Let's hope however everything we did here *should* work.
This commit is contained in:
parent
e8eeb9e53d
commit
5894dc9a71
|
@ -4,9 +4,11 @@ import android.content.Context
|
|||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.se.omapi.SEService
|
||||
import android.telephony.TelephonyManager
|
||||
import android.util.Log
|
||||
import com.truphone.lpa.ApduChannel
|
||||
import com.truphone.lpa.impl.LocalProfileAssistantImpl
|
||||
import im.angry.openeuicc.OpenEuiccApplication
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -23,6 +25,10 @@ class EuiccChannelManager(private val context: Context) {
|
|||
|
||||
private var seService: SEService? = null
|
||||
|
||||
private val tm by lazy {
|
||||
(context.applicationContext as OpenEuiccApplication).telephonyManager
|
||||
}
|
||||
|
||||
private val handler = Handler(HandlerThread("EuiccChannelManager").also { it.start() }.looper)
|
||||
|
||||
private suspend fun connectSEService(): SEService = suspendCoroutine { cont ->
|
||||
|
@ -50,12 +56,30 @@ class EuiccChannelManager(private val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
val shouldTryTelephonyManager =
|
||||
tm.uiccCardsInfo.find { it.slotIndex == slotId }?.let {
|
||||
it.isEuicc && !it.isRemovable
|
||||
} ?: false
|
||||
|
||||
var apduChannel: ApduChannel? = null
|
||||
var stateManager: EuiccChannelStateManager? = null
|
||||
OmapiApduChannel.tryConnectUiccSlot(seService!!, slotId)?.let { (_apduChannel, _stateManager) ->
|
||||
apduChannel = _apduChannel
|
||||
stateManager = _stateManager
|
||||
} ?: return null
|
||||
|
||||
if (shouldTryTelephonyManager) {
|
||||
Log.d(TAG, "Using TelephonyManager for slot $slotId")
|
||||
// TODO: On Tiramisu, we should also connect all available "ports" for MEP support
|
||||
TelephonyManagerApduChannel.tryConnectUiccSlot(tm, slotId)?.let { (_apduChannel, _stateManager) ->
|
||||
apduChannel = _apduChannel
|
||||
stateManager = _stateManager
|
||||
}
|
||||
}
|
||||
|
||||
if (apduChannel == null || stateManager == null) {
|
||||
OmapiApduChannel.tryConnectUiccSlot(seService!!, slotId)
|
||||
?.let { (_apduChannel, _stateManager) ->
|
||||
apduChannel = _apduChannel
|
||||
stateManager = _stateManager
|
||||
} ?: return null
|
||||
}
|
||||
|
||||
val channel = EuiccChannel(slotId, "SIM $slotId", LocalProfileAssistantImpl(apduChannel), stateManager!!)
|
||||
channels.add(channel)
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
package im.angry.openeuicc.core
|
||||
|
||||
import android.telephony.IccOpenLogicalChannelResponse
|
||||
import android.telephony.IccOpenLogicalChannelResponse.INVALID_CHANNEL
|
||||
import android.telephony.IccOpenLogicalChannelResponse.STATUS_NO_ERROR
|
||||
import android.telephony.TelephonyManager
|
||||
import android.util.Log
|
||||
import com.truphone.lpa.ApduChannel
|
||||
import com.truphone.lpa.ApduTransmittedListener
|
||||
import java.lang.Exception
|
||||
import java.lang.reflect.Method
|
||||
|
||||
class TelephonyManagerApduChannel(
|
||||
private val tm: TelephonyManager,
|
||||
private val slotId: Int,
|
||||
private val channelId: Int) : ApduChannel {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "TelephonyManagerApduChannel"
|
||||
private const val EUICC_APP_ID = "A0000005591010FFFFFFFF8900000100"
|
||||
|
||||
private val iccOpenLogicalChannelBySlot: Method =
|
||||
TelephonyManager::class.java.getMethod("iccOpenLogicalChannelBySlot",
|
||||
Int::class.java, String::class.java, Int::class.java)
|
||||
private val iccCloseLogicalChannelBySlot: Method =
|
||||
TelephonyManager::class.java.getMethod("iccCloseLogicalChannelBySlot",
|
||||
Int::class.java, Int::class.java)
|
||||
private val iccTransmitApduLogicalChannelBySlot: Method =
|
||||
TelephonyManager::class.java.getMethod("iccTransmitApduLogicalChannelBySlot",
|
||||
Int::class.java, Int::class.java, Int::class.java, Int::class.java,
|
||||
Int::class.java, Int::class.java, Int::class.java, String::class.java)
|
||||
|
||||
// TODO: On Tiramisu, we need to specify the portId also if we want MEP support
|
||||
fun tryConnectUiccSlot(tm: TelephonyManager, slotId: Int): Pair<ApduChannel, EuiccChannelStateManager>? {
|
||||
try {
|
||||
val channel = iccOpenLogicalChannelBySlot.invoke(tm, slotId, EUICC_APP_ID, 0) as IccOpenLogicalChannelResponse
|
||||
if (channel.status != STATUS_NO_ERROR || channel.channel == INVALID_CHANNEL) {
|
||||
Log.e(TAG, "Unable to open eUICC channel for slot ${slotId} via TelephonyManager")
|
||||
return null
|
||||
}
|
||||
|
||||
val stateManager = object : EuiccChannelStateManager {
|
||||
override val valid: Boolean
|
||||
get() = true // TODO: Fix this properly
|
||||
|
||||
override fun destroy() {
|
||||
iccCloseLogicalChannelBySlot.invoke(tm, slotId, channel.channel)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Pair(TelephonyManagerApduChannel(tm, slotId, channel.channel), stateManager)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to open eUICC channel for slot ${slotId} via TelephonyManager")
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun transmitAPDU(apdu: String): String {
|
||||
val cla = Integer.parseInt(apdu.substring(0, 2), 16)
|
||||
val instruction = Integer.parseInt(apdu.substring(2, 4), 16)
|
||||
val p1 = Integer.parseInt(apdu.substring(4, 6), 16)
|
||||
val p2 = Integer.parseInt(apdu.substring(6, 8), 16)
|
||||
val p3 = Integer.parseInt(apdu.substring(8, 10), 16)
|
||||
val p4 = apdu.substring(10)
|
||||
|
||||
return iccTransmitApduLogicalChannelBySlot.invoke(
|
||||
tm, slotId, channelId,
|
||||
cla, instruction, p1, p2, p3, p4) as String
|
||||
}
|
||||
|
||||
override fun transmitAPDUS(apdus: MutableList<String>): String {
|
||||
var res = ""
|
||||
for (pdu in apdus) {
|
||||
res = transmitAPDU(pdu)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
override fun sendStatus() {
|
||||
}
|
||||
|
||||
override fun setApduTransmittedListener(apduTransmittedListener: ApduTransmittedListener?) {
|
||||
}
|
||||
|
||||
override fun removeApduTransmittedListener(apduTransmittedListener: ApduTransmittedListener?) {
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue