ソースを参照

refactor: Move notification tracking logic to EuiccChannelFragmentUtils

Peter Cai 1 年間 前
コミット
7834e0348a

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

@@ -163,13 +163,13 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
     }
 
     private suspend fun doEnableProfile(iccid: String) =
-        channel.lpa.beginOperation {
+        beginTrackedOperation {
             channel.lpa.enableProfile(iccid, reconnectTimeout = 15 * 1000) &&
                 preferenceRepository.notificationEnableFlow.first()
         }
 
     private suspend fun doDisableProfile(iccid: String) =
-        channel.lpa.beginOperation {
+        beginTrackedOperation {
             channel.lpa.disableProfile(iccid, reconnectTimeout = 15 * 1000) &&
                 preferenceRepository.notificationDisableFlow.first()
         }

+ 1 - 1
app-common/src/main/java/im/angry/openeuicc/ui/ProfileDeleteFragment.kt

@@ -82,7 +82,7 @@ class ProfileDeleteFragment : DialogFragment(), EuiccChannelFragmentMarker {
         }
     }
 
-    private suspend fun doDelete() = channel.lpa.beginOperation {
+    private suspend fun doDelete() = beginTrackedOperation {
         channel.lpa.deleteProfile(requireArguments().getString("iccid")!!)
         preferenceRepository.notificationDeleteFlow.first()
     }

+ 18 - 8
app-common/src/main/java/im/angry/openeuicc/ui/ProfileDownloadFragment.kt

@@ -189,15 +189,25 @@ class ProfileDownloadFragment : BaseMaterialDialogFragment(),
         }
     }
 
-    private suspend fun doDownloadProfile(server: String, code: String?, confirmationCode: String?, imei: String?) = channel.lpa.beginOperation {
-        downloadProfile(server, code, imei, confirmationCode, object : ProfileDownloadCallback {
-            override fun onStateUpdate(state: ProfileDownloadCallback.DownloadState) {
-                lifecycleScope.launch(Dispatchers.Main) {
-                    progress.isIndeterminate = false
-                    progress.progress = state.progress
+    private suspend fun doDownloadProfile(
+        server: String,
+        code: String?,
+        confirmationCode: String?,
+        imei: String?
+    ) = beginTrackedOperation {
+        channel.lpa.downloadProfile(
+            server,
+            code,
+            imei,
+            confirmationCode,
+            object : ProfileDownloadCallback {
+                override fun onStateUpdate(state: ProfileDownloadCallback.DownloadState) {
+                    lifecycleScope.launch(Dispatchers.Main) {
+                        progress.isIndeterminate = false
+                        progress.progress = state.progress
+                    }
                 }
-            }
-        })
+            })
 
         // If we get here, we are successful
         // Only send notifications if the user allowed us to

+ 27 - 0
app-common/src/main/java/im/angry/openeuicc/util/EuiccChannelFragmentUtils.kt

@@ -1,8 +1,14 @@
 package im.angry.openeuicc.util
 
 import android.os.Bundle
+import android.util.Log
 import androidx.fragment.app.Fragment
 import im.angry.openeuicc.core.EuiccChannel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import net.typeblog.lpac_jni.LocalProfileAssistant
+
+private const val TAG = "EuiccChannelFragmentUtils"
 
 interface EuiccChannelFragmentMarker: OpenEuiccContextMarker
 
@@ -28,6 +34,27 @@ val <T> T.channel: EuiccChannel where T: Fragment, T: EuiccChannelFragmentMarker
     get() =
         euiccChannelManager.findEuiccChannelByPortBlocking(slotId, portId)!!
 
+/*
+ * Begin a "tracked" operation where notifications may be generated by the eSIM
+ * Automatically handle any newly generated notification during the operation
+ * if the function "op" returns true.
+ */
+suspend fun <T> T.beginTrackedOperation(op: suspend () -> Boolean) where T : Fragment, T : EuiccChannelFragmentMarker =
+    withContext(Dispatchers.IO) {
+        val latestSeq = channel.lpa.notifications.firstOrNull()?.seqNumber ?: 0
+        Log.d(TAG, "Latest notification is $latestSeq before operation")
+        if (op()) {
+            Log.d(TAG, "Operation has requested notification handling")
+            // Note that the exact instance of "channel" might have changed here if reconnected;
+            // so we MUST use the automatic getter for "channel"
+            channel.lpa.notifications.filter { it.seqNumber > latestSeq }.forEach {
+                Log.d(TAG, "Handling notification $it")
+                channel.lpa.handleNotification(it.seqNumber)
+            }
+        }
+        Log.d(TAG, "Operation complete")
+    }
+
 interface EuiccProfilesChangedListener {
     fun onEuiccProfilesChanged()
 }

+ 0 - 26
libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt

@@ -1,14 +1,6 @@
 package net.typeblog.lpac_jni
 
-import android.util.Log
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-
 interface LocalProfileAssistant {
-    companion object {
-        private const val TAG = "LocalProfileAssistant"
-    }
-
     val valid: Boolean
         get() = try {
             // If we can read both eID and profiles properly, we are likely looking at
@@ -37,24 +29,6 @@ interface LocalProfileAssistant {
     fun deleteNotification(seqNumber: Long): Boolean
     fun handleNotification(seqNumber: Long): Boolean
 
-    // Wraps an operation on the eSIM chip (any of the other blocking functions)
-    // Handles notifications automatically after the operation, unless the lambda executing
-    // the operation returns false, which inhibits automatic notification processing.
-    // All code executed within are also wrapped automatically in the IO context.
-    suspend fun beginOperation(op: suspend LocalProfileAssistant.() -> Boolean) =
-        withContext(Dispatchers.IO) {
-            val latestSeq = notifications.firstOrNull()?.seqNumber ?: 0
-            Log.d(TAG, "Latest notification is $latestSeq before operation")
-            if (op(this@LocalProfileAssistant)) {
-                Log.d(TAG, "Operation has requested notification handling")
-                notifications.filter { it.seqNumber > latestSeq }.forEach {
-                    Log.d(TAG, "Handling notification $it")
-                    handleNotification(it.seqNumber)
-                }
-            }
-            Log.d(TAG, "Operation complete")
-        }
-
     fun setNickname(
         iccid: String, nickname: String
     ): Boolean