diff --git a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt index 74ec285..5a22629 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt @@ -55,7 +55,7 @@ open class DefaultEuiccChannelManager( parseIsdrAidList(appContainer.preferenceRepository.isdrAidListFlow.first()) return isdrAidList.firstNotNullOfOrNull { - Log.i(TAG, "Opening channel, trying ISDR AID ${it.encodeHex()}") + Log.i(TAG, "Opening channel, trying ISD-R AID: ${it.encodeHex()}") openFn(it)?.let { channel -> if (channel.valid) { @@ -277,11 +277,11 @@ open class DefaultEuiccChannelManager( ) try { val channel = tryOpenChannelFirstValidAid { - euiccChannelFactory.tryOpenUsbEuiccChannel( - device, - iface, - it - ) + try { + euiccChannelFactory.tryOpenUsbEuiccChannel(device, iface, it) + } catch (_: IllegalArgumentException) { + null + } } if (channel != null && channel.lpa.valid) { usbChannel = channel diff --git a/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt b/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt index f9e764b..107395f 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt @@ -45,6 +45,15 @@ class UsbApduInterface( e.printStackTrace() throw e } + + // Send Terminal Capabilities + // Specs: ETSI TS 102 221 v15.0.0 - 11.1.19 TERMINAL CAPABILITY + val terminalCapabilities = buildCmd( + 0x80.toByte(), 0xaa.toByte(), 0x00, 0x00, + "A9088100820101830107".decodeHex(), + le = null, + ) + transmitApduByChannel(terminalCapabilities, 0) } override fun disconnect() { diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt index 4e499dc..aa922be 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt @@ -104,7 +104,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { add(Item(R.string.euicc_info_eid, channel.lpa.eID, copiedToastResId = R.string.toast_eid_copied)) channel.tryParseEuiccVendorInfo()?.let { vendorInfo -> vendorInfo.skuName?.let { add(Item(R.string.euicc_info_sku, it)) } - vendorInfo.serialNumber?.let { add(Item(R.string.euicc_info_sn, it)) } + vendorInfo.serialNumber?.let { add(Item(R.string.euicc_info_sn, it, copiedToastResId = R.string.toast_sn_copied)) } vendorInfo.firmwareVersion?.let { add(Item(R.string.euicc_info_fw_ver, it)) } vendorInfo.bootloaderVersion?.let { add(Item(R.string.euicc_info_bl_ver, it)) } } diff --git a/app-common/src/main/java/im/angry/openeuicc/util/LPAString.kt b/app-common/src/main/java/im/angry/openeuicc/util/LPAString.kt index 20956fb..63a81f1 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/LPAString.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/LPAString.kt @@ -8,15 +8,15 @@ data class LPAString( ) { companion object { fun parse(input: String): LPAString { - val components = input.removePrefix("LPA:").split('$') - if (components.size < 2 || components[0] != "1") { - throw IllegalArgumentException("Invalid activation code format") - } + var token = input + if (token.startsWith("LPA:", ignoreCase = true)) token = token.drop(4) + val components = token.split('$').map { it.trim().ifBlank { null } } + require(components.getOrNull(0) == "1") { "Invalid AC_Format" } return LPAString( - address = components[1].trim(), - matchingId = components.getOrNull(2)?.trim()?.ifBlank { null }, - oid = components.getOrNull(3)?.trim()?.ifBlank { null }, - confirmationCodeRequired = components.getOrNull(4)?.trim() == "1" + requireNotNull(components.getOrNull(1)) { "SM-DP+ is required" }, + components.getOrNull(2), + components.getOrNull(3), + components.getOrNull(4) == "1" ) } } diff --git a/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt b/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt index 928079f..5f4aec4 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt @@ -45,11 +45,22 @@ const val EUICC_DEFAULT_ISDR_AID = "A0000005591010FFFFFFFF8900000100" internal object PreferenceConstants { val DEFAULT_AID_LIST = """ # One AID per line. Comment lines start with #. + # Refs: + # eUICC standard $EUICC_DEFAULT_ISDR_AID - - # 5ber + + # eSTK.me + A06573746B6D65FFFFFFFF4953442D52 + + # eSIM.me + A0000005591010000000008900000300 + + # 5ber.eSIM A0000005591010FFFFFFFF8900050500 + + # Xesim + A0000005591010FFFFFFFF8900000177 """.trimIndent() } @@ -97,13 +108,12 @@ class PreferenceFlowWrapper private constructor( defaultValue: T, encoder: (T) -> T, decoder: (T) -> T - ) : - this( - context, - key, - context.dataStore.data.map { it[key]?.let(decoder) ?: defaultValue }, - encoder - ) + ) : this( + context, + key, + context.dataStore.data.map { it[key]?.let(decoder) ?: defaultValue }, + encoder + ) suspend fun updatePreference(value: T) { context.dataStore.edit { it[key] = encoder(value) } diff --git a/app-common/src/main/java/im/angry/openeuicc/util/StringUtils.kt b/app-common/src/main/java/im/angry/openeuicc/util/StringUtils.kt index 9f993a3..99cf0b3 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/StringUtils.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/StringUtils.kt @@ -36,6 +36,7 @@ fun formatFreeSpace(size: Int): String = fun parseIsdrAidList(s: String): List = s.split('\n').map(String::trim).filter { !it.startsWith('#') } .map(String::trim) + .filter(String::isNotEmpty) .mapNotNull { try { it.decodeHex() diff --git a/app-common/src/main/res/layout/activity_isdr_aid_list.xml b/app-common/src/main/res/layout/activity_isdr_aid_list.xml index 06a75a1..48135fb 100644 --- a/app-common/src/main/res/layout/activity_isdr_aid_list.xml +++ b/app-common/src/main/res/layout/activity_isdr_aid_list.xml @@ -11,6 +11,7 @@ android:id="@+id/isdr_aid_list_editor" android:layout_width="0dp" android:layout_height="0dp" + android:fontFamily="monospace" android:importantForAutofill="no" android:inputType="textMultiLine" android:gravity="top|start"