From 4b842c4afeaec33c9f9304ceac834a6d39d85a7d Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sat, 23 Mar 2024 20:56:42 -0400 Subject: [PATCH] feat: Add an "verdict" to compatibility checks --- .../openeuicc/util/CompatibilityCheck.kt | 69 ++++++++++++++++--- app-unpriv/src/main/res/values/strings.xml | 8 +++ 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/util/CompatibilityCheck.kt b/app-unpriv/src/main/java/im/angry/openeuicc/util/CompatibilityCheck.kt index 83c1c5d..d2ee8cc 100644 --- a/app-unpriv/src/main/java/im/angry/openeuicc/util/CompatibilityCheck.kt +++ b/app-unpriv/src/main/java/im/angry/openeuicc/util/CompatibilityCheck.kt @@ -16,12 +16,16 @@ fun getCompatibilityChecks(context: Context): List = HasSystemFeaturesCheck(context), OmapiConnCheck(context), IsdrChannelAccessCheck(context), - KnownBrokenCheck(context) + KnownBrokenCheck(context), + Verdict(context), ) +inline fun List.findCheck(): T? = + find { it.javaClass == T::class.java }?.let { it as T } + suspend fun List.executeAll(callback: () -> Unit) = withContext(Dispatchers.IO) { forEach { - it.run() + it.run(this@executeAll) withContext(Dispatchers.Main) { callback() } @@ -57,13 +61,13 @@ abstract class CompatibilityCheck(context: Context) { else -> defaultDescription } - protected abstract suspend fun doCheck(): State + protected abstract suspend fun doCheck(allChecks: List): State - suspend fun run() { + suspend fun run(allChecks: List) { state = State.IN_PROGRESS delay(200) state = try { - doCheck() + doCheck(allChecks) } catch (_: Exception) { State.FAILURE } @@ -76,7 +80,7 @@ internal class HasSystemFeaturesCheck(private val context: Context): Compatibili override val defaultDescription: String get() = context.getString(R.string.compatibility_check_system_features_desc) - override suspend fun doCheck(): State { + override suspend fun doCheck(allChecks: List): State { if (!context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { failureDescription = context.getString(R.string.compatibility_check_system_features_no_telephony) return State.FAILURE @@ -100,7 +104,7 @@ internal class OmapiConnCheck(private val context: Context): CompatibilityCheck( override val defaultDescription: String get() = context.getString(R.string.compatibility_check_omapi_connectivity_desc) - override suspend fun doCheck(): State { + override suspend fun doCheck(allChecks: List): State { val seService = connectSEService(context) if (!seService.isConnected) { failureDescription = context.getString(R.string.compatibility_check_omapi_connectivity_fail) @@ -132,7 +136,7 @@ internal class IsdrChannelAccessCheck(private val context: Context): Compatibili override val defaultDescription: String get() = context.getString(R.string.compatibility_check_isdr_channel_desc) - override suspend fun doCheck(): State { + override suspend fun doCheck(allChecks: List): State { val seService = connectSEService(context) val readers = seService.readers.filter { it.isSIM } if (readers.isEmpty()) { @@ -200,10 +204,57 @@ internal class KnownBrokenCheck(private val context: Context): CompatibilityChec failureDescription = context.getString(R.string.compatibility_check_known_broken_fail) } - override suspend fun doCheck(): State = + override suspend fun doCheck(allChecks: List): State = if (Build.MANUFACTURER.lowercase() in BROKEN_MANUFACTURERS) { State.FAILURE } else { State.SUCCESS } +} + +internal class Verdict(private val context: Context) : CompatibilityCheck(context) { + override val title: String + get() = context.getString(R.string.compatibility_check_verdict) + override val defaultDescription: String + get() = context.getString(R.string.compatibility_check_verdict_desc) + + override suspend fun doCheck(allChecks: List): State { + if (allChecks.findCheck()?.state == State.FAILURE) { + failureDescription = context.getString( + R.string.compatibility_check_verdict_known_broken, + context.getString(R.string.compatibility_check_verdict_fail_shared) + ) + return State.FAILURE + } + + if (allChecks.findCheck()?.state == State.SUCCESS && + allChecks.findCheck()?.state == State.SUCCESS + ) { + successDescription = context.getString(R.string.compatibility_check_verdict_ok) + return State.SUCCESS + } + + if (allChecks.findCheck()?.state == State.FAILURE_UNKNOWN || + allChecks.findCheck()?.state == State.FAILURE_UNKNOWN + ) { + // We are not sure because we can't fully check OMAPI + // however we can guess based on feature flags + // TODO: We probably need a "known-good" list for these devices as well? + failureDescription = context.getString( + if (allChecks.findCheck()?.state == State.SUCCESS) { + R.string.compatibility_check_verdict_unknown_likely_ok + } else { + R.string.compatibility_check_verdict_unknown_likely_fail + }, + context.getString(R.string.compatibility_check_verdict_fail_shared) + ) + return State.FAILURE_UNKNOWN + } + + failureDescription = context.getString( + R.string.compatibility_check_verdict_unknown, + context.getString(R.string.compatibility_check_verdict_fail_shared) + ) + return State.FAILURE_UNKNOWN + } } \ No newline at end of file diff --git a/app-unpriv/src/main/res/values/strings.xml b/app-unpriv/src/main/res/values/strings.xml index 7ba42fe..625136d 100644 --- a/app-unpriv/src/main/res/values/strings.xml +++ b/app-unpriv/src/main/res/values/strings.xml @@ -18,4 +18,12 @@ Not on the Known Broken List Making sure your device is not known to have bugs associated with removable eSIMs. Oops, your device is known to have bugs when accessing removable eSIMs. This does not necessarily mean that it will not work at all, but you will have to proceed with caution. + Verdict + Based on all previous checks, how likely is your device to be compatible with removable eSIMs? + You can likely use and manage removable eSIMs on this device. + Your device is known to be buggy when accessing removable eSIMs.\n%s + We cannot determine whether removable eSIMs can be managed on your device. Your device does declare support for OMAPI, though, so it is slightly more likely that it will work.\n%s + We cannot determine whether removable eSIMs can be managed on your device. Since your device does not declare support for OMAPI, it is more likely that managing removable eSIMs on this device is unsupported.\n%s + We cannot determine whether removable eSIMs can be managed on your device.\n%s + However, a removable eSIM that has already been loaded with an eSIM profile will still work; this verdict is only for management features via the app, such as switching and downloading profiles. \ No newline at end of file