From 54d546665fcf66f0c4a7c32e5e39e62f172cb90a Mon Sep 17 00:00:00 2001 From: septs Date: Wed, 16 Jul 2025 01:31:06 +0800 Subject: [PATCH 01/11] feat: simplified error handling --- .../ui/wizard/SimplifiedErrorHandling.kt | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt new file mode 100644 index 0000000..1aa1c26 --- /dev/null +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt @@ -0,0 +1,110 @@ +package im.angry.openeuicc.ui.wizard + +import net.typeblog.lpac_jni.LocalProfileAssistant +import org.json.JSONObject +import java.net.NoRouteToHostException +import java.net.PortUnreachableException +import java.net.SocketTimeoutException +import java.net.UnknownHostException +import javax.net.ssl.SSLHandshakeException + +object SimplifiedErrorHandling { + enum class ErrorCode { + // Profile Installed + ICCIDAlready, + + // Profile Mismatch + ICCIDMismatch, + + // Insufficient Memory Space + InsufficientMemorySpace, + + // Unsupported Profile + UnsupportedProfile, + + // The card internal error + CardInternalError, + + // EID doesn’t match the expected value. + EIDMismatch, + + // Expired The Download order has expired. + ProfileExpired, + + // Profile has not yet been released. + UnreleasedProfile, + + // MatchingID (AC_Token or EventID) is refused. + MatchingIDRefused, + + // Confirmation Code is missing. + ConfirmationCodeMissing, + + // Confirmation Code is refused. + ConfirmationCodeRefused, + + // The maximum number of retries for the Profile download order has been exceeded. + ConfirmationCodeRetriesExceeded, + + // The maximum number of retries for the Profile download order has been exceeded. + ProfileRetriesExceeded, + + // The FQDN is unknown + UnknownHost, + + // The Network Timeout + NetworkTimeout, + } + + private val httpErrors = buildMap { + // Stage: AuthenticateClient + put("8.1" to "4.8", ErrorCode.InsufficientMemorySpace) + put("8.1.1" to "3.8", ErrorCode.EIDMismatch) + put("8.2" to "1.2", ErrorCode.UnreleasedProfile) + put("8.2.6" to "3.8", ErrorCode.MatchingIDRefused) + put("8.8.5" to "6.4", ErrorCode.ProfileRetriesExceeded) + + // Stage: GetBoundProfilePackage + put("8.2.7" to "2.2", ErrorCode.ConfirmationCodeMissing) + put("8.2.7" to "3.8", ErrorCode.ConfirmationCodeRefused) + put("8.2.7" to "6.4", ErrorCode.ConfirmationCodeRetriesExceeded) + put("8.8.5" to "4.10", ErrorCode.ProfileExpired) + } + + fun toSimplifiedDownloadError(exc: LocalProfileAssistant.ProfileDownloadException) = when { + exc.lpaErrorReason != "ES10B_ERROR_REASON_UNDEFINED" -> toSimplifiedLPAErrorReason(exc.lpaErrorReason) + exc.lastHttpResponse?.rcode == 200 -> toSimplifiedHTTPResponse(exc.lastHttpResponse!!) + exc.lastHttpException is UnknownHostException -> ErrorCode.UnknownHost + exc.lastHttpException is NoRouteToHostException -> ErrorCode.UnknownHost + exc.lastHttpException is PortUnreachableException -> ErrorCode.UnknownHost + exc.lastHttpException is SSLHandshakeException -> ErrorCode.UnknownHost + exc.lastHttpException is SocketTimeoutException -> ErrorCode.NetworkTimeout + else -> null + } + + private fun toSimplifiedLPAErrorReason(reason: String) = when (reason) { + "ES10B_ERROR_REASON_UNSUPPORTED_CRT_VALUES" -> ErrorCode.UnsupportedProfile + "ES10B_ERROR_REASON_UNSUPPORTED_REMOTE_OPERATION_TYPE" -> ErrorCode.UnsupportedProfile + "ES10B_ERROR_REASON_UNSUPPORTED_PROFILE_CLASS" -> ErrorCode.UnsupportedProfile + "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_ALREADY_EXISTS_ON_EUICC" -> ErrorCode.ICCIDAlready + "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INSUFFICIENT_MEMORY_FOR_PROFILE" -> ErrorCode.InsufficientMemorySpace + "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INTERRUPTION" -> ErrorCode.CardInternalError + "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_PE_PROCESSING_ERROR" -> ErrorCode.CardInternalError + "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_MISMATCH" -> ErrorCode.ICCIDMismatch + else -> null + } + + private fun toSimplifiedHTTPResponse(response: net.typeblog.lpac_jni.HttpInterface.HttpResponse): ErrorCode? { + val content = response.data.decodeToString() + if (!content.startsWith('{')) return null + val response = JSONObject(content) + if (!response.has("header")) return null + val statusCodeData = response + .getJSONObject("header") + .getJSONObject("functionExecutionStatus") + .getJSONObject("statusCodeData") + val subjectCode = statusCodeData.getString("subjectCode") + val reasonCode = statusCodeData.getString("reasonCode") + return httpErrors[subjectCode to reasonCode] + } +} \ No newline at end of file From f21577a37777ea3022c2d69913468f8b32328ce3 Mon Sep 17 00:00:00 2001 From: septs Date: Wed, 16 Jul 2025 01:32:16 +0800 Subject: [PATCH 02/11] fix: comment --- .../im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt index 1aa1c26..5d2aba3 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt @@ -25,7 +25,7 @@ object SimplifiedErrorHandling { // The card internal error CardInternalError, - // EID doesn’t match the expected value. + // EID doesn't match the expected value. EIDMismatch, // Expired The Download order has expired. From 7a1eeca65a1a2a5bea479a2e5418484f70da4634 Mon Sep 17 00:00:00 2001 From: septs Date: Wed, 16 Jul 2025 01:50:36 +0800 Subject: [PATCH 03/11] fix: http exc handling --- .../ui/wizard/SimplifiedErrorHandling.kt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt index 5d2aba3..7be35a6 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt @@ -13,9 +13,6 @@ object SimplifiedErrorHandling { // Profile Installed ICCIDAlready, - // Profile Mismatch - ICCIDMismatch, - // Insufficient Memory Space InsufficientMemorySpace, @@ -54,6 +51,12 @@ object SimplifiedErrorHandling { // The Network Timeout NetworkTimeout, + + // The network unreachable + NetworkUnreachable, + + // TLS Certificate Error + TLSCertificateError, } private val httpErrors = buildMap { @@ -75,9 +78,9 @@ object SimplifiedErrorHandling { exc.lpaErrorReason != "ES10B_ERROR_REASON_UNDEFINED" -> toSimplifiedLPAErrorReason(exc.lpaErrorReason) exc.lastHttpResponse?.rcode == 200 -> toSimplifiedHTTPResponse(exc.lastHttpResponse!!) exc.lastHttpException is UnknownHostException -> ErrorCode.UnknownHost - exc.lastHttpException is NoRouteToHostException -> ErrorCode.UnknownHost - exc.lastHttpException is PortUnreachableException -> ErrorCode.UnknownHost - exc.lastHttpException is SSLHandshakeException -> ErrorCode.UnknownHost + exc.lastHttpException is SSLHandshakeException -> ErrorCode.TLSCertificateError + exc.lastHttpException is NoRouteToHostException -> ErrorCode.NetworkUnreachable + exc.lastHttpException is PortUnreachableException -> ErrorCode.NetworkUnreachable exc.lastHttpException is SocketTimeoutException -> ErrorCode.NetworkTimeout else -> null } @@ -90,7 +93,6 @@ object SimplifiedErrorHandling { "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INSUFFICIENT_MEMORY_FOR_PROFILE" -> ErrorCode.InsufficientMemorySpace "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INTERRUPTION" -> ErrorCode.CardInternalError "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_PE_PROCESSING_ERROR" -> ErrorCode.CardInternalError - "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_MISMATCH" -> ErrorCode.ICCIDMismatch else -> null } From fe7b5300e38291c0ef9c0f2c1047138b1e245be0 Mon Sep 17 00:00:00 2001 From: septs Date: Wed, 16 Jul 2025 12:44:27 +0800 Subject: [PATCH 04/11] chore: add strings --- .../ui/wizard/SimplifiedErrorHandling.kt | 74 ++++++------------- app-common/src/main/res/values/strings.xml | 15 ++++ 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt index 7be35a6..ca46958 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt @@ -1,5 +1,7 @@ package im.angry.openeuicc.ui.wizard +import androidx.annotation.StringRes +import im.angry.openeuicc.common.R import net.typeblog.lpac_jni.LocalProfileAssistant import org.json.JSONObject import java.net.NoRouteToHostException @@ -9,59 +11,27 @@ import java.net.UnknownHostException import javax.net.ssl.SSLHandshakeException object SimplifiedErrorHandling { - enum class ErrorCode { - // Profile Installed - ICCIDAlready, - - // Insufficient Memory Space - InsufficientMemorySpace, - - // Unsupported Profile - UnsupportedProfile, - - // The card internal error - CardInternalError, - - // EID doesn't match the expected value. - EIDMismatch, - - // Expired The Download order has expired. - ProfileExpired, - - // Profile has not yet been released. - UnreleasedProfile, - - // MatchingID (AC_Token or EventID) is refused. - MatchingIDRefused, - - // Confirmation Code is missing. - ConfirmationCodeMissing, - - // Confirmation Code is refused. - ConfirmationCodeRefused, - - // The maximum number of retries for the Profile download order has been exceeded. - ConfirmationCodeRetriesExceeded, - - // The maximum number of retries for the Profile download order has been exceeded. - ProfileRetriesExceeded, - - // The FQDN is unknown - UnknownHost, - - // The Network Timeout - NetworkTimeout, - - // The network unreachable - NetworkUnreachable, - - // TLS Certificate Error - TLSCertificateError, + enum class ErrorCode(@StringRes val resId: Int) { + ICCIDAlready(R.string.download_wizard_error_iccid_already), + InsufficientMemory(R.string.download_wizard_error_insufficient_memory), + UnsupportedProfile(R.string.download_wizard_error_unsupported_profile), + CardInternalError(R.string.download_wizard_error_card_internal_error), + EIDMismatch(R.string.download_wizard_error_eid_mismatch), + UnreleasedProfile(R.string.download_wizard_error_profile_unreleased), + MatchingIDRefused(R.string.download_wizard_error_matching_id_refused), + ProfileRetriesExceeded(R.string.download_wizard_error_profile_retries_exceeded), + ConfirmationCodeMissing(R.string.download_wizard_error_confirmation_code_missing), + ConfirmationCodeRefused(R.string.download_wizard_error_confirmation_code_missing), + ConfirmationCodeRetriesExceeded(R.string.download_wizard_error_confirmation_code_retries_exceeded), + ProfileExpired(R.string.download_wizard_error_profile_expired), + UnknownHost(R.string.download_wizard_error_unknown_hostname), + NetworkUnreachable(R.string.download_wizard_error_network_unreachable), + TLSCertificateError(R.string.download_wizard_error_tls_certificate) } private val httpErrors = buildMap { // Stage: AuthenticateClient - put("8.1" to "4.8", ErrorCode.InsufficientMemorySpace) + put("8.1" to "4.8", ErrorCode.InsufficientMemory) put("8.1.1" to "3.8", ErrorCode.EIDMismatch) put("8.2" to "1.2", ErrorCode.UnreleasedProfile) put("8.2.6" to "3.8", ErrorCode.MatchingIDRefused) @@ -71,6 +41,8 @@ object SimplifiedErrorHandling { put("8.2.7" to "2.2", ErrorCode.ConfirmationCodeMissing) put("8.2.7" to "3.8", ErrorCode.ConfirmationCodeRefused) put("8.2.7" to "6.4", ErrorCode.ConfirmationCodeRetriesExceeded) + + // Stage: AuthenticateClient, GetBoundProfilePackage put("8.8.5" to "4.10", ErrorCode.ProfileExpired) } @@ -81,7 +53,7 @@ object SimplifiedErrorHandling { exc.lastHttpException is SSLHandshakeException -> ErrorCode.TLSCertificateError exc.lastHttpException is NoRouteToHostException -> ErrorCode.NetworkUnreachable exc.lastHttpException is PortUnreachableException -> ErrorCode.NetworkUnreachable - exc.lastHttpException is SocketTimeoutException -> ErrorCode.NetworkTimeout + exc.lastHttpException is SocketTimeoutException -> ErrorCode.NetworkUnreachable else -> null } @@ -90,7 +62,7 @@ object SimplifiedErrorHandling { "ES10B_ERROR_REASON_UNSUPPORTED_REMOTE_OPERATION_TYPE" -> ErrorCode.UnsupportedProfile "ES10B_ERROR_REASON_UNSUPPORTED_PROFILE_CLASS" -> ErrorCode.UnsupportedProfile "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_ICCID_ALREADY_EXISTS_ON_EUICC" -> ErrorCode.ICCIDAlready - "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INSUFFICIENT_MEMORY_FOR_PROFILE" -> ErrorCode.InsufficientMemorySpace + "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INSUFFICIENT_MEMORY_FOR_PROFILE" -> ErrorCode.InsufficientMemory "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_INTERRUPTION" -> ErrorCode.CardInternalError "ES10B_ERROR_REASON_INSTALL_FAILED_DUE_TO_PE_PROCESSING_ERROR" -> ErrorCode.CardInternalError else -> null diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index 38bb976..e872121 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -102,6 +102,21 @@ Last APDU exception: Save Diagnostics at %s + This eSIM profile is installed, Cannot be reinstalled. + Sorry, The remaining capacity of this eSIM chip cannot be used to install this eSIM profile. + Sorry, This eSIM profile is unsupported. + An error occurred inside the card. + This eSIM profile has been installed on another device. Please contact your carrier to reissue this eSIM profile. + This eSIM profile has been unreleased. Please contact your carrier to reissue this eSIM profile. + This eSIM activation code is invalid. Please contact your carrier for assistance. + The maximum number of retries for the eSIM profile has been exceeded. + Please enter the confirmation code to continue. + The confirmation code you entered is invalid. + This eSIM profile has been expired. Please contact your carrier to reissue this eSIM profile. + The maximum number of retries for the Confirmation Code has been exceeded. + Unknown SM-DP+ address + The current network is unreachable + TLS certificate error, this eSIM profile is not supported Logs have been saved to the selected path. Would you like to share the log through another app? From 2f1efffe3133368e0f398bf43e7fd6828b3d30e0 Mon Sep 17 00:00:00 2001 From: septs Date: Wed, 16 Jul 2025 17:41:49 +0800 Subject: [PATCH 05/11] chore: improve error handling --- .../im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt index ca46958..34b1cf5 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt @@ -69,9 +69,8 @@ object SimplifiedErrorHandling { } private fun toSimplifiedHTTPResponse(response: net.typeblog.lpac_jni.HttpInterface.HttpResponse): ErrorCode? { - val content = response.data.decodeToString() - if (!content.startsWith('{')) return null - val response = JSONObject(content) + if (response.data.first().toInt() != '{'.code) return null + val response = JSONObject(response.data.decodeToString()) if (!response.has("header")) return null val statusCodeData = response .getJSONObject("header") From e5693d80cf9da91ea7e68b6d9dcb313f07f6ded5 Mon Sep 17 00:00:00 2001 From: septs Date: Wed, 16 Jul 2025 22:45:19 +0800 Subject: [PATCH 06/11] chore: add strings --- .../ui/wizard/SimplifiedErrorHandling.kt | 52 +++++++++++++++---- app-common/src/main/res/values/strings.xml | 12 +++-- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt index 34b1cf5..011ab5a 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt @@ -11,19 +11,49 @@ import java.net.UnknownHostException import javax.net.ssl.SSLHandshakeException object SimplifiedErrorHandling { - enum class ErrorCode(@StringRes val resId: Int) { - ICCIDAlready(R.string.download_wizard_error_iccid_already), - InsufficientMemory(R.string.download_wizard_error_insufficient_memory), + enum class ErrorCode(@StringRes val titleResId: Int, @StringRes val suggestResId: Int? = null) { + ICCIDAlready( + R.string.download_wizard_error_iccid_already, + R.string.download_wizard_error_suggest_profile_installed + ), + InsufficientMemory( + R.string.download_wizard_error_insufficient_memory, + R.string.download_wizard_error_suggest_insufficient_memory + ), UnsupportedProfile(R.string.download_wizard_error_unsupported_profile), CardInternalError(R.string.download_wizard_error_card_internal_error), - EIDMismatch(R.string.download_wizard_error_eid_mismatch), - UnreleasedProfile(R.string.download_wizard_error_profile_unreleased), - MatchingIDRefused(R.string.download_wizard_error_matching_id_refused), - ProfileRetriesExceeded(R.string.download_wizard_error_profile_retries_exceeded), - ConfirmationCodeMissing(R.string.download_wizard_error_confirmation_code_missing), - ConfirmationCodeRefused(R.string.download_wizard_error_confirmation_code_missing), - ConfirmationCodeRetriesExceeded(R.string.download_wizard_error_confirmation_code_retries_exceeded), - ProfileExpired(R.string.download_wizard_error_profile_expired), + EIDMismatch( + R.string.download_wizard_error_eid_mismatch, + R.string.download_wizard_error_suggest_contact_reissue + ), + UnreleasedProfile( + R.string.download_wizard_error_profile_unreleased, + R.string.download_wizard_error_suggest_contact_reissue + ), + MatchingIDRefused( + R.string.download_wizard_error_matching_id_refused, + R.string.download_wizard_error_suggest_contact_carrier + ), + ProfileRetriesExceeded( + R.string.download_wizard_error_profile_retries_exceeded, + R.string.download_wizard_error_suggest_contact_carrier + ), + ConfirmationCodeMissing( + R.string.download_wizard_error_confirmation_code_missing, + R.string.download_wizard_error_suggest_contact_carrier + ), + ConfirmationCodeRefused( + R.string.download_wizard_error_confirmation_code_refused, + R.string.download_wizard_error_suggest_contact_carrier + ), + ConfirmationCodeRetriesExceeded( + R.string.download_wizard_error_confirmation_code_retries_exceeded, + R.string.download_wizard_error_suggest_contact_carrier + ), + ProfileExpired( + R.string.download_wizard_error_profile_expired, + R.string.download_wizard_error_suggest_contact_carrier + ), UnknownHost(R.string.download_wizard_error_unknown_hostname), NetworkUnreachable(R.string.download_wizard_error_network_unreachable), TLSCertificateError(R.string.download_wizard_error_tls_certificate) diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index e872121..b487e16 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -106,17 +106,21 @@ Sorry, The remaining capacity of this eSIM chip cannot be used to install this eSIM profile. Sorry, This eSIM profile is unsupported. An error occurred inside the card. - This eSIM profile has been installed on another device. Please contact your carrier to reissue this eSIM profile. - This eSIM profile has been unreleased. Please contact your carrier to reissue this eSIM profile. - This eSIM activation code is invalid. Please contact your carrier for assistance. + This eSIM profile has been installed on another device. + This eSIM profile has been unreleased. + This eSIM activation code is invalid. The maximum number of retries for the eSIM profile has been exceeded. Please enter the confirmation code to continue. The confirmation code you entered is invalid. - This eSIM profile has been expired. Please contact your carrier to reissue this eSIM profile. + This eSIM profile has been expired. The maximum number of retries for the Confirmation Code has been exceeded. Unknown SM-DP+ address The current network is unreachable TLS certificate error, this eSIM profile is not supported + You are trying to reinstall an already installed eSIM profile + Please delete an eSIM profile and try again + Please contact your carrier for assistance. + Please contact your carrier to reissue this eSIM profile. Logs have been saved to the selected path. Would you like to share the log through another app? From b2a9ee65c5d43b8c2a7ad7332aa9d04ecaff99ad Mon Sep 17 00:00:00 2001 From: septs Date: Wed, 16 Jul 2025 23:16:28 +0800 Subject: [PATCH 07/11] chore: add strings --- .../im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt | 5 ++++- app-common/src/main/res/values/strings.xml | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt index 011ab5a..723b3bb 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt @@ -55,7 +55,10 @@ object SimplifiedErrorHandling { R.string.download_wizard_error_suggest_contact_carrier ), UnknownHost(R.string.download_wizard_error_unknown_hostname), - NetworkUnreachable(R.string.download_wizard_error_network_unreachable), + NetworkUnreachable( + R.string.download_wizard_error_network_unreachable, + R.string.download_wizard_error_suggest_network_unreachable + ), TLSCertificateError(R.string.download_wizard_error_tls_certificate) } diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index b487e16..45ec3a7 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -121,6 +121,7 @@ Please delete an eSIM profile and try again Please contact your carrier for assistance. Please contact your carrier to reissue this eSIM profile. + The current network is unavailable. Please try again after changing the network. Logs have been saved to the selected path. Would you like to share the log through another app? From 52e24fb3210d52980ab9d7af0ba0fed8534d44e9 Mon Sep 17 00:00:00 2001 From: septs Date: Wed, 16 Jul 2025 23:17:22 +0800 Subject: [PATCH 08/11] chore: add strings --- .../ui/wizard/SimplifiedErrorHandling.kt | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt index 723b3bb..736e317 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt @@ -11,7 +11,7 @@ import java.net.UnknownHostException import javax.net.ssl.SSLHandshakeException object SimplifiedErrorHandling { - enum class ErrorCode(@StringRes val titleResId: Int, @StringRes val suggestResId: Int? = null) { + enum class ErrorCode(@StringRes val titleResId: Int, @StringRes val suggestResId: Int?) { ICCIDAlready( R.string.download_wizard_error_iccid_already, R.string.download_wizard_error_suggest_profile_installed @@ -20,8 +20,14 @@ object SimplifiedErrorHandling { R.string.download_wizard_error_insufficient_memory, R.string.download_wizard_error_suggest_insufficient_memory ), - UnsupportedProfile(R.string.download_wizard_error_unsupported_profile), - CardInternalError(R.string.download_wizard_error_card_internal_error), + UnsupportedProfile( + R.string.download_wizard_error_unsupported_profile, + null + ), + CardInternalError( + R.string.download_wizard_error_card_internal_error, + null + ), EIDMismatch( R.string.download_wizard_error_eid_mismatch, R.string.download_wizard_error_suggest_contact_reissue @@ -54,12 +60,18 @@ object SimplifiedErrorHandling { R.string.download_wizard_error_profile_expired, R.string.download_wizard_error_suggest_contact_carrier ), - UnknownHost(R.string.download_wizard_error_unknown_hostname), + UnknownHost( + R.string.download_wizard_error_unknown_hostname, + null + ), NetworkUnreachable( R.string.download_wizard_error_network_unreachable, R.string.download_wizard_error_suggest_network_unreachable ), - TLSCertificateError(R.string.download_wizard_error_tls_certificate) + TLSCertificateError( + R.string.download_wizard_error_tls_certificate, + null + ) } private val httpErrors = buildMap { From 1e8f782ca9eeb94385f93f1876ffea72ab351a79 Mon Sep 17 00:00:00 2001 From: septs Date: Thu, 17 Jul 2025 13:14:01 +0800 Subject: [PATCH 09/11] chore: improve http resposne handling --- .../openeuicc/ui/wizard/SimplifiedErrorHandling.kt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt index 736e317..e1d32e8 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt @@ -116,13 +116,12 @@ object SimplifiedErrorHandling { private fun toSimplifiedHTTPResponse(response: net.typeblog.lpac_jni.HttpInterface.HttpResponse): ErrorCode? { if (response.data.first().toInt() != '{'.code) return null val response = JSONObject(response.data.decodeToString()) - if (!response.has("header")) return null - val statusCodeData = response - .getJSONObject("header") - .getJSONObject("functionExecutionStatus") - .getJSONObject("statusCodeData") - val subjectCode = statusCodeData.getString("subjectCode") - val reasonCode = statusCodeData.getString("reasonCode") + val statusCodeData = response.optJSONObject("header") + ?.optJSONObject("functionExecutionStatus") + ?.optJSONObject("statusCodeData") + ?: return null + val subjectCode = statusCodeData.optString("subjectCode") + val reasonCode = statusCodeData.optString("reasonCode") return httpErrors[subjectCode to reasonCode] } } \ No newline at end of file From 2667e2340b589a2c7d0c1292db64ffada8a0aeab Mon Sep 17 00:00:00 2001 From: septs Date: Thu, 17 Jul 2025 13:28:04 +0800 Subject: [PATCH 10/11] chore: enhance error handling --- .../ui/wizard/SimplifiedErrorHandling.kt | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt index e1d32e8..b638c1f 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt @@ -6,9 +6,10 @@ import net.typeblog.lpac_jni.LocalProfileAssistant import org.json.JSONObject import java.net.NoRouteToHostException import java.net.PortUnreachableException +import java.net.SocketException import java.net.SocketTimeoutException import java.net.UnknownHostException -import javax.net.ssl.SSLHandshakeException +import javax.net.ssl.SSLException object SimplifiedErrorHandling { enum class ErrorCode(@StringRes val titleResId: Int, @StringRes val suggestResId: Int?) { @@ -68,7 +69,7 @@ object SimplifiedErrorHandling { R.string.download_wizard_error_network_unreachable, R.string.download_wizard_error_suggest_network_unreachable ), - TLSCertificateError( + TLSError( R.string.download_wizard_error_tls_certificate, null ) @@ -94,11 +95,8 @@ object SimplifiedErrorHandling { fun toSimplifiedDownloadError(exc: LocalProfileAssistant.ProfileDownloadException) = when { exc.lpaErrorReason != "ES10B_ERROR_REASON_UNDEFINED" -> toSimplifiedLPAErrorReason(exc.lpaErrorReason) exc.lastHttpResponse?.rcode == 200 -> toSimplifiedHTTPResponse(exc.lastHttpResponse!!) - exc.lastHttpException is UnknownHostException -> ErrorCode.UnknownHost - exc.lastHttpException is SSLHandshakeException -> ErrorCode.TLSCertificateError - exc.lastHttpException is NoRouteToHostException -> ErrorCode.NetworkUnreachable - exc.lastHttpException is PortUnreachableException -> ErrorCode.NetworkUnreachable - exc.lastHttpException is SocketTimeoutException -> ErrorCode.NetworkUnreachable + exc.lastHttpException != null -> toSimplifiedHTTPException(exc.lastHttpException!!) + exc.lastApduResponse != null -> toSimplifiedAPDUResponse(exc.lastApduResponse!!) else -> null } @@ -124,4 +122,21 @@ object SimplifiedErrorHandling { val reasonCode = statusCodeData.optString("reasonCode") return httpErrors[subjectCode to reasonCode] } -} \ No newline at end of file + + private fun toSimplifiedHTTPException(exc: Exception) = when (exc) { + is SSLException -> ErrorCode.TLSError + is UnknownHostException -> ErrorCode.UnknownHost + is NoRouteToHostException -> ErrorCode.NetworkUnreachable + is PortUnreachableException -> ErrorCode.NetworkUnreachable + is SocketTimeoutException -> ErrorCode.NetworkUnreachable + else -> null + } + + private fun toSimplifiedAPDUResponse(resp: ByteArray): ErrorCode? { + val isSuccess = resp.size >= 2 && + resp[resp.size - 2] == 0x90.toByte() && + resp[resp.size - 1] == 0x00.toByte() + if (isSuccess) return null + return ErrorCode.CardInternalError + } +} From 1ca48699a851351c74bc9cf0940f626c0a70a046 Mon Sep 17 00:00:00 2001 From: septs Date: Thu, 17 Jul 2025 13:56:51 +0800 Subject: [PATCH 11/11] chore: detect connection reset --- .../im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt index b638c1f..14a4f57 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/SimplifiedErrorHandling.kt @@ -129,6 +129,9 @@ object SimplifiedErrorHandling { is NoRouteToHostException -> ErrorCode.NetworkUnreachable is PortUnreachableException -> ErrorCode.NetworkUnreachable is SocketTimeoutException -> ErrorCode.NetworkUnreachable + is SocketException -> exc.message + ?.contains("Connection reset", ignoreCase = true) + ?.let { if (it) ErrorCode.NetworkUnreachable else null } else -> null }