ソースを参照

Retry profile switching with refresh = false if refresh = true failed

Peter Cai 1 年間 前
コミット
6396f17012

+ 28 - 5
app-common/src/main/java/im/angry/openeuicc/ui/EuiccManagementFragment.kt

@@ -134,11 +134,17 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
 
         lifecycleScope.launch {
             beginTrackedOperation {
-                val res = if (enable) {
-                    channel.lpa.enableProfile(iccid)
-                } else {
-                    channel.lpa.disableProfile(iccid)
-                }
+                val (res, refreshed) =
+                    if (!channel.lpa.switchProfile(iccid, enable, refresh = true)) {
+                        // Sometimes, we *can* enable or disable the profile, but we cannot
+                        // send the refresh command to the modem because the profile somehow
+                        // makes the modem "busy". In this case, we can still switch by setting
+                        // refresh to false, but then the switch cannot take effect until the
+                        // user resets the modem manually by toggling airplane mode or rebooting.
+                        Pair(channel.lpa.switchProfile(iccid, enable, refresh = false), false)
+                    } else {
+                        Pair(true, true)
+                    }
 
                 if (!res) {
                     Log.d(TAG, "Failed to enable / disable profile $iccid")
@@ -152,6 +158,23 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
                     return@beginTrackedOperation false
                 }
 
+                if (!refreshed) {
+                    withContext(Dispatchers.Main) {
+                        AlertDialog.Builder(requireContext()).apply {
+                            setMessage(R.string.switch_did_not_refresh)
+                            setPositiveButton(android.R.string.ok) { dialog, _ ->
+                                dialog.dismiss()
+                                requireActivity().finish()
+                            }
+                            setOnDismissListener { _ ->
+                                requireActivity().finish()
+                            }
+                            show()
+                        }
+                    }
+                    return@beginTrackedOperation true
+                }
+
                 try {
                     euiccChannelManager.waitForReconnect(slotId, portId, timeoutMillis = 30 * 1000)
                 } catch (e: TimeoutCancellationException) {

+ 11 - 0
app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt

@@ -26,6 +26,17 @@ val List<LocalProfileInfo>.operational: List<LocalProfileInfo>
 val List<EuiccChannel>.hasMultipleChips: Boolean
     get() = distinctBy { it.slotId }.size > 1
 
+fun LocalProfileAssistant.switchProfile(
+    iccid: String,
+    enable: Boolean = false,
+    refresh: Boolean = false
+): Boolean =
+    if (enable) {
+        enableProfile(iccid, refresh)
+    } else {
+        disableProfile(iccid, refresh)
+    }
+
 /**
  * Disable the current active profile if any. If refresh is true, also cause a refresh command.
  * See EuiccManager.waitForReconnect()

+ 1 - 0
app-common/src/main/res/values/strings.xml

@@ -17,6 +17,7 @@
     <string name="rename">Rename</string>
 
     <string name="enable_disable_timeout">Timed out waiting for the eSIM chip to switch profiles. This may be a bug in your phone\'s modem firmware. Try toggling airplane mode, restarting the application, or rebooting the phone.</string>
+    <string name="switch_did_not_refresh">The operation was successful, but your phone\'s modem refused to refresh. You might need to toggle airplane mode or reboot in order to use the new profile.</string>
 
     <string name="toast_profile_enable_failed">Cannot switch to new eSIM profile.</string>
     <string name="toast_profile_name_too_long">Nickname cannot be longer than 64 characters</string>