ソースを参照

feat: Add an "verdict" to compatibility checks

Peter Cai 1 年間 前
コミット
4b842c4afe

+ 60 - 9
app-unpriv/src/main/java/im/angry/openeuicc/util/CompatibilityCheck.kt

@@ -16,12 +16,16 @@ fun getCompatibilityChecks(context: Context): List<CompatibilityCheck> =
         HasSystemFeaturesCheck(context),
         HasSystemFeaturesCheck(context),
         OmapiConnCheck(context),
         OmapiConnCheck(context),
         IsdrChannelAccessCheck(context),
         IsdrChannelAccessCheck(context),
-        KnownBrokenCheck(context)
+        KnownBrokenCheck(context),
+        Verdict(context),
     )
     )
 
 
+inline fun <reified T: CompatibilityCheck> List<CompatibilityCheck>.findCheck(): T? =
+    find { it.javaClass == T::class.java }?.let { it as T }
+
 suspend fun List<CompatibilityCheck>.executeAll(callback: () -> Unit) = withContext(Dispatchers.IO) {
 suspend fun List<CompatibilityCheck>.executeAll(callback: () -> Unit) = withContext(Dispatchers.IO) {
     forEach {
     forEach {
-        it.run()
+        it.run(this@executeAll)
         withContext(Dispatchers.Main) {
         withContext(Dispatchers.Main) {
             callback()
             callback()
         }
         }
@@ -57,13 +61,13 @@ abstract class CompatibilityCheck(context: Context) {
             else -> defaultDescription
             else -> defaultDescription
         }
         }
 
 
-    protected abstract suspend fun doCheck(): State
+    protected abstract suspend fun doCheck(allChecks: List<CompatibilityCheck>): State
 
 
-    suspend fun run() {
+    suspend fun run(allChecks: List<CompatibilityCheck>) {
         state = State.IN_PROGRESS
         state = State.IN_PROGRESS
         delay(200)
         delay(200)
         state = try {
         state = try {
-            doCheck()
+            doCheck(allChecks)
         } catch (_: Exception) {
         } catch (_: Exception) {
             State.FAILURE
             State.FAILURE
         }
         }
@@ -76,7 +80,7 @@ internal class HasSystemFeaturesCheck(private val context: Context): Compatibili
     override val defaultDescription: String
     override val defaultDescription: String
         get() = context.getString(R.string.compatibility_check_system_features_desc)
         get() = context.getString(R.string.compatibility_check_system_features_desc)
 
 
-    override suspend fun doCheck(): State {
+    override suspend fun doCheck(allChecks: List<CompatibilityCheck>): State {
         if (!context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
         if (!context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
             failureDescription = context.getString(R.string.compatibility_check_system_features_no_telephony)
             failureDescription = context.getString(R.string.compatibility_check_system_features_no_telephony)
             return State.FAILURE
             return State.FAILURE
@@ -100,7 +104,7 @@ internal class OmapiConnCheck(private val context: Context): CompatibilityCheck(
     override val defaultDescription: String
     override val defaultDescription: String
         get() = context.getString(R.string.compatibility_check_omapi_connectivity_desc)
         get() = context.getString(R.string.compatibility_check_omapi_connectivity_desc)
 
 
-    override suspend fun doCheck(): State {
+    override suspend fun doCheck(allChecks: List<CompatibilityCheck>): State {
         val seService = connectSEService(context)
         val seService = connectSEService(context)
         if (!seService.isConnected) {
         if (!seService.isConnected) {
             failureDescription = context.getString(R.string.compatibility_check_omapi_connectivity_fail)
             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
     override val defaultDescription: String
         get() = context.getString(R.string.compatibility_check_isdr_channel_desc)
         get() = context.getString(R.string.compatibility_check_isdr_channel_desc)
 
 
-    override suspend fun doCheck(): State {
+    override suspend fun doCheck(allChecks: List<CompatibilityCheck>): State {
         val seService = connectSEService(context)
         val seService = connectSEService(context)
         val readers = seService.readers.filter { it.isSIM }
         val readers = seService.readers.filter { it.isSIM }
         if (readers.isEmpty()) {
         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)
         failureDescription = context.getString(R.string.compatibility_check_known_broken_fail)
     }
     }
 
 
-    override suspend fun doCheck(): State =
+    override suspend fun doCheck(allChecks: List<CompatibilityCheck>): State =
         if (Build.MANUFACTURER.lowercase() in BROKEN_MANUFACTURERS) {
         if (Build.MANUFACTURER.lowercase() in BROKEN_MANUFACTURERS) {
             State.FAILURE
             State.FAILURE
         } else {
         } else {
             State.SUCCESS
             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<CompatibilityCheck>): State {
+        if (allChecks.findCheck<KnownBrokenCheck>()?.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<OmapiConnCheck>()?.state == State.SUCCESS &&
+            allChecks.findCheck<IsdrChannelAccessCheck>()?.state == State.SUCCESS
+        ) {
+            successDescription = context.getString(R.string.compatibility_check_verdict_ok)
+            return State.SUCCESS
+        }
+
+        if (allChecks.findCheck<OmapiConnCheck>()?.state == State.FAILURE_UNKNOWN ||
+            allChecks.findCheck<IsdrChannelAccessCheck>()?.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<HasSystemFeaturesCheck>()?.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
+    }
 }
 }

+ 8 - 0
app-unpriv/src/main/res/values/strings.xml

@@ -18,4 +18,12 @@
     <string name="compatibility_check_known_broken">Not on the Known Broken List</string>
     <string name="compatibility_check_known_broken">Not on the Known Broken List</string>
     <string name="compatibility_check_known_broken_desc">Making sure your device is not known to have bugs associated with removable eSIMs.</string>
     <string name="compatibility_check_known_broken_desc">Making sure your device is not known to have bugs associated with removable eSIMs.</string>
     <string name="compatibility_check_known_broken_fail">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.</string>
     <string name="compatibility_check_known_broken_fail">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.</string>
+    <string name="compatibility_check_verdict">Verdict</string>
+    <string name="compatibility_check_verdict_desc">Based on all previous checks, how likely is your device to be compatible with removable eSIMs?</string>
+    <string name="compatibility_check_verdict_ok">You can likely use and manage removable eSIMs on this device.</string>
+    <string name="compatibility_check_verdict_known_broken">Your device is known to be buggy when accessing removable eSIMs.\n%s</string>
+    <string name="compatibility_check_verdict_unknown_likely_ok">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</string>
+    <string name="compatibility_check_verdict_unknown_likely_fail">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</string>
+    <string name="compatibility_check_verdict_unknown">We cannot determine whether removable eSIMs can be managed on your device.\n%s</string>
+    <string name="compatibility_check_verdict_fail_shared">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.</string>
 </resources>
 </resources>