forked from mihonapp/mihon
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replace AppUpdateService with a WorkManager job
Fixes #7773 Co-authored-by: Jays2Kings <Jays2Kings@users.noreply.github.com>
- Loading branch information
1 parent
c46c39d
commit eed57b8
Showing
6 changed files
with
183 additions
and
211 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
148 changes: 148 additions & 0 deletions
148
app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateDownloadJob.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package eu.kanade.tachiyomi.data.updater | ||
|
||
import android.content.Context | ||
import androidx.work.Constraints | ||
import androidx.work.CoroutineWorker | ||
import androidx.work.ExistingWorkPolicy | ||
import androidx.work.ForegroundInfo | ||
import androidx.work.NetworkType | ||
import androidx.work.OneTimeWorkRequestBuilder | ||
import androidx.work.WorkerParameters | ||
import androidx.work.workDataOf | ||
import eu.kanade.tachiyomi.R | ||
import eu.kanade.tachiyomi.data.notification.Notifications | ||
import eu.kanade.tachiyomi.network.GET | ||
import eu.kanade.tachiyomi.network.NetworkHelper | ||
import eu.kanade.tachiyomi.network.ProgressListener | ||
import eu.kanade.tachiyomi.network.await | ||
import eu.kanade.tachiyomi.network.newCachelessCallWithProgress | ||
import eu.kanade.tachiyomi.util.storage.getUriCompat | ||
import eu.kanade.tachiyomi.util.storage.saveTo | ||
import eu.kanade.tachiyomi.util.system.workManager | ||
import logcat.LogPriority | ||
import okhttp3.internal.http2.ErrorCode | ||
import okhttp3.internal.http2.StreamResetException | ||
import tachiyomi.core.util.lang.withIOContext | ||
import tachiyomi.core.util.system.logcat | ||
import uy.kohesive.injekt.injectLazy | ||
import java.io.File | ||
import kotlin.coroutines.cancellation.CancellationException | ||
|
||
class AppUpdateDownloadJob(private val context: Context, workerParams: WorkerParameters) : | ||
CoroutineWorker(context, workerParams) { | ||
|
||
private val notifier = AppUpdateNotifier(context) | ||
private val network: NetworkHelper by injectLazy() | ||
|
||
override suspend fun doWork(): Result { | ||
val url = inputData.getString(EXTRA_DOWNLOAD_URL) | ||
val title = inputData.getString(EXTRA_DOWNLOAD_TITLE) ?: context.getString(R.string.app_name) | ||
|
||
if (url.isNullOrEmpty()) { | ||
return Result.failure() | ||
} | ||
|
||
try { | ||
setForeground(getForegroundInfo()) | ||
} catch (e: IllegalStateException) { | ||
logcat(LogPriority.ERROR, e) { "Not allowed to run on foreground service" } | ||
} | ||
|
||
withIOContext { | ||
downloadApk(title, url) | ||
} | ||
|
||
return Result.success() | ||
} | ||
|
||
override suspend fun getForegroundInfo(): ForegroundInfo { | ||
return ForegroundInfo( | ||
Notifications.ID_APP_UPDATER, | ||
notifier.onDownloadStarted().build(), | ||
) | ||
} | ||
|
||
/** | ||
* Called to start downloading apk of new update | ||
* | ||
* @param url url location of file | ||
*/ | ||
private suspend fun downloadApk(title: String, url: String) { | ||
// Show notification download starting. | ||
notifier.onDownloadStarted(title) | ||
|
||
val progressListener = object : ProgressListener { | ||
// Progress of the download | ||
var savedProgress = 0 | ||
|
||
// Keep track of the last notification sent to avoid posting too many. | ||
var lastTick = 0L | ||
|
||
override fun update(bytesRead: Long, contentLength: Long, done: Boolean) { | ||
val progress = (100 * (bytesRead.toFloat() / contentLength)).toInt() | ||
val currentTime = System.currentTimeMillis() | ||
if (progress > savedProgress && currentTime - 200 > lastTick) { | ||
savedProgress = progress | ||
lastTick = currentTime | ||
notifier.onProgressChange(progress) | ||
} | ||
} | ||
} | ||
|
||
try { | ||
// Download the new update. | ||
val response = network.client.newCachelessCallWithProgress(GET(url), progressListener) | ||
.await() | ||
|
||
// File where the apk will be saved. | ||
val apkFile = File(context.externalCacheDir, "update.apk") | ||
|
||
if (response.isSuccessful) { | ||
response.body.source().saveTo(apkFile) | ||
} else { | ||
response.close() | ||
throw Exception("Unsuccessful response") | ||
} | ||
notifier.cancel() | ||
notifier.promptInstall(apkFile.getUriCompat(context)) | ||
} catch (e: Exception) { | ||
val shouldCancel = e is CancellationException || | ||
(e is StreamResetException && e.errorCode == ErrorCode.CANCEL) | ||
if (shouldCancel) { | ||
notifier.cancel() | ||
} else { | ||
notifier.onDownloadError(url) | ||
} | ||
} | ||
} | ||
|
||
companion object { | ||
private const val TAG = "AppUpdateDownload" | ||
|
||
const val EXTRA_DOWNLOAD_URL = "DOWNLOAD_URL" | ||
const val EXTRA_DOWNLOAD_TITLE = "DOWNLOAD_TITLE" | ||
|
||
fun start(context: Context, url: String, title: String? = null) { | ||
val constraints = Constraints( | ||
requiredNetworkType = NetworkType.CONNECTED, | ||
) | ||
|
||
val request = OneTimeWorkRequestBuilder<AppUpdateDownloadJob>() | ||
.setConstraints(constraints) | ||
.addTag(TAG) | ||
.setInputData( | ||
workDataOf( | ||
EXTRA_DOWNLOAD_URL to url, | ||
EXTRA_DOWNLOAD_TITLE to title, | ||
), | ||
) | ||
.build() | ||
|
||
context.workManager.enqueueUniqueWork(TAG, ExistingWorkPolicy.REPLACE, request) | ||
} | ||
|
||
fun stop(context: Context) { | ||
context.workManager.cancelUniqueWork(TAG) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.