From 1743e20fdccfbd41127f6b066d62502f1f1fc4a3 Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 05:11:25 +0800 Subject: [PATCH 01/20] feat: stricted imei checking --- .../wizard/DownloadWizardDetailsFragment.kt | 43 +++++++++++++++++-- app-common/src/main/res/values/strings.xml | 4 ++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index 5fa8002..ec59d6e 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -48,9 +48,8 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF matchingId = view.requireViewById(R.id.profile_download_code) confirmationCode = view.requireViewById(R.id.profile_download_confirmation_code) imei = view.requireViewById(R.id.profile_download_imei) - smdp.editText!!.addTextChangedListener { - updateInputCompleteness() - } + smdp.editText!!.addTextChangedListener { updateInputCompleteness() } + imei.editText!!.addTextChangedListener { updateInputCompleteness() } return view } @@ -69,7 +68,43 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF } private fun updateInputCompleteness() { - inputComplete = Patterns.DOMAIN_NAME.matcher(smdp.editText!!.text).matches() + validate() + val errors = arrayOf( + smdp.error, + imei.error, + ) + inputComplete = errors.all { it == null } refreshButtons() } + + private fun validate() { + smdp.error = smdp.editText!!.text?.let { + when { + it.isEmpty() -> getString(R.string.download_wizard_error_address_required) + it.contains("://") -> getString(R.string.download_wizard_error_cannot_url) + Patterns.DOMAIN_NAME.matcher(it).matches() -> null + else -> getString(R.string.download_wizard_error_address_invalid_format) + } + } + imei.error = imei.editText!!.text?.let { + when { + it.isEmpty() -> null + it.length == 15 && luhnValid(it) -> null + else -> getString(R.string.download_wizard_error_imei_invalid_format) + } + } + } +} + +private fun luhnValid(number: CharSequence, mod: Int = 10): Boolean { + if (!number.all(Char::isDigit)) return false + var checksum = 0 + for (i in number.length - 1 downTo 0 step 2) { + checksum += number[i] - '0' + } + for (i in number.length - 2 downTo 0 step 2) { + val n: Int = (number[i] - '0') * 2 + checksum += if (n > 9) n - 9 else n + } + return checksum % mod == 0 } \ No newline at end of file diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index a45ce1f..13d765f 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -98,6 +98,10 @@ Last APDU exception: Save Diagnostics at %s + Server address is required + Server address not is URL + Invalid Server address + Invalid IMEI format Logs have been saved to the selected path. Would you like to share the log through another app? -- 2.45.3 From cf319dc064d2d8cbb0dea0b72021e990f8b80da4 Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 08:12:27 +0800 Subject: [PATCH 02/20] feat: add error handling --- .../wizard/DownloadWizardDetailsFragment.kt | 19 ++++++++++++++++++- .../res/layout/fragment_download_details.xml | 4 ++++ app-common/src/main/res/values/strings.xml | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index ec59d6e..268e8ef 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -49,6 +49,7 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF confirmationCode = view.requireViewById(R.id.profile_download_confirmation_code) imei = view.requireViewById(R.id.profile_download_imei) smdp.editText!!.addTextChangedListener { updateInputCompleteness() } + matchingId.editText!!.addTextChangedListener { updateInputCompleteness() } imei.editText!!.addTextChangedListener { updateInputCompleteness() } return view } @@ -71,6 +72,7 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF validate() val errors = arrayOf( smdp.error, + matchingId.error, imei.error, ) inputComplete = errors.all { it == null } @@ -82,10 +84,17 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF when { it.isEmpty() -> getString(R.string.download_wizard_error_address_required) it.contains("://") -> getString(R.string.download_wizard_error_cannot_url) - Patterns.DOMAIN_NAME.matcher(it).matches() -> null + isFQDN(it) -> null else -> getString(R.string.download_wizard_error_address_invalid_format) } } + matchingId.error = matchingId.editText!!.text?.let { + when { + it.isEmpty() -> null + isMatchingID(it) -> null + else -> getString(R.string.download_wizard_error_matching_id_invalid_format) + } + } imei.error = imei.editText!!.text?.let { when { it.isEmpty() -> null @@ -96,6 +105,14 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF } } +private fun isFQDN(input: CharSequence) = + input.length < 255 && input.count { it == '.' } > 2 && input.split('.').all { part -> + part.isNotEmpty() && part.length < 64 && part.all { it.isLetterOrDigit() || it == '-' } + } + +private fun isMatchingID(input: CharSequence) = + input.all { it.isLetterOrDigit() || it == '-' } + private fun luhnValid(number: CharSequence, mod: Int = 10): Boolean { if (!number.all(Char::isDigit)) return false var checksum = 0 diff --git a/app-common/src/main/res/layout/fragment_download_details.xml b/app-common/src/main/res/layout/fragment_download_details.xml index 1a25075..1f74458 100644 --- a/app-common/src/main/res/layout/fragment_download_details.xml +++ b/app-common/src/main/res/layout/fragment_download_details.xml @@ -29,6 +29,7 @@ android:id="@+id/profile_download_server" android:layout_width="0dp" android:layout_height="wrap_content" + app:errorEnabled="true" android:hint="@string/profile_download_server"> App Version Source Code https://gitea.angry.im/PeterCxy/OpenEUICC + Invalid Matching ID format \ No newline at end of file -- 2.45.3 From 9777e22b1b861f9c20d8278791205e152d456361 Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 08:19:51 +0800 Subject: [PATCH 03/20] chore: reduce imports --- .../angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index 268e8ef..b825f2f 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -1,7 +1,6 @@ package im.angry.openeuicc.ui.wizard import android.os.Bundle -import android.util.Patterns import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -- 2.45.3 From 2435b2132e899ead8f9e4b95643d61a956b61367 Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 11:07:12 +0800 Subject: [PATCH 04/20] refacator: luhnValid --- .../ui/wizard/DownloadWizardDetailsFragment.kt | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index b825f2f..f4d5ea9 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -112,15 +112,8 @@ private fun isFQDN(input: CharSequence) = private fun isMatchingID(input: CharSequence) = input.all { it.isLetterOrDigit() || it == '-' } -private fun luhnValid(number: CharSequence, mod: Int = 10): Boolean { - if (!number.all(Char::isDigit)) return false - var checksum = 0 - for (i in number.length - 1 downTo 0 step 2) { - checksum += number[i] - '0' - } - for (i in number.length - 2 downTo 0 step 2) { - val n: Int = (number[i] - '0') * 2 - checksum += if (n > 9) n - 9 else n - } - return checksum % mod == 0 -} \ No newline at end of file +private fun luhnValid(input: CharSequence) = input.all(Char::isDigit) && input + .map(Char::digitToInt) + .mapIndexed { index, digit -> if (index % 2 == 0) digit else digit * 2 } + .fold(0) { sum, n -> sum + if (n > 9) n - 9 else n } + .rem(10) == 0 \ No newline at end of file -- 2.45.3 From d9dc029ab42995a1007ccecf1dd0a9b9231d1606 Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 11:09:00 +0800 Subject: [PATCH 05/20] refacator: luhnValid --- .../angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index f4d5ea9..74c289d 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -115,5 +115,5 @@ private fun isMatchingID(input: CharSequence) = private fun luhnValid(input: CharSequence) = input.all(Char::isDigit) && input .map(Char::digitToInt) .mapIndexed { index, digit -> if (index % 2 == 0) digit else digit * 2 } - .fold(0) { sum, n -> sum + if (n > 9) n - 9 else n } + .sumOf { if (it > 9) it - 9 else it } .rem(10) == 0 \ No newline at end of file -- 2.45.3 From 6a71f5828ad9ba2c8bc5b6cfeca4599b9ef5b288 Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 11:21:41 +0800 Subject: [PATCH 06/20] refactor: improve is fqdn and matching id --- .../ui/wizard/DownloadWizardDetailsFragment.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index 74c289d..7d1bc8b 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -89,7 +89,6 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF } matchingId.error = matchingId.editText!!.text?.let { when { - it.isEmpty() -> null isMatchingID(it) -> null else -> getString(R.string.download_wizard_error_matching_id_invalid_format) } @@ -104,13 +103,19 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF } } -private fun isFQDN(input: CharSequence) = - input.length < 255 && input.count { it == '.' } > 2 && input.split('.').all { part -> - part.isNotEmpty() && part.length < 64 && part.all { it.isLetterOrDigit() || it == '-' } +private fun isFQDN(input: CharSequence): Boolean { + if (input.isEmpty() || input.length > 255) return false + if (!input.contains('.')) return false + for (label in input.split('.')) { + if (label.isEmpty() || label.length > 63) return false + if (label.all { it.isLetterOrDigit() || it == '-' }) continue + return false } + return true +} private fun isMatchingID(input: CharSequence) = - input.all { it.isLetterOrDigit() || it == '-' } + input.isEmpty() || input.all { it.isLetterOrDigit() || it == '-' } private fun luhnValid(input: CharSequence) = input.all(Char::isDigit) && input .map(Char::digitToInt) -- 2.45.3 From d765cbe461b45a09270674587965b0fa619c59e3 Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 11:36:21 +0800 Subject: [PATCH 07/20] chore: imei error handling --- .../openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt | 4 +++- app-common/src/main/res/values/strings.xml | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index 7d1bc8b..a6ffe31 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -96,7 +96,9 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF imei.error = imei.editText!!.text?.let { when { it.isEmpty() -> null - it.length == 15 && luhnValid(it) -> null + !it.all(Char::isDigit) -> getString(R.string.download_wizard_error_imei_not_numeric) + it.length != 15 -> getString(R.string.download_wizard_error_imei_length, it.length) + luhnValid(it) -> null else -> getString(R.string.download_wizard_error_imei_invalid_format) } } diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index bbcb9e0..5ebaeb9 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -101,7 +101,10 @@ Server address is required Server address not is URL Invalid Server address - Invalid IMEI format + Invalid Matching ID format + The IMEI must be numeric + The IMEI length error (expected: 15, actual: %d) + The IMEI format check failed Logs have been saved to the selected path. Would you like to share the log through another app? @@ -183,5 +186,4 @@ App Version Source Code https://gitea.angry.im/PeterCxy/OpenEUICC - Invalid Matching ID format \ No newline at end of file -- 2.45.3 From 5be52633529fb2335ed2734876a233ecbb12066e Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 13:22:36 +0800 Subject: [PATCH 08/20] chore: simplify error infos --- .../wizard/DownloadWizardDetailsFragment.kt | 28 +++++++------------ app-common/src/main/res/values/strings.xml | 8 ++---- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index a6ffe31..4e95fba 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -80,27 +80,19 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF private fun validate() { smdp.error = smdp.editText!!.text?.let { - when { - it.isEmpty() -> getString(R.string.download_wizard_error_address_required) - it.contains("://") -> getString(R.string.download_wizard_error_cannot_url) - isFQDN(it) -> null - else -> getString(R.string.download_wizard_error_address_invalid_format) - } + if (it.isEmpty()) return@let getString(R.string.download_wizard_error_address_required) + if (it.contains("://")) return@let getString(R.string.download_wizard_error_cannot_url) + if (!isFQDN(it)) return@let getString(R.string.download_wizard_error_address_incorrect_format) + null } matchingId.error = matchingId.editText!!.text?.let { - when { - isMatchingID(it) -> null - else -> getString(R.string.download_wizard_error_matching_id_invalid_format) - } + if (isMatchingID(it)) return@let null + getString(R.string.download_wizard_error_matching_id_incorrect_format) } imei.error = imei.editText!!.text?.let { - when { - it.isEmpty() -> null - !it.all(Char::isDigit) -> getString(R.string.download_wizard_error_imei_not_numeric) - it.length != 15 -> getString(R.string.download_wizard_error_imei_length, it.length) - luhnValid(it) -> null - else -> getString(R.string.download_wizard_error_imei_invalid_format) - } + if (it.isEmpty()) return@let null + if (it.length == 15 && it.all(Char::isDigit) && luhnValid(it)) return@let null + getString(R.string.download_wizard_error_imei_incorrect_format) } } } @@ -119,7 +111,7 @@ private fun isFQDN(input: CharSequence): Boolean { private fun isMatchingID(input: CharSequence) = input.isEmpty() || input.all { it.isLetterOrDigit() || it == '-' } -private fun luhnValid(input: CharSequence) = input.all(Char::isDigit) && input +private fun luhnValid(input: CharSequence) = input .map(Char::digitToInt) .mapIndexed { index, digit -> if (index % 2 == 0) digit else digit * 2 } .sumOf { if (it > 9) it - 9 else it } diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index 5ebaeb9..ae3fa51 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -100,11 +100,9 @@ Diagnostics at %s Server address is required Server address not is URL - Invalid Server address - Invalid Matching ID format - The IMEI must be numeric - The IMEI length error (expected: 15, actual: %d) - The IMEI format check failed + Incorrect Server address + Incorrect Matching ID format + Incorrect IMEI format Logs have been saved to the selected path. Would you like to share the log through another app? -- 2.45.3 From f6f21494c56e100ef7ecf7d8f0a1313947d15737 Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 15:24:57 +0800 Subject: [PATCH 09/20] refactor: download wizard details form --- .../wizard/DownloadWizardDetailsFragment.kt | 24 ++++++++ .../main/res/drawable/ic_format_number.xml | 11 ++++ .../src/main/res/drawable/ic_format_text.xml | 11 ++++ .../res/layout/fragment_download_details.xml | 56 +++++++++---------- 4 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 app-common/src/main/res/drawable/ic_format_number.xml create mode 100644 app-common/src/main/res/drawable/ic_format_text.xml diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index 4e95fba..5978250 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -1,9 +1,13 @@ package im.angry.openeuicc.ui.wizard import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.inputmethod.EditorInfo +import androidx.annotation.DrawableRes +import androidx.core.content.ContextCompat import androidx.core.widget.addTextChangedListener import com.google.android.material.textfield.TextInputLayout import im.angry.openeuicc.common.R @@ -49,6 +53,7 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF imei = view.requireViewById(R.id.profile_download_imei) smdp.editText!!.addTextChangedListener { updateInputCompleteness() } matchingId.editText!!.addTextChangedListener { updateInputCompleteness() } + confirmationCode.setEndIconOnClickListener { onConfirmationCodeEndIconClick(confirmationCode) } imei.editText!!.addTextChangedListener { updateInputCompleteness() } return view } @@ -95,6 +100,25 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF getString(R.string.download_wizard_error_imei_incorrect_format) } } + + private fun onConfirmationCodeEndIconClick(layout: TextInputLayout) { + val editText = layout.editText ?: return + fun getDrawable(@DrawableRes resId: Int) = + ContextCompat.getDrawable(requireActivity(), resId) + layout.endIconDrawable = when (editText.inputType) { + EditorInfo.TYPE_CLASS_NUMBER -> { + editText.inputType = EditorInfo.TYPE_CLASS_TEXT + getDrawable(R.drawable.ic_format_text) + } + + EditorInfo.TYPE_CLASS_TEXT -> { + editText.inputType = EditorInfo.TYPE_CLASS_NUMBER + getDrawable(R.drawable.ic_format_number) + } + + else -> null + } + } } private fun isFQDN(input: CharSequence): Boolean { diff --git a/app-common/src/main/res/drawable/ic_format_number.xml b/app-common/src/main/res/drawable/ic_format_number.xml new file mode 100644 index 0000000..bbb8a85 --- /dev/null +++ b/app-common/src/main/res/drawable/ic_format_number.xml @@ -0,0 +1,11 @@ + + + diff --git a/app-common/src/main/res/drawable/ic_format_text.xml b/app-common/src/main/res/drawable/ic_format_text.xml new file mode 100644 index 0000000..6a269f1 --- /dev/null +++ b/app-common/src/main/res/drawable/ic_format_text.xml @@ -0,0 +1,11 @@ + + + diff --git a/app-common/src/main/res/layout/fragment_download_details.xml b/app-common/src/main/res/layout/fragment_download_details.xml index 1f74458..24023d1 100644 --- a/app-common/src/main/res/layout/fragment_download_details.xml +++ b/app-common/src/main/res/layout/fragment_download_details.xml @@ -11,32 +11,32 @@ + android:hint="@string/profile_download_server" + app:errorEnabled="true"> + android:layout_height="match_parent" + android:inputType="text" + android:maxLines="1" /> @@ -45,14 +45,13 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:hint="@string/profile_download_code" - app:errorEnabled="true" - app:passwordToggleEnabled="true"> + app:errorEnabled="true"> + android:inputType="text" + android:maxLines="1" /> @@ -61,14 +60,16 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:hint="@string/profile_download_confirmation_code" - app:errorEnabled="true" - app:passwordToggleEnabled="true"> + app:endIconCheckable="true" + app:endIconDrawable="@drawable/ic_format_number" + app:endIconMode="custom" + app:errorEnabled="true"> + android:inputType="number" + android:maxLines="1" /> @@ -79,29 +80,28 @@ android:layout_marginTop="15dp" android:layout_marginBottom="6dp" android:hint="@string/profile_download_imei" - app:errorEnabled="true" - app:passwordToggleEnabled="true"> + app:errorEnabled="true"> + android:inputType="number" + android:maxLines="1" /> + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/download_wizard_details_title" /> -- 2.45.3 From 87d43e96be2d327a7ce782622f7aa99a8efee010 Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 15:26:00 +0800 Subject: [PATCH 10/20] chore: cleanup imports --- .../angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index 5978250..59fe7d5 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -1,7 +1,6 @@ package im.angry.openeuicc.ui.wizard import android.os.Bundle -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -- 2.45.3 From 9ce531d794cf02ca3530ae75a8fb93fb4ef93c82 Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 17:11:47 +0800 Subject: [PATCH 11/20] feat: fold error height --- .../ui/wizard/DownloadWizardDetailsFragment.kt | 9 +++------ .../main/res/layout/fragment_download_details.xml | 12 ++++-------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index 59fe7d5..00676b7 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -73,12 +73,9 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF private fun updateInputCompleteness() { validate() - val errors = arrayOf( - smdp.error, - matchingId.error, - imei.error, - ) - inputComplete = errors.all { it == null } + val layouts = arrayOf(smdp, matchingId, imei) + for (layout in layouts) layout.isErrorEnabled = layout.error != null + inputComplete = layouts.all { it.error == null } refreshButtons() } diff --git a/app-common/src/main/res/layout/fragment_download_details.xml b/app-common/src/main/res/layout/fragment_download_details.xml index 24023d1..378b39a 100644 --- a/app-common/src/main/res/layout/fragment_download_details.xml +++ b/app-common/src/main/res/layout/fragment_download_details.xml @@ -29,8 +29,7 @@ android:id="@+id/profile_download_server" android:layout_width="0dp" android:layout_height="wrap_content" - android:hint="@string/profile_download_server" - app:errorEnabled="true"> + android:hint="@string/profile_download_server"> + android:hint="@string/profile_download_code"> + app:endIconMode="custom"> + android:hint="@string/profile_download_imei"> Date: Fri, 7 Mar 2025 19:53:12 +0800 Subject: [PATCH 12/20] fix: update vector drawable attributes for better visibility --- app-common/src/main/res/drawable/ic_format_number.xml | 4 ++-- app-common/src/main/res/drawable/ic_format_text.xml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app-common/src/main/res/drawable/ic_format_number.xml b/app-common/src/main/res/drawable/ic_format_number.xml index bbb8a85..bed33e3 100644 --- a/app-common/src/main/res/drawable/ic_format_number.xml +++ b/app-common/src/main/res/drawable/ic_format_number.xml @@ -2,10 +2,10 @@ android:width="24dp" android:height="24dp" android:alpha="0.8" - android:tint="#FFFFFF" + android:tint="@android:color/white" android:viewportWidth="24" android:viewportHeight="24"> + android:pathData="M7 15H5.5v-4.5H4V9h3v6zm6.5-1.5h-3v-1h2c0.55 0 1-0.45 1-1V10c0-0.55-0.45-1-1-1H9v1.5h3v1h-2c-0.55 0-1 0.45-1 1V15h4.5v-1.5zm6 0.5v-4c0-0.55-0.45-1-1-1H15v1.5h3v1h-2v1h2v1h-3V15h3.5c0.55 0 1-0.45 1-1z" /> diff --git a/app-common/src/main/res/drawable/ic_format_text.xml b/app-common/src/main/res/drawable/ic_format_text.xml index 6a269f1..8a376a7 100644 --- a/app-common/src/main/res/drawable/ic_format_text.xml +++ b/app-common/src/main/res/drawable/ic_format_text.xml @@ -1,11 +1,11 @@ + android:pathData="M21 11h-1.5v-0.5h-2v3h2V13H21v1c0 0.55-0.45 1-1 1h-3c-0.55 0-1-0.45-1-1v-4c0-0.55 0.45-1 1-1h3c0.55 0 1 0.45 1 1v1zM8 10v5H6.5v-1.5h-2V15H3v-5c0-0.55 0.45-1 1-1h3c0.55 0 1 0.45 1 1zm-1.5 0.5h-2V12h2v-1.5zm7 1.5c0.55 0 1 0.45 1 1v1c0 0.55-0.45 1-1 1h-4V9h4c0.55 0 1 0.45 1 1v1c0 0.55-0.45 1-1 1zM11 10.5v0.75h2V10.5h-2zm2 2.25h-2v0.75h2v-0.75z" /> -- 2.45.3 From d417eac08d7c68a33fc45bbff0ffd0fa742eab0b Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 7 Mar 2025 19:57:30 +0800 Subject: [PATCH 13/20] fix: change input type to textVisiblePassword for better security --- app-common/src/main/res/layout/fragment_download_details.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app-common/src/main/res/layout/fragment_download_details.xml b/app-common/src/main/res/layout/fragment_download_details.xml index 378b39a..d492643 100644 --- a/app-common/src/main/res/layout/fragment_download_details.xml +++ b/app-common/src/main/res/layout/fragment_download_details.xml @@ -34,7 +34,7 @@ @@ -48,7 +48,7 @@ -- 2.45.3 From 0820b92dbba599e88a4a0d4e1654e347aa840fc1 Mon Sep 17 00:00:00 2001 From: septs Date: Sat, 8 Mar 2025 08:32:05 +0800 Subject: [PATCH 14/20] fix: update input type for better password visibility --- .../wizard/DownloadWizardDetailsFragment.kt | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index 00676b7..e45c70c 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -1,6 +1,7 @@ package im.angry.openeuicc.ui.wizard import android.os.Bundle +import android.text.InputType import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -101,17 +102,14 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF val editText = layout.editText ?: return fun getDrawable(@DrawableRes resId: Int) = ContextCompat.getDrawable(requireActivity(), resId) - layout.endIconDrawable = when (editText.inputType) { - EditorInfo.TYPE_CLASS_NUMBER -> { - editText.inputType = EditorInfo.TYPE_CLASS_TEXT - getDrawable(R.drawable.ic_format_text) - } - - EditorInfo.TYPE_CLASS_TEXT -> { - editText.inputType = EditorInfo.TYPE_CLASS_NUMBER - getDrawable(R.drawable.ic_format_number) - } - + editText.inputType = when (editText.inputType and EditorInfo.TYPE_MASK_CLASS) { + EditorInfo.TYPE_CLASS_NUMBER -> InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD + EditorInfo.TYPE_CLASS_TEXT -> InputType.TYPE_CLASS_NUMBER + else -> EditorInfo.TYPE_NULL + } + layout.endIconDrawable = when (editText.inputType and EditorInfo.TYPE_MASK_CLASS) { + EditorInfo.TYPE_CLASS_NUMBER -> getDrawable(R.drawable.ic_format_number) + EditorInfo.TYPE_CLASS_TEXT -> getDrawable(R.drawable.ic_format_text) else -> null } } -- 2.45.3 From b3145d6847c31ca9f7ef4a76fdb0671b68596a98 Mon Sep 17 00:00:00 2001 From: septs Date: Sat, 8 Mar 2025 08:48:53 +0800 Subject: [PATCH 15/20] fix: add error message for incorrect confirmation code format --- .../ui/wizard/DownloadWizardDetailsFragment.kt | 16 +++++++++++++++- app-common/src/main/res/values/strings.xml | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index e45c70c..7286446 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -53,8 +53,12 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF imei = view.requireViewById(R.id.profile_download_imei) smdp.editText!!.addTextChangedListener { updateInputCompleteness() } matchingId.editText!!.addTextChangedListener { updateInputCompleteness() } - confirmationCode.setEndIconOnClickListener { onConfirmationCodeEndIconClick(confirmationCode) } + confirmationCode.editText!!.addTextChangedListener { updateInputCompleteness() } imei.editText!!.addTextChangedListener { updateInputCompleteness() } + confirmationCode.setEndIconOnClickListener { + onConfirmationCodeEndIconClick(confirmationCode) + validate() + } return view } @@ -91,6 +95,16 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF if (isMatchingID(it)) return@let null getString(R.string.download_wizard_error_matching_id_incorrect_format) } + confirmationCode.error = confirmationCode.editText!!.let { + if (it.text.isEmpty()) return@let null + val passed = when (it.inputType and EditorInfo.TYPE_MASK_CLASS) { + EditorInfo.TYPE_CLASS_NUMBER -> it.text.all(Char::isDigit) + EditorInfo.TYPE_CLASS_TEXT -> true + else -> false + } + if (passed) return@let null + getString(R.string.download_wizard_error_confirmation_code_incorrect_format) + } imei.error = imei.editText!!.text?.let { if (it.isEmpty()) return@let null if (it.length == 15 && it.all(Char::isDigit) && luhnValid(it)) return@let null diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index ae3fa51..6f9a873 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -102,6 +102,7 @@ Server address not is URL Incorrect Server address Incorrect Matching ID format + Incorrect Confirmation Code format Incorrect IMEI format Logs have been saved to the selected path. Would you like to share the log through another app? -- 2.45.3 From 8f6c317a06a8cc7ba9e52492aa94b56bc9e2ec06 Mon Sep 17 00:00:00 2001 From: septs Date: Sat, 8 Mar 2025 09:09:46 +0800 Subject: [PATCH 16/20] fix: set typeface to monospace for better readability in input fields --- .../main/res/layout/fragment_download_details.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app-common/src/main/res/layout/fragment_download_details.xml b/app-common/src/main/res/layout/fragment_download_details.xml index d492643..524bd35 100644 --- a/app-common/src/main/res/layout/fragment_download_details.xml +++ b/app-common/src/main/res/layout/fragment_download_details.xml @@ -35,7 +35,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:inputType="textVisiblePassword" - android:maxLines="1" /> + android:maxLines="1" + android:typeface="monospace" /> @@ -49,7 +50,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:inputType="textVisiblePassword" - android:maxLines="1" /> + android:maxLines="1" + android:typeface="monospace" /> @@ -66,7 +68,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:inputType="number" - android:maxLines="1" /> + android:maxLines="1" + android:typeface="monospace" /> @@ -82,7 +85,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:inputType="number" - android:maxLines="1" /> + android:maxLines="1" + android:typeface="monospace" /> -- 2.45.3 From f96fffabf0f16994b0d6c5e509c89d7813aee548 Mon Sep 17 00:00:00 2001 From: septs Date: Sat, 8 Mar 2025 11:32:00 +0800 Subject: [PATCH 17/20] fix: update error messages for download wizard details validation --- .../ui/wizard/DownloadWizardDetailsFragment.kt | 14 +++++++------- app-common/src/main/res/values/strings.xml | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index 7286446..bd42336 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -86,29 +86,29 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF private fun validate() { smdp.error = smdp.editText!!.text?.let { - if (it.isEmpty()) return@let getString(R.string.download_wizard_error_address_required) - if (it.contains("://")) return@let getString(R.string.download_wizard_error_cannot_url) - if (!isFQDN(it)) return@let getString(R.string.download_wizard_error_address_incorrect_format) + if (it.isEmpty()) return@let getString(R.string.download_wizard_details_error_address_required) + if (it.contains("://")) return@let getString(R.string.download_wizard_details_error_cannot_url) + if (!isFQDN(it)) return@let getString(R.string.download_wizard_details_error_address_incorrect_format) null } matchingId.error = matchingId.editText!!.text?.let { if (isMatchingID(it)) return@let null - getString(R.string.download_wizard_error_matching_id_incorrect_format) + getString(R.string.download_wizard_details_error_matching_id_incorrect_format) } confirmationCode.error = confirmationCode.editText!!.let { if (it.text.isEmpty()) return@let null val passed = when (it.inputType and EditorInfo.TYPE_MASK_CLASS) { EditorInfo.TYPE_CLASS_NUMBER -> it.text.all(Char::isDigit) EditorInfo.TYPE_CLASS_TEXT -> true - else -> false + else -> return@let null } if (passed) return@let null - getString(R.string.download_wizard_error_confirmation_code_incorrect_format) + getString(R.string.download_wizard_details_error_confirmation_code_incorrect_format) } imei.error = imei.editText!!.text?.let { if (it.isEmpty()) return@let null if (it.length == 15 && it.all(Char::isDigit) && luhnValid(it)) return@let null - getString(R.string.download_wizard_error_imei_incorrect_format) + getString(R.string.download_wizard_details_error_imei_incorrect_format) } } diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index 6f9a873..28ed78e 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -81,6 +81,12 @@ Load from Clipboard Enter manually Input or confirm details for downloading your eSIM: + Server address is required + Server address not is URL + Incorrect Server address + Incorrect Matching ID format + Incorrect Confirmation Code format + Incorrect IMEI format Downloading your eSIM… Preparing Establishing connection to server @@ -98,12 +104,6 @@ Last APDU exception: Save Diagnostics at %s - Server address is required - Server address not is URL - Incorrect Server address - Incorrect Matching ID format - Incorrect Confirmation Code format - Incorrect IMEI format Logs have been saved to the selected path. Would you like to share the log through another app? -- 2.45.3 From eb95e2d756a65b2ae2a58892d4861d344d62452f Mon Sep 17 00:00:00 2001 From: septs Date: Sat, 8 Mar 2025 12:05:37 +0800 Subject: [PATCH 18/20] fix: enhance validation for download address format with host and port checks --- .../ui/wizard/DownloadWizardDetailsFragment.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index bd42336..e465c1c 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -88,8 +88,9 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF smdp.error = smdp.editText!!.text?.let { if (it.isEmpty()) return@let getString(R.string.download_wizard_details_error_address_required) if (it.contains("://")) return@let getString(R.string.download_wizard_details_error_cannot_url) - if (!isFQDN(it)) return@let getString(R.string.download_wizard_details_error_address_incorrect_format) - null + val (host, port) = splitHostPort(it) + if (isFQDN(host) && port in 1..65535) return@let null + getString(R.string.download_wizard_details_error_address_incorrect_format) } matchingId.error = matchingId.editText!!.text?.let { if (isMatchingID(it)) return@let null @@ -129,6 +130,15 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF } } +private fun splitHostPort(input: CharSequence): Pair { + val portIndex = input.lastIndexOf(':') + if (portIndex == -1) return Pair(input, 443) + return Pair( + input.slice(0 until portIndex), + input.slice(portIndex + 1 until input.length).toString().toIntOrNull() + ) +} + private fun isFQDN(input: CharSequence): Boolean { if (input.isEmpty() || input.length > 255) return false if (!input.contains('.')) return false -- 2.45.3 From 3ab0bada91f5480e3bb9f781a1964ce433d531c9 Mon Sep 17 00:00:00 2001 From: septs Date: Sat, 8 Mar 2025 12:21:38 +0800 Subject: [PATCH 19/20] fix: include confirmation code in input completeness validation --- .../openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index e465c1c..6d9ca39 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -1,7 +1,9 @@ package im.angry.openeuicc.ui.wizard import android.os.Bundle +import android.text.Editable import android.text.InputType +import android.text.TextWatcher import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -11,6 +13,7 @@ import androidx.core.content.ContextCompat import androidx.core.widget.addTextChangedListener import com.google.android.material.textfield.TextInputLayout import im.angry.openeuicc.common.R +import org.w3c.dom.Text class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepFragment() { private var inputComplete = false @@ -78,7 +81,7 @@ class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepF private fun updateInputCompleteness() { validate() - val layouts = arrayOf(smdp, matchingId, imei) + val layouts = arrayOf(smdp, matchingId, confirmationCode, imei) for (layout in layouts) layout.isErrorEnabled = layout.error != null inputComplete = layouts.all { it.error == null } refreshButtons() -- 2.45.3 From f2d9ecb93b17e1475de2cfbd45499eeee38183c4 Mon Sep 17 00:00:00 2001 From: septs Date: Sat, 8 Mar 2025 14:42:11 +0800 Subject: [PATCH 20/20] fix: include confirmation code in input completeness validation --- .../angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt index 6d9ca39..3b6a99d 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardDetailsFragment.kt @@ -1,9 +1,7 @@ package im.angry.openeuicc.ui.wizard import android.os.Bundle -import android.text.Editable import android.text.InputType -import android.text.TextWatcher import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -13,7 +11,6 @@ import androidx.core.content.ContextCompat import androidx.core.widget.addTextChangedListener import com.google.android.material.textfield.TextInputLayout import im.angry.openeuicc.common.R -import org.w3c.dom.Text class DownloadWizardDetailsFragment : DownloadWizardActivity.DownloadWizardStepFragment() { private var inputComplete = false -- 2.45.3