diff --git a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt index 870baae..b249675 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt @@ -60,11 +60,11 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha Log.i(DefaultEuiccChannelManager.TAG, "Is OMAPI channel, setting MSS to 60") it.lpa.setEs10xMss(60) } - } catch (_: IllegalArgumentException) { + } catch (e: IllegalArgumentException) { // Failed Log.w( DefaultEuiccChannelManager.TAG, - "OMAPI APDU interface unavailable for physical slot ${port.card.physicalSlotIndex} with ISD-R AID: ${isdrAid.encodeHex()}." + "OMAPI APDU interface unavailable for physical slot ${port.card.physicalSlotIndex}." ) } @@ -80,29 +80,20 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha if (bulkIn == null || bulkOut == null) return null val conn = usbManager.openDevice(usbDevice) ?: return null if (!conn.claimInterface(usbInterface, true)) return null - try { - return EuiccChannelImpl( - context.getString(R.string.usb), - FakeUiccPortInfoCompat(FakeUiccCardInfoCompat(EuiccChannelManager.USB_CHANNEL_ID)), - intrinsicChannelName = usbDevice.productName, - UsbApduInterface( - conn, - bulkIn, - bulkOut, - context.preferenceRepository.verboseLoggingFlow - ), - isdrAid, - context.preferenceRepository.verboseLoggingFlow, - context.preferenceRepository.ignoreTLSCertificateFlow, - ) - } catch (_: IllegalArgumentException) { - // Failed - Log.w( - DefaultEuiccChannelManager.TAG, - "USB APDU interface unavailable for ISD-R AID: ${isdrAid.encodeHex()}." - ) - } - return null + return EuiccChannelImpl( + context.getString(R.string.usb), + FakeUiccPortInfoCompat(FakeUiccCardInfoCompat(EuiccChannelManager.USB_CHANNEL_ID)), + intrinsicChannelName = usbDevice.productName, + UsbApduInterface( + conn, + bulkIn, + bulkOut, + context.preferenceRepository.verboseLoggingFlow + ), + isdrAid, + context.preferenceRepository.verboseLoggingFlow, + context.preferenceRepository.ignoreTLSCertificateFlow, + ) } override fun cleanup() { 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 ac9ba08..74ec285 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 @@ -277,7 +277,11 @@ open class DefaultEuiccChannelManager( ) try { val channel = tryOpenChannelFirstValidAid { - euiccChannelFactory.tryOpenUsbEuiccChannel(device, iface, it) + euiccChannelFactory.tryOpenUsbEuiccChannel( + device, + iface, + it + ) } 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 107395f..f9e764b 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,15 +45,6 @@ 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 aa922be..4e499dc 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, copiedToastResId = R.string.toast_sn_copied)) } + vendorInfo.serialNumber?.let { add(Item(R.string.euicc_info_sn, it)) } 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 63a81f1..20956fb 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 { - 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" } + val components = input.removePrefix("LPA:").split('$') + if (components.size < 2 || components[0] != "1") { + throw IllegalArgumentException("Invalid activation code format") + } return LPAString( - requireNotNull(components.getOrNull(1)) { "SM-DP+ is required" }, - components.getOrNull(2), - components.getOrNull(3), - components.getOrNull(4) == "1" + address = components[1].trim(), + matchingId = components.getOrNull(2)?.trim()?.ifBlank { null }, + oid = components.getOrNull(3)?.trim()?.ifBlank { null }, + confirmationCodeRequired = components.getOrNull(4)?.trim() == "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 5f4aec4..928079f 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,22 +45,11 @@ 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 - - # eSTK.me - A06573746B6D65FFFFFFFF4953442D52 - - # eSIM.me - A0000005591010000000008900000300 - - # 5ber.eSIM + + # 5ber A0000005591010FFFFFFFF8900050500 - - # Xesim - A0000005591010FFFFFFFF8900000177 """.trimIndent() } @@ -108,12 +97,13 @@ 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 079853e..9f993a3 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 @@ -34,12 +34,15 @@ fun formatFreeSpace(size: Int): String = * If none is found, at least EUICC_DEFAULT_ISDR_AID is returned */ fun parseIsdrAidList(s: String): List = - s.split('\n') + s.split('\n').map(String::trim).filter { !it.startsWith('#') } .map(String::trim) - .filter { !it.startsWith('#') } - .map(String::trim) - .filter(String::isNotEmpty) - .mapNotNull { runCatching(it::decodeHex).getOrNull() } + .mapNotNull { + try { + it.decodeHex() + } catch (_: IllegalArgumentException) { + null + } + } .ifEmpty { listOf(EUICC_DEFAULT_ISDR_AID.decodeHex()) } fun String.prettyPrintJson(): String { 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 48135fb..06a75a1 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,7 +11,6 @@ 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" diff --git a/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt b/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt index 68eddef..5489bd5 100644 --- a/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt +++ b/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt @@ -44,11 +44,11 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto context.preferenceRepository.verboseLoggingFlow, context.preferenceRepository.ignoreTLSCertificateFlow, ) - } catch (_: IllegalArgumentException) { + } catch (e: IllegalArgumentException) { // Failed Log.w( DefaultEuiccChannelManager.TAG, - "TelephonyManager APDU interface unavailable for slot ${port.card.physicalSlotIndex} port ${port.portIndex} with ISD-R AID: ${isdrAid.encodeHex()}." + "TelephonyManager APDU interface unavailable for slot ${port.card.physicalSlotIndex} port ${port.portIndex}, falling back" ) } }