DownloadWorkerUtil: Cancel all failed downloads on init

WorkManager downloads can fail due to n number of reason. Regardless of the reason
there might be not enough time to mark the download as failed within the worker
causing the download to keep the status as downloading on next startup, thus blocking
the queue.

Always check for downloads with downloading status on init and cancel them if work
manager cannot find atleast one ongoing work for it.

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
Aayush Gupta
2024-02-21 19:04:32 +05:30
parent 1a01f96f08
commit 1108edc303

View File

@@ -50,29 +50,35 @@ class DownloadWorkerUtil @Inject constructor(
private val TAG = DownloadWorkerUtil::class.java.simpleName
fun init() {
// Run cleanup for last finished download and drop it database
GlobalScope.launch {
downloadDao.downloads()
.collectLatest { list ->
// Check and trigger next download in queue, if any
if (!list.any { it.downloadStatus == DownloadStatus.DOWNLOADING }) {
val enqueuedDownloads = list.filter { it.downloadStatus == DownloadStatus.QUEUED }
enqueuedDownloads.firstOrNull()?.let {
try {
if (context.isIgnoringBatteryOptimizations() || CommonUtil.inForeground()) {
Log.i(DOWNLOAD_WORKER, "Downloading ${it.packageName}")
trigger(it)
} else {
Log.i(TAG, "Not in foreground or ignoring battery optimization")
cancel()
}
} catch (exception: Exception) {
Log.i(DOWNLOAD_WORKER, "Failed to download app", exception)
downloadDao.delete(it.packageName)
cancelFailedDownloads(downloadDao.downloads().firstOrNull() ?: emptyList())
}.invokeOnCompletion {
observeDownloads()
}
}
private fun observeDownloads() {
GlobalScope.launch {
downloadDao.downloads().collectLatest { list ->
// Check and trigger next download in queue, if any
if (!list.any { it.downloadStatus == DownloadStatus.DOWNLOADING }) {
val enqueuedDownloads = list.filter { it.downloadStatus == DownloadStatus.QUEUED }
enqueuedDownloads.firstOrNull()?.let {
try {
if (context.isIgnoringBatteryOptimizations() || CommonUtil.inForeground()) {
Log.i(DOWNLOAD_WORKER, "Downloading ${it.packageName}")
trigger(it)
} else {
Log.i(TAG, "Not in foreground or ignoring battery optimization")
cancel()
}
} catch (exception: Exception) {
Log.i(DOWNLOAD_WORKER, "Failed to download app", exception)
downloadDao.delete(it.packageName)
}
}
}
}
}
}
@@ -118,6 +124,16 @@ class DownloadWorkerUtil @Inject constructor(
.cancelAllWorkByTag(if (updatesOnly) DOWNLOAD_UPDATE else DOWNLOAD_APP)
}
private suspend fun cancelFailedDownloads(downloadList: List<Download>) {
val workManager = WorkManager.getInstance(context)
downloadList.filter { it.isRunning }.forEach {
workManager.getWorkInfosByTagFlow("$PACKAGE_NAME:${it.packageName}").firstOrNull()
?.all { workInfo -> workInfo.state.isFinished }
?.run { downloadDao.updateStatus(it.packageName, DownloadStatus.CANCELLED) }
}
}
private fun trigger(download: Download) {
val inputData = Data.Builder()
.putString(DOWNLOAD_DATA, gson.toJson(download))