ソースを参照

feat: Optional confirmation signal for profileDownloadTask

This is to prepare for confirmation UI and EuiccService preview impl.
Peter Cai 2 週間 前
コミット
297880fa53

+ 27 - 1
app-common/src/main/java/im/angry/openeuicc/service/EuiccChannelManagerService.kt

@@ -17,7 +17,10 @@ import im.angry.openeuicc.core.EuiccChannelManager
 import im.angry.openeuicc.util.*
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.NonCancellable
+import kotlinx.coroutines.TimeoutCancellationException
 import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.trySendBlocking
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
@@ -34,7 +37,9 @@ import kotlinx.coroutines.flow.takeWhile
 import kotlinx.coroutines.flow.transformWhile
 import kotlinx.coroutines.isActive
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
+import kotlinx.coroutines.withTimeout
 import kotlinx.coroutines.withTimeoutOrNull
 import kotlinx.coroutines.yield
 import net.typeblog.lpac_jni.ProfileDownloadInput
@@ -381,7 +386,13 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
 
     fun launchProfileDownloadTask(
         slotId: Int, portId: Int, seId: EuiccChannel.SecureElementId,
-        input: ProfileDownloadInput
+        input: ProfileDownloadInput,
+        // Optionally, a Channel to send confirmation signal when metadata preview is received.
+        // When we emit a ForegroundTaskState.InProgress with ProfileDownloadState.ConfirmingMetadata,
+        // the caller can send a true/false value into this channel to either continue immediately or cancel the download.
+        // Note that there is a timeout of 1 minute, after which we default to cancelling.
+        // When absent, the default value is just a buffered channel with 1 true value in it, so effectively no-op.
+        confirmationSignal: Channel<Boolean> = Channel<Boolean>(1).apply { trySendBlocking(true) }
     ): ForegroundTaskSubscriberFlow =
         launchForegroundTask(
             getString(R.string.task_profile_download),
@@ -405,6 +416,21 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
                                     "Downloading profile provider=${metadata.providerName} name=${metadata.name}"
                                 )
                             }
+
+                            // Try to receive a signal for confirmation while blocking this thread
+                            // This of course assumes we're NOT on the main thread here. We aren't,
+                            // because we don't run download on the main thread; see withEuiccChannel.
+                            return@downloadProfile runBlocking {
+                                try {
+                                    // We can't wait indefinitely; just time out after 1 minute.
+                                    withTimeout(60 * 1000) {
+                                        confirmationSignal.receive()
+                                    }
+                                } catch (_: TimeoutCancellationException) {
+                                    // Default to cancelling / aborting here if we didn't receive a confirmation signal
+                                    false
+                                }
+                            }
                         }
 
                         true