ソースを参照

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)
Peter Cai 3 年 前
コミット
103be89d17

+ 10 - 22
app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduChannel.kt

@@ -1,14 +1,13 @@
 package im.angry.openeuicc.core
 package im.angry.openeuicc.core
 
 
-import android.telephony.IccOpenLogicalChannelResponse
 import android.telephony.IccOpenLogicalChannelResponse.INVALID_CHANNEL
 import android.telephony.IccOpenLogicalChannelResponse.INVALID_CHANNEL
 import android.telephony.IccOpenLogicalChannelResponse.STATUS_NO_ERROR
 import android.telephony.IccOpenLogicalChannelResponse.STATUS_NO_ERROR
 import android.telephony.TelephonyManager
 import android.telephony.TelephonyManager
 import android.util.Log
 import android.util.Log
 import com.truphone.lpa.ApduChannel
 import com.truphone.lpa.ApduChannel
 import com.truphone.lpa.ApduTransmittedListener
 import com.truphone.lpa.ApduTransmittedListener
+import im.angry.openeuicc.util.*
 import java.lang.Exception
 import java.lang.Exception
-import java.lang.reflect.Method
 
 
 class TelephonyManagerApduChannel(
 class TelephonyManagerApduChannel(
     private val tm: TelephonyManager,
     private val tm: TelephonyManager,
@@ -19,23 +18,12 @@ class TelephonyManagerApduChannel(
         private const val TAG = "TelephonyManagerApduChannel"
         private const val TAG = "TelephonyManagerApduChannel"
         private const val EUICC_APP_ID = "A0000005591010FFFFFFFF8900000100"
         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
         // TODO: On Tiramisu, we need to specify the portId also if we want MEP support
         fun tryConnectUiccSlot(tm: TelephonyManager, slotId: Int): Pair<ApduChannel, EuiccChannelStateManager>? {
         fun tryConnectUiccSlot(tm: TelephonyManager, slotId: Int): Pair<ApduChannel, EuiccChannelStateManager>? {
             try {
             try {
                 // FIXME: Clean up previously opened channels across restarts
                 // 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) {
                 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}")
                     Log.e(TAG, "Unable to open eUICC channel for slot ${slotId} via TelephonyManager: ${channel.status}")
                     return null
                     return null
@@ -48,7 +36,7 @@ class TelephonyManagerApduChannel(
                         get() = true // TODO: Fix this properly
                         get() = true // TODO: Fix this properly
 
 
                     override fun destroy() {
                     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 cla = Integer.parseInt(apdu.substring(0, 2), 16)
         val instruction = Integer.parseInt(apdu.substring(2, 4), 16)
         val instruction = Integer.parseInt(apdu.substring(2, 4), 16)
         val p1 = Integer.parseInt(apdu.substring(4, 6), 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 p3 = Integer.parseInt(apdu.substring(8, 10), 16)
         val p4 = apdu.substring(10)
         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>): String {
-        var res = ""
+    override fun transmitAPDUS(apdus: MutableList<String>): String? {
+        var res: String? = ""
         for (pdu in apdus) {
         for (pdu in apdus) {
             res = transmitAPDU(pdu)
             res = transmitAPDU(pdu)
         }
         }

+ 40 - 1
app/src/main/java/im/angry/openeuicc/util/TelephonyUtils.kt

@@ -1,6 +1,8 @@
 package im.angry.openeuicc.util
 package im.angry.openeuicc.util
 
 
+import android.telephony.IccOpenLogicalChannelResponse
 import android.telephony.TelephonyManager
 import android.telephony.TelephonyManager
+import java.lang.reflect.Method
 
 
 val TelephonyManager.supportsDSDS: Boolean
 val TelephonyManager.supportsDSDS: Boolean
     get() = supportedModemCount == 2
     get() = supportedModemCount == 2
@@ -9,4 +11,41 @@ var TelephonyManager.dsdsEnabled: Boolean
     get() = activeModemCount >= 2
     get() = activeModemCount >= 2
     set(value) {
     set(value) {
         switchMultiSimConfig(if (value) { 2 } else {1})
         switchMultiSimConfig(if (value) { 2 } else {1})
-    }
+    }
+
+// 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?