WIP: feat: icc get atr #183
2 changed files with 55 additions and 19 deletions
|
@ -1,6 +1,7 @@
|
|||
package im.angry.openeuicc.core
|
||||
|
||||
import android.telephony.IccOpenLogicalChannelResponse
|
||||
import android.telephony.IccOpenLogicalChannelResponse.STATUS_NO_ERROR
|
||||
import android.telephony.IccOpenLogicalChannelResponse.INVALID_CHANNEL
|
||||
import android.telephony.TelephonyManager
|
||||
import android.util.Log
|
||||
import im.angry.openeuicc.util.*
|
||||
|
@ -13,7 +14,7 @@ class TelephonyManagerApduInterface(
|
|||
private val port: UiccPortInfoCompat,
|
||||
private val tm: TelephonyManager,
|
||||
private val verboseLoggingFlow: Flow<Boolean>
|
||||
): ApduInterface {
|
||||
) : ApduInterface, ApduInterfaceAtrProvider {
|
||||
companion object {
|
||||
const val TAG = "TelephonyManagerApduInterface"
|
||||
}
|
||||
|
@ -31,11 +32,17 @@ class TelephonyManagerApduInterface(
|
|||
// Do nothing
|
||||
}
|
||||
|
||||
private val slotIndex: Int
|
||||
get() = port.card.physicalSlotIndex
|
||||
|
||||
private val portIndex: Int
|
||||
get() = port.portIndex
|
||||
|
||||
override fun logicalChannelOpen(aid: ByteArray): Int {
|
||||
val hex = aid.encodeHex()
|
||||
val channel = tm.iccOpenLogicalChannelByPortCompat(port.card.physicalSlotIndex, port.portIndex, hex, 0)
|
||||
if (channel.status != IccOpenLogicalChannelResponse.STATUS_NO_ERROR || channel.channel == IccOpenLogicalChannelResponse.INVALID_CHANNEL) {
|
||||
throw IllegalArgumentException("Cannot open logical channel $hex via TelephonyManager on slot ${port.card.physicalSlotIndex} port ${port.portIndex}")
|
||||
val channel = tm.iccOpenLogicalChannelByPortCompat(slotIndex, portIndex, hex, 0)
|
||||
require(channel.status == STATUS_NO_ERROR && channel.channel != INVALID_CHANNEL) {
|
||||
"Cannot open logical channel $hex via TelephonyManager on slot $slotIndex port $portIndex"
|
||||
}
|
||||
channels.add(channel.channel)
|
||||
return channel.channel
|
||||
|
@ -45,7 +52,7 @@ class TelephonyManagerApduInterface(
|
|||
check(channels.contains(handle)) {
|
||||
"Invalid logical channel handle $handle"
|
||||
}
|
||||
tm.iccCloseLogicalChannelByPortCompat(port.card.physicalSlotIndex, port.portIndex, handle)
|
||||
tm.iccCloseLogicalChannelByPortCompat(slotIndex, portIndex, handle)
|
||||
channels.remove(handle)
|
||||
}
|
||||
|
||||
|
@ -53,15 +60,21 @@ class TelephonyManagerApduInterface(
|
|||
check(channels.contains(handle)) {
|
||||
"Invalid logical channel handle $handle"
|
||||
}
|
||||
if (runBlocking { verboseLoggingFlow.first() }) {
|
||||
Log.d(TAG, "TelephonyManager APDU: ${tx.encodeHex()}")
|
||||
}
|
||||
val result = tm.iccTransmitApduLogicalChannelByPortCompat(
|
||||
port.card.physicalSlotIndex, port.portIndex, handle,
|
||||
tx,
|
||||
)
|
||||
if (runBlocking { verboseLoggingFlow.first() })
|
||||
Log.d(TAG, "TelephonyManager APDU response: $result")
|
||||
val verbose = runBlocking { verboseLoggingFlow.first() }
|
||||
if (verbose) Log.d(TAG, "TelephonyManager APDU: ${tx.encodeHex()}")
|
||||
val result = tm.iccTransmitApduLogicalChannelByPortCompat(slotIndex, portIndex, handle, tx)
|
||||
if (verbose) Log.d(TAG, "TelephonyManager APDU response: $result")
|
||||
return result?.decodeHex() ?: byteArrayOf()
|
||||
}
|
||||
|
||||
override val atr: ByteArray?
|
||||
get() = try {
|
||||
tm.iccGetAtr(slotIndex)?.decodeHex()
|
||||
} catch (e: NoSuchMethodException) {
|
||||
try {
|
||||
tm.getAtrUsingSlotId(slotIndex)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,6 +58,23 @@ private val setSimSlotMapping: Method by lazy {
|
|||
Collection::class.java
|
||||
)
|
||||
}
|
||||
private val getITelephony: Method by lazy {
|
||||
TelephonyManager::class.java.getMethod("getITelephony").apply {
|
||||
isAccessible = true
|
||||
}
|
||||
}
|
||||
|
||||
fun TelephonyManager.getAtrUsingSlotId(slotId: Int): ByteArray? {
|
||||
val telephony = getITelephony.invoke(this)
|
||||
val getAtrUsingSlotId = telephony.javaClass.getMethod("getAtrUsingSlotId", Int::class.java)
|
||||
return getAtrUsingSlotId.invoke(telephony, slotId) as ByteArray?
|
||||
}
|
||||
|
||||
fun TelephonyManager.iccGetAtr(slotId: Int): String? {
|
||||
val telephony = getITelephony.invoke(this)
|
||||
val iccGetAtr = telephony.javaClass.getMethod("iccGetAtr", Int::class.java)
|
||||
return iccGetAtr.invoke(telephony, slotId) as String?
|
||||
}
|
||||
|
||||
fun TelephonyManager.iccOpenLogicalChannelBySlot(
|
||||
slotId: Int, appletId: String?, p2: Int
|
||||
|
@ -67,7 +84,8 @@ fun TelephonyManager.iccOpenLogicalChannelBySlot(
|
|||
fun TelephonyManager.iccOpenLogicalChannelByPort(
|
||||
slotId: Int, portId: Int, appletId: String?, p2: Int
|
||||
): IccOpenLogicalChannelResponse =
|
||||
iccOpenLogicalChannelByPort.invoke(this, slotId, portId, appletId, p2) as IccOpenLogicalChannelResponse
|
||||
iccOpenLogicalChannelByPort.invoke(this, slotId, portId, appletId, p2)
|
||||
as IccOpenLogicalChannelResponse
|
||||
|
||||
fun TelephonyManager.iccCloseLogicalChannelBySlot(slotId: Int, channel: Int) {
|
||||
iccCloseLogicalChannelBySlot.invoke(this, slotId, channel)
|
||||
|
@ -95,12 +113,17 @@ fun TelephonyManager.iccTransmitApduLogicalChannelByPort(
|
|||
|
||||
var TelephonyManager.simSlotMapping: Collection<UiccSlotMapping>
|
||||
get() = getSimSlotMapping.invoke(this) as Collection<UiccSlotMapping>
|
||||
set(new) { setSimSlotMapping.invoke(this, new) }
|
||||
set(new) {
|
||||
setSimSlotMapping.invoke(this, new)
|
||||
}
|
||||
|
||||
private val requestEmbeddedSubscriptionInfoListRefresh: Method by lazy {
|
||||
SubscriptionManager::class.java.getMethod("requestEmbeddedSubscriptionInfoListRefresh", Int::class.java)
|
||||
SubscriptionManager::class.java.getMethod(
|
||||
"requestEmbeddedSubscriptionInfoListRefresh",
|
||||
Int::class.java
|
||||
)
|
||||
}
|
||||
|
||||
fun SubscriptionManager.requestEmbeddedSubscriptionInfoListRefresh(cardId: Int): Unit {
|
||||
fun SubscriptionManager.requestEmbeddedSubscriptionInfoListRefresh(cardId: Int) {
|
||||
requestEmbeddedSubscriptionInfoListRefresh.invoke(this, cardId)
|
||||
}
|
Loading…
Add table
Reference in a new issue