瀏覽代碼

OpenEuiccService: track LPA actions for notifications

Peter Cai 1 年之前
父節點
當前提交
261ad6dbeb

+ 22 - 17
app-common/src/main/java/im/angry/openeuicc/util/LPAUtils.kt

@@ -3,11 +3,12 @@ package im.angry.openeuicc.util
 import android.util.Log
 import im.angry.openeuicc.core.EuiccChannel
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
 import net.typeblog.lpac_jni.LocalProfileAssistant
 import net.typeblog.lpac_jni.LocalProfileInfo
 
-private const val TAG = "LPAUtils"
+const val TAG = "LPAUtils"
 
 val LocalProfileInfo.displayName: String
     get() = nickName.ifEmpty { name }
@@ -53,21 +54,25 @@ fun LocalProfileAssistant.disableActiveProfileWithUndo(refreshOnDisable: Boolean
  */
 suspend fun LocalProfileAssistant.beginTrackedOperation(op: suspend () -> Boolean) =
     withContext(Dispatchers.IO) {
-        val latestSeq = notifications.firstOrNull()?.seqNumber ?: 0
-        Log.d(TAG, "Latest notification is $latestSeq before operation")
-        if (op()) {
-            Log.d(TAG, "Operation has requested notification handling")
-            try {
-                // Note that the exact instance of "channel" might have changed here if reconnected;
-                // so we MUST use the automatic getter for "channel"
-                notifications.filter { it.seqNumber > latestSeq }.forEach {
-                    Log.d(TAG, "Handling notification $it")
-                    handleNotification(it.seqNumber)
-                }
-            } catch (e: Exception) {
-                // Ignore any error during notification handling
-                e.printStackTrace()
+        beginTrackedOperationBlocking { op() }
+    }
+
+inline fun LocalProfileAssistant.beginTrackedOperationBlocking(op: () -> Boolean) {
+    val latestSeq = notifications.firstOrNull()?.seqNumber ?: 0
+    Log.d(TAG, "Latest notification is $latestSeq before operation")
+    if (op()) {
+        Log.d(TAG, "Operation has requested notification handling")
+        try {
+            // Note that the exact instance of "channel" might have changed here if reconnected;
+            // so we MUST use the automatic getter for "channel"
+            notifications.filter { it.seqNumber > latestSeq }.forEach {
+                Log.d(TAG, "Handling notification $it")
+                handleNotification(it.seqNumber)
             }
+        } catch (e: Exception) {
+            // Ignore any error during notification handling
+            e.printStackTrace()
         }
-        Log.d(TAG, "Operation complete")
-    }
+    }
+    Log.d(TAG, "Operation complete")
+}

+ 25 - 11
app/src/main/java/im/angry/openeuicc/service/OpenEuiccService.kt

@@ -12,6 +12,8 @@ import net.typeblog.lpac_jni.LocalProfileInfo
 import im.angry.openeuicc.core.EuiccChannel
 import im.angry.openeuicc.core.EuiccChannelManager
 import im.angry.openeuicc.util.*
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.single
 import kotlinx.coroutines.runBlocking
 import java.lang.IllegalStateException
 
@@ -226,11 +228,17 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
                 }
             }
 
-            return if (channels[0].lpa.deleteProfile(iccid)) {
-                RESULT_OK
-            } else {
-                RESULT_FIRST_USER
+            channels[0].lpa.beginTrackedOperationBlocking {
+                if (channels[0].lpa.deleteProfile(iccid)) {
+                    return RESULT_OK
+                }
+
+                runBlocking {
+                    preferenceRepository.notificationDeleteFlow.first()
+                }
             }
+
+            return RESULT_FIRST_USER
         } catch (e: Exception) {
             return RESULT_FIRST_USER
         }
@@ -283,14 +291,20 @@ class OpenEuiccService : EuiccService(), OpenEuiccContextMarker {
                 return RESULT_FIRST_USER
             }
 
-            // Disable any active profile first if present
-            if (!channel.lpa.disableActiveProfile(false)) {
-                return RESULT_FIRST_USER
-            }
+            channel.lpa.beginTrackedOperationBlocking {
+                if (iccid != null) {
+                    // Disable any active profile first if present
+                    channel.lpa.disableActiveProfile(false)
+                    if (!channel.lpa.enableProfile(iccid)) {
+                        return RESULT_FIRST_USER
+                    }
+                } else {
+                    channel.lpa.disableActiveProfile(true)
+                }
 
-            if (iccid != null) {
-                if (!channel.lpa.enableProfile(iccid)) {
-                    return RESULT_FIRST_USER
+                runBlocking {
+                    // TODO: The enable / disable operations should really be one
+                    preferenceRepository.notificationEnableFlow.first()
                 }
             }