From 103be89d17bb40c008af27a0d207e59ec7eea57a Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Tue, 3 May 2022 16:18:05 -0400 Subject: [PATCH] Make the hidden APIs of TelephonyManager extensions So that it looks nicer and we can potentially build against AOSP by simply excluding all of the reflection-based hacks (by putting them in a library first) --- .../core/TelephonyManagerApduChannel.kt | 32 +++++---------- .../im/angry/openeuicc/util/TelephonyUtils.kt | 41 ++++++++++++++++++- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduChannel.kt b/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduChannel.kt index e4ffa63..74eae6d 100644 --- a/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduChannel.kt +++ b/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduChannel.kt @@ -1,14 +1,13 @@ 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 im.angry.openeuicc.util.* import java.lang.Exception -import java.lang.reflect.Method class TelephonyManagerApduChannel( private val tm: TelephonyManager, @@ -19,23 +18,12 @@ class TelephonyManagerApduChannel( 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? { try { // FIXME: Clean up previously opened channels across restarts - iccCloseLogicalChannelBySlot.invoke(tm, slotId, 1) - val channel = iccOpenLogicalChannelBySlot.invoke(tm, slotId, EUICC_APP_ID, 0) as IccOpenLogicalChannelResponse + tm.iccCloseLogicalChannelBySlot(slotId, 1) + val channel = tm.iccOpenLogicalChannelBySlot(slotId, EUICC_APP_ID, 0) if (channel.status != STATUS_NO_ERROR || channel.channel == INVALID_CHANNEL) { Log.e(TAG, "Unable to open eUICC channel for slot ${slotId} via TelephonyManager: ${channel.status}") return null @@ -48,7 +36,7 @@ class TelephonyManagerApduChannel( get() = true // TODO: Fix this properly override fun destroy() { - iccCloseLogicalChannelBySlot.invoke(tm, slotId, channel.channel) + tm.iccCloseLogicalChannelBySlot(slotId, channel.channel) } } @@ -62,7 +50,7 @@ class TelephonyManagerApduChannel( } } - override fun transmitAPDU(apdu: String): String { + 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) @@ -70,13 +58,13 @@ class TelephonyManagerApduChannel( 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 + return tm.iccTransmitApduLogicalChannelBySlot( + slotId, channelId, + cla, instruction, p1, p2, p3, p4) } - override fun transmitAPDUS(apdus: MutableList): String { - var res = "" + override fun transmitAPDUS(apdus: MutableList): String? { + var res: String? = "" for (pdu in apdus) { res = transmitAPDU(pdu) } diff --git a/app/src/main/java/im/angry/openeuicc/util/TelephonyUtils.kt b/app/src/main/java/im/angry/openeuicc/util/TelephonyUtils.kt index a1ae2d1..b655f10 100644 --- a/app/src/main/java/im/angry/openeuicc/util/TelephonyUtils.kt +++ b/app/src/main/java/im/angry/openeuicc/util/TelephonyUtils.kt @@ -1,6 +1,8 @@ package im.angry.openeuicc.util +import android.telephony.IccOpenLogicalChannelResponse import android.telephony.TelephonyManager +import java.lang.reflect.Method val TelephonyManager.supportsDSDS: Boolean get() = supportedModemCount == 2 @@ -9,4 +11,41 @@ var TelephonyManager.dsdsEnabled: Boolean get() = activeModemCount >= 2 set(value) { switchMultiSimConfig(if (value) { 2 } else {1}) - } \ No newline at end of file + } + +// Hidden APIs via reflection to enable building without AOSP source tree +private val iccOpenLogicalChannelBySlot: Method by lazy { + TelephonyManager::class.java.getMethod( + "iccOpenLogicalChannelBySlot", + Int::class.java, String::class.java, Int::class.java + ) +} +private val iccCloseLogicalChannelBySlot: Method by lazy { + TelephonyManager::class.java.getMethod( + "iccCloseLogicalChannelBySlot", + Int::class.java, Int::class.java + ) +} +private val iccTransmitApduLogicalChannelBySlot: Method by lazy { + 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 + ) +} + +fun TelephonyManager.iccOpenLogicalChannelBySlot( + slotId: Int, appletId: String, p2: Int +): IccOpenLogicalChannelResponse = + iccOpenLogicalChannelBySlot.invoke(this, slotId, appletId, p2) as IccOpenLogicalChannelResponse + +fun TelephonyManager.iccCloseLogicalChannelBySlot(slotId: Int, channel: Int): Boolean = + iccCloseLogicalChannelBySlot.invoke(this, slotId, channel) as Boolean + +fun TelephonyManager.iccTransmitApduLogicalChannelBySlot( + slotId: Int, channel: Int, cla: Int, instruction: Int, + p1: Int, p2: Int, p3: Int, data: String? +): String? = + iccTransmitApduLogicalChannelBySlot.invoke( + this, slotId, channel, cla, instruction, p1, p2, p3, data + ) as String? \ No newline at end of file