Compare commits
2 commits
1c0ddefad9
...
9b75295936
Author | SHA1 | Date | |
---|---|---|---|
Peter Cai | 9b75295936 | ||
Peter Cai | 048764d305 |
|
@ -64,6 +64,9 @@ class CompatibilityCheckActivity: AppCompatActivity() {
|
|||
CompatibilityCheck.State.FAILURE -> {
|
||||
root.findViewById<View>(R.id.compatibility_check_error).visibility = View.VISIBLE
|
||||
}
|
||||
CompatibilityCheck.State.FAILURE_UNKNOWN -> {
|
||||
root.findViewById<View>(R.id.compatibility_check_unknown).visibility = View.VISIBLE
|
||||
}
|
||||
else -> {
|
||||
root.findViewById<View>(R.id.compatibility_check_progress_bar).visibility = View.VISIBLE
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import im.angry.easyeuicc.R
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.IOException
|
||||
|
||||
fun getCompatibilityChecks(context: Context): List<CompatibilityCheck> =
|
||||
listOf(
|
||||
|
@ -38,6 +39,7 @@ abstract class CompatibilityCheck(context: Context) {
|
|||
NOT_STARTED,
|
||||
IN_PROGRESS,
|
||||
SUCCESS,
|
||||
FAILURE_UNKNOWN, // The check technically failed, but no conclusion can be drawn
|
||||
FAILURE
|
||||
}
|
||||
|
||||
|
@ -49,21 +51,17 @@ abstract class CompatibilityCheck(context: Context) {
|
|||
|
||||
val description: String
|
||||
get() = when {
|
||||
state == State.FAILURE && this::failureDescription.isInitialized -> failureDescription
|
||||
(state == State.FAILURE || state == State.FAILURE_UNKNOWN) && this::failureDescription.isInitialized -> failureDescription
|
||||
else -> defaultDescription
|
||||
}
|
||||
|
||||
protected abstract suspend fun doCheck(): Boolean
|
||||
protected abstract suspend fun doCheck(): State
|
||||
|
||||
suspend fun run() {
|
||||
state = State.IN_PROGRESS
|
||||
delay(200)
|
||||
state = try {
|
||||
if (doCheck()) {
|
||||
State.SUCCESS
|
||||
} else {
|
||||
State.FAILURE
|
||||
}
|
||||
doCheck()
|
||||
} catch (_: Exception) {
|
||||
State.FAILURE
|
||||
}
|
||||
|
@ -76,10 +74,10 @@ 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(): Boolean {
|
||||
override suspend fun doCheck(): State {
|
||||
if (!context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
|
||||
failureDescription = context.getString(R.string.compatibility_check_system_features_no_telephony)
|
||||
return false
|
||||
return State.FAILURE
|
||||
}
|
||||
|
||||
// We can check OMAPI UICC availability on R or later (if before R, we check OMAPI connectivity later)
|
||||
|
@ -87,10 +85,10 @@ internal class HasSystemFeaturesCheck(private val context: Context): Compatibili
|
|||
PackageManager.FEATURE_SE_OMAPI_UICC
|
||||
)) {
|
||||
failureDescription = context.getString(R.string.compatibility_check_system_features_no_omapi)
|
||||
return false
|
||||
return State.FAILURE
|
||||
}
|
||||
|
||||
return true
|
||||
return State.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,25 +98,25 @@ 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(): Boolean {
|
||||
override suspend fun doCheck(): State {
|
||||
val seService = connectSEService(context)
|
||||
if (!seService.isConnected) {
|
||||
failureDescription = context.getString(R.string.compatibility_check_omapi_connectivity_fail)
|
||||
return false
|
||||
return State.FAILURE
|
||||
}
|
||||
|
||||
val tm = context.getSystemService(TelephonyManager::class.java)
|
||||
val simReaders = seService.readers.filter { it.isSIM }
|
||||
if (simReaders.isEmpty()) {
|
||||
failureDescription = context.getString(R.string.compatibility_check_omapi_connectivity_fail)
|
||||
return false
|
||||
return State.FAILURE
|
||||
} else if (simReaders.size < tm.activeModemCountCompat) {
|
||||
failureDescription = context.getString(R.string.compatibility_check_omapi_connectivity_fail_sim_number,
|
||||
simReaders.map { it.slotIndex }.joinToString(", "))
|
||||
return false
|
||||
return State.FAILURE
|
||||
}
|
||||
|
||||
return true
|
||||
return State.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,30 +130,38 @@ 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(): Boolean {
|
||||
override suspend fun doCheck(): State {
|
||||
val seService = connectSEService(context)
|
||||
val (validSlotIds, result) = seService.readers.filter { it.isSIM }.map {
|
||||
try {
|
||||
it.openSession().openLogicalChannel(ISDR_AID)?.close()
|
||||
Pair(it.slotIndex, true)
|
||||
Pair(it.slotIndex, State.SUCCESS)
|
||||
} catch (_: SecurityException) {
|
||||
// Ignore; this is expected when everything works
|
||||
// ref: https://android.googlesource.com/platform/frameworks/base/+/4fe64fb4712a99d5da9c9a0eb8fd5169b252e1e1/omapi/java/android/se/omapi/Session.java#305
|
||||
// SecurityException is only thrown when Channel is constructed, which means everything else needs to succeed
|
||||
Pair(it.slotIndex, true)
|
||||
Pair(it.slotIndex, State.SUCCESS)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
if (e.message?.contains("Secure Element is not present") == true) {
|
||||
failureDescription = context.getString(R.string.compatibility_check_isdr_channel_desc_unknown)
|
||||
Pair(it.slotIndex, State.FAILURE_UNKNOWN)
|
||||
} else {
|
||||
Pair(it.slotIndex, State.FAILURE)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Pair(it.slotIndex, false)
|
||||
Pair(it.slotIndex, State.FAILURE)
|
||||
}
|
||||
}.fold(Pair(mutableListOf<Int>(), true)) { (ids, result), (id, ok) ->
|
||||
if (!ok) {
|
||||
Pair(ids, false)
|
||||
}.fold(Pair(mutableListOf<Int>(), State.SUCCESS)) { (ids, result), (id, ok) ->
|
||||
if (ok != State.SUCCESS) {
|
||||
Pair(ids, ok)
|
||||
} else {
|
||||
Pair(ids.apply { add(id) }, result)
|
||||
}
|
||||
}
|
||||
|
||||
if (!result && validSlotIds.size > 0) {
|
||||
if (result != State.SUCCESS && validSlotIds.size > 0) {
|
||||
if (!context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_EUICC)) {
|
||||
failureDescription = context.getString(
|
||||
R.string.compatibility_check_isdr_channel_desc_partial_fail,
|
||||
|
@ -164,7 +170,7 @@ internal class IsdrChannelAccessCheck(private val context: Context): Compatibili
|
|||
} else {
|
||||
// If the device has embedded eSIMs, we can likely ignore the failure here;
|
||||
// the OMAPI failure likely resulted from trying to access internal eSIMs.
|
||||
return true
|
||||
return State.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,6 +192,10 @@ internal class KnownBrokenCheck(private val context: Context): CompatibilityChec
|
|||
failureDescription = context.getString(R.string.compatibility_check_known_broken_fail)
|
||||
}
|
||||
|
||||
override suspend fun doCheck(): Boolean =
|
||||
Build.MANUFACTURER.lowercase() !in BROKEN_MANUFACTURERS
|
||||
override suspend fun doCheck(): State =
|
||||
if (Build.MANUFACTURER.lowercase() in BROKEN_MANUFACTURERS) {
|
||||
State.FAILURE
|
||||
} else {
|
||||
State.SUCCESS
|
||||
}
|
||||
}
|
|
@ -60,6 +60,14 @@
|
|||
android:layout_width="32dp"
|
||||
android:layout_height="32dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/compatibility_check_unknown"
|
||||
android:src="@drawable/ic_question_outline"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -13,6 +13,7 @@
|
|||
<string name="compatibility_check_omapi_connectivity_fail_sim_number">Only the following SIM slots are accessible via OMAPI: %s.</string>
|
||||
<string name="compatibility_check_isdr_channel">ISD-R Channel Access</string>
|
||||
<string name="compatibility_check_isdr_channel_desc">Does your device support opening an ISD-R (management) channel to eSIMs via OMAPI?</string>
|
||||
<string name="compatibility_check_isdr_channel_desc_unknown">Cannot determine whether ISD-R access through OMAPI is supported. You might want to retry with SIM cards inserted (any SIM card will do) if not already.</string>
|
||||
<string name="compatibility_check_isdr_channel_desc_partial_fail">OMAPI access to ISD-R is only possible on the following SIM slots: %s.</string>
|
||||
<string name="compatibility_check_known_broken">Known Broken?</string>
|
||||
<string name="compatibility_check_known_broken_desc">Making sure your device is not known to have bugs associated with removable eSIMs.</string>
|
||||
|
|
Loading…
Reference in a new issue