浏览代码

feat: atr in euiccinfo activity

commit 0fbec512ab7dd8be207bb771129a29eb5f9434a8
Author: septs <github@septs.pw>
Date:   Wed Dec 18 21:27:53 2024 +0800

    feat: atr in euiccinfo activity
septs 1 年之前
父节点
当前提交
3ef78a23db

+ 2 - 0
app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt

@@ -30,6 +30,8 @@ class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) :
     override val euiccInfo2: EuiccInfo2?
         get() = lpa.euiccInfo2
 
+    override fun readATR() = lpa.readATR()
+
     override fun setEs10xMss(mss: Byte) = lpa.setEs10xMss(mss)
 
     override fun enableProfile(iccid: String, refresh: Boolean): Boolean =

+ 3 - 0
app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt

@@ -26,6 +26,9 @@ class OmapiApduInterface(
     override val valid: Boolean
         get() = service.isConnected && (this::session.isInitialized && !session.isClosed)
 
+    override fun readATR() =
+        session.atr?.clone() ?: throw IllegalStateException("atr unavailable")
+
     override fun connect() {
         session = service.getUiccReaderCompat(port.logicalSlotIndex + 1).openSession()
     }

+ 8 - 1
app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt

@@ -32,7 +32,9 @@ class UsbApduInterface(
         transceiver = UsbCcidTransceiver(conn, bulkIn, bulkOut, ccidDescription, verboseLoggingFlow)
 
         try {
-            transceiver.iccPowerOn()
+            // 6.1.1.1 PC_to_RDR_IccPowerOn (Page 20 of 40)
+            // https://www.usb.org/sites/default/files/DWG_Smart-Card_USB-ICC_ICCD_rev10.pdf
+            atr = transceiver.iccPowerOn().data
         } catch (e: Exception) {
             e.printStackTrace()
             throw e
@@ -99,6 +101,11 @@ class UsbApduInterface(
     override val valid: Boolean
         get() = channelId != -1
 
+    private var atr: ByteArray? = null
+
+    override fun readATR() =
+        atr?.clone() ?: throw IllegalStateException("atr unavailable")
+
     private fun isSuccessResponse(resp: ByteArray): Boolean =
         resp.size >= 2 && resp[resp.size - 2] == 0x90.toByte() && resp[resp.size - 1] == 0x00.toByte()
 

+ 13 - 1
app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt

@@ -23,6 +23,7 @@ import im.angry.openeuicc.common.R
 import im.angry.openeuicc.core.EuiccChannel
 import im.angry.openeuicc.core.EuiccChannelManager
 import im.angry.openeuicc.util.*
+import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.launch
 import net.typeblog.lpac_jni.impl.PKID_GSMA_LIVE_CI
 import net.typeblog.lpac_jni.impl.PKID_GSMA_TEST_CI
@@ -41,7 +42,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
         @StringRes
         val titleResId: Int,
         val content: String?,
-        val copiedToastResId: Int? = null
+        val copiedToastResId: Int? = null,
     )
 
     override fun onCreate(savedInstanceState: Bundle?) {
@@ -134,6 +135,17 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
             }
             add(Item(R.string.euicc_info_ci_type, getString(resId)))
         }
+        add(
+            Item(
+                R.string.euicc_info_atr,
+                try {
+                    channel.lpa.readATR().encodeHex()
+                } catch (e: Exception) {
+                    getString(R.string.euicc_info_atr_unavailable)
+                },
+                copiedToastResId = R.string.toast_atr_copied,
+            )
+        )
     }
 
     private fun formatByBoolean(b: Boolean, res: Pair<Int, Int>): String =

+ 3 - 0
app-common/src/main/res/values/strings.xml

@@ -31,6 +31,7 @@
     <string name="toast_profile_delete_confirm_text_mismatched">Confirmation string mismatch</string>
     <string name="toast_iccid_copied">ICCID copied to clipboard</string>
     <string name="toast_eid_copied">EID copied to clipboard</string>
+    <string name="toast_atr_copied">ATR copied to clipboard</string>
 
     <string name="usb_permission">Grant USB permission</string>
     <string name="usb_permission_needed">Permission is needed to access the USB smart card reader.</string>
@@ -132,6 +133,8 @@
     <string name="euicc_info_ci_gsma_live">GSMA Live CI</string>
     <string name="euicc_info_ci_gsma_test">GSMA Test CI</string>
     <string name="euicc_info_ci_unknown">Unknown eSIM CI</string>
+    <string name="euicc_info_atr">ATR (Answer To Reset)</string>
+    <string name="euicc_info_atr_unavailable">ATR unavailable</string>
 
     <string name="yes">Yes</string>
     <string name="no">No</string>

+ 3 - 0
app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduInterface.kt

@@ -25,6 +25,9 @@ class TelephonyManagerApduInterface(
         // just that transactions might return errors or nonsense
         get() = lastChannel != -1
 
+    override fun readATR() =
+        throw IllegalStateException("atr unavailable")
+
     override fun connect() {
         // Do nothing
     }

+ 5 - 0
libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ApduInterface.kt

@@ -16,4 +16,9 @@ interface ApduInterface {
      * callers should further check with the LPA to fully determine the validity of a channel
      */
     val valid: Boolean
+
+    /**
+     * Read Answer To Reset
+     */
+    fun readATR(): ByteArray
 }

+ 2 - 0
libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt

@@ -23,6 +23,8 @@ interface LocalProfileAssistant {
     // Extended EuiccInfo for use with LUIs, containing information such as firmware version
     val euiccInfo2: EuiccInfo2?
 
+    fun readATR(): ByteArray
+
     /**
      * Set the max segment size (mss) for all es10x commands. This can help with removable
      * eUICCs that may run at a baud rate too fast for the modem.

+ 2 - 0
libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt

@@ -188,6 +188,8 @@ class LocalProfileAssistantImpl(
             return ret
         }
 
+    override fun readATR() = apduInterface.readATR()
+
     @Synchronized
     override fun enableProfile(iccid: String, refresh: Boolean): Boolean =
         LpacJni.es10cEnableProfile(contextHandle, iccid, refresh) == 0