Compare commits

...

2 commits

Author SHA1 Message Date
f71da0e4ff Update documentation
All checks were successful
/ build-debug (push) Successful in 4m29s
2024-09-29 15:32:46 -04:00
fe1319537a Make foreground tasks block UI reloads 2024-09-29 15:30:49 -04:00
4 changed files with 27 additions and 1 deletions

View file

@ -16,8 +16,10 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.flow.transformWhile
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -129,9 +131,13 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
/**
* Launch a potentially blocking foreground task in this service's lifecycle context.
* This function does not block, but returns a Flow that emits ForegroundTaskState
* updates associated with this task.
* updates associated with this task. The last update the returned flow will emit is
* always ForegroundTaskState.Done.
*
* The task closure is expected to update foregroundTaskState whenever appropriate.
* If a foreground task is already running, this function returns null.
*
* The function will set the state back to Idle once it sees ForegroundTaskState.Done.
*/
private fun launchForegroundTask(
title: String,
@ -176,6 +182,9 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
// We should be the only task running, so we can subscribe to foregroundTaskState
// until we encounter ForegroundTaskState.Done.
// Then, we complete the returned flow, but we also set the state back to Idle.
// The state update back to Idle won't show up in the returned stream, because
// it has been completed by that point.
return foregroundTaskState.transformWhile {
// Also update our notification when we see an update
withContext(Dispatchers.Main) {
@ -186,6 +195,14 @@ class EuiccChannelManagerService : LifecycleService(), OpenEuiccContextMarker {
}.onCompletion { foregroundTaskState.value = ForegroundTaskState.Idle }
}
val isForegroundTaskRunning: Boolean
get() = foregroundTaskState.value != ForegroundTaskState.Idle
suspend fun waitForForegroundTask() {
foregroundTaskState.takeWhile { it != ForegroundTaskState.Idle }
.collect()
}
fun launchProfileDownloadTask(
slotId: Int,
portId: Int,

View file

@ -155,6 +155,7 @@ open class EuiccManagementFragment : Fragment(), EuiccProfilesChangedListener,
lifecycleScope.launch {
ensureEuiccChannelManager()
euiccChannelManagerService.waitForForegroundTask()
if (!this@EuiccManagementFragment::disableSafeguardFlow.isInitialized) {
disableSafeguardFlow =

View file

@ -134,6 +134,8 @@ open class MainActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
loadingProgress.visibility = View.VISIBLE
viewPager.visibility = View.GONE
tabs.visibility = View.GONE
// Prevent concurrent access with any running foreground task
euiccChannelManagerService.waitForForegroundTask()
val knownChannels = withContext(Dispatchers.IO) {
euiccChannelManager.enumerateEuiccChannels().onEach {

View file

@ -160,6 +160,12 @@ class ProfileDownloadFragment : BaseMaterialDialogFragment(),
lifecycleScope.launch(Dispatchers.IO) {
ensureEuiccChannelManager()
if (euiccChannelManagerService.isForegroundTaskRunning) {
withContext(Dispatchers.Main) {
dismiss()
}
return@launch
}
// Fetch remaining NVRAM
val str = channel.lpa.euiccInfo2?.freeNvram?.also {