Replace AppUpdateService with a WorkManager job
Fixes #7773 Co-authored-by: Jays2Kings <Jays2Kings@users.noreply.github.com>
This commit is contained in:
parent
c46c39d4ae
commit
eed57b80be
6 changed files with 183 additions and 211 deletions
|
@ -145,10 +145,6 @@
|
||||||
android:name=".data.download.DownloadService"
|
android:name=".data.download.DownloadService"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
<service
|
|
||||||
android:name=".data.updater.AppUpdateService"
|
|
||||||
android:exported="false" />
|
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".extension.util.ExtensionInstallService"
|
android:name=".extension.util.ExtensionInstallService"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
|
@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupRestoreJob
|
import eu.kanade.tachiyomi.data.backup.BackupRestoreJob
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||||
import eu.kanade.tachiyomi.data.updater.AppUpdateService
|
import eu.kanade.tachiyomi.data.updater.AppUpdateDownloadJob
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
|
@ -85,6 +85,8 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||||
ACTION_CANCEL_RESTORE -> cancelRestore(context)
|
ACTION_CANCEL_RESTORE -> cancelRestore(context)
|
||||||
// Cancel library update and dismiss notification
|
// Cancel library update and dismiss notification
|
||||||
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context)
|
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context)
|
||||||
|
// Start downloading app update
|
||||||
|
ACTION_START_APP_UPDATE -> startDownloadAppUpdate(context, intent)
|
||||||
// Cancel downloading app update
|
// Cancel downloading app update
|
||||||
ACTION_CANCEL_APP_UPDATE_DOWNLOAD -> cancelDownloadAppUpdate(context)
|
ACTION_CANCEL_APP_UPDATE_DOWNLOAD -> cancelDownloadAppUpdate(context)
|
||||||
// Open reader activity
|
// Open reader activity
|
||||||
|
@ -209,8 +211,13 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||||
LibraryUpdateJob.stop(context)
|
LibraryUpdateJob.stop(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun startDownloadAppUpdate(context: Context, intent: Intent) {
|
||||||
|
val url = intent.getStringExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_URL) ?: return
|
||||||
|
AppUpdateDownloadJob.start(context, url)
|
||||||
|
}
|
||||||
|
|
||||||
private fun cancelDownloadAppUpdate(context: Context) {
|
private fun cancelDownloadAppUpdate(context: Context) {
|
||||||
AppUpdateService.stop(context)
|
AppUpdateDownloadJob.stop(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -268,6 +275,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
private const val ACTION_CANCEL_LIBRARY_UPDATE = "$ID.$NAME.CANCEL_LIBRARY_UPDATE"
|
private const val ACTION_CANCEL_LIBRARY_UPDATE = "$ID.$NAME.CANCEL_LIBRARY_UPDATE"
|
||||||
|
|
||||||
|
private const val ACTION_START_APP_UPDATE = "$ID.$NAME.ACTION_START_APP_UPDATE"
|
||||||
private const val ACTION_CANCEL_APP_UPDATE_DOWNLOAD = "$ID.$NAME.CANCEL_APP_UPDATE_DOWNLOAD"
|
private const val ACTION_CANCEL_APP_UPDATE_DOWNLOAD = "$ID.$NAME.CANCEL_APP_UPDATE_DOWNLOAD"
|
||||||
|
|
||||||
private const val ACTION_MARK_AS_READ = "$ID.$NAME.MARK_AS_READ"
|
private const val ACTION_MARK_AS_READ = "$ID.$NAME.MARK_AS_READ"
|
||||||
|
@ -499,10 +507,25 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [PendingIntent] that starts the [AppUpdateDownloadJob] to download an app update.
|
||||||
|
*
|
||||||
|
* @param context context of application
|
||||||
|
* @return [PendingIntent]
|
||||||
|
*/
|
||||||
|
internal fun downloadAppUpdatePendingBroadcast(context: Context, url: String, title: String? = null): PendingIntent {
|
||||||
|
return Intent(context, NotificationReceiver::class.java).run {
|
||||||
|
action = ACTION_START_APP_UPDATE
|
||||||
|
putExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_URL, url)
|
||||||
|
title?.let { putExtra(AppUpdateDownloadJob.EXTRA_DOWNLOAD_TITLE, it) }
|
||||||
|
PendingIntent.getBroadcast(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
internal fun cancelUpdateDownloadPendingBroadcast(context: Context): PendingIntent {
|
internal fun cancelDownloadAppUpdatePendingBroadcast(context: Context): PendingIntent {
|
||||||
val intent = Intent(context, NotificationReceiver::class.java).apply {
|
val intent = Intent(context, NotificationReceiver::class.java).apply {
|
||||||
action = ACTION_CANCEL_APP_UPDATE_DOWNLOAD
|
action = ACTION_CANCEL_APP_UPDATE_DOWNLOAD
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,11 +34,11 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||||
|
|
||||||
@SuppressLint("LaunchActivityFromNotification")
|
@SuppressLint("LaunchActivityFromNotification")
|
||||||
fun promptUpdate(release: Release) {
|
fun promptUpdate(release: Release) {
|
||||||
val updateIntent = Intent(context, AppUpdateService::class.java).run {
|
val updateIntent = NotificationReceiver.downloadAppUpdatePendingBroadcast(
|
||||||
putExtra(AppUpdateService.EXTRA_DOWNLOAD_URL, release.getDownloadLink())
|
context,
|
||||||
putExtra(AppUpdateService.EXTRA_DOWNLOAD_TITLE, release.version)
|
release.getDownloadLink(),
|
||||||
PendingIntent.getService(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
release.version,
|
||||||
}
|
)
|
||||||
|
|
||||||
val releaseIntent = Intent(Intent.ACTION_VIEW, release.releaseLink.toUri()).run {
|
val releaseIntent = Intent(Intent.ACTION_VIEW, release.releaseLink.toUri()).run {
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
|
@ -82,7 +82,7 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||||
addAction(
|
addAction(
|
||||||
R.drawable.ic_close_24dp,
|
R.drawable.ic_close_24dp,
|
||||||
context.getString(R.string.action_cancel),
|
context.getString(R.string.action_cancel),
|
||||||
NotificationReceiver.cancelUpdateDownloadPendingBroadcast(context),
|
NotificationReceiver.cancelDownloadAppUpdatePendingBroadcast(context),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
notificationBuilder.show()
|
notificationBuilder.show()
|
||||||
|
@ -164,7 +164,7 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||||
addAction(
|
addAction(
|
||||||
R.drawable.ic_refresh_24dp,
|
R.drawable.ic_refresh_24dp,
|
||||||
context.getString(R.string.action_retry),
|
context.getString(R.string.action_retry),
|
||||||
AppUpdateService.downloadApkPendingService(context, url),
|
NotificationReceiver.downloadAppUpdatePendingBroadcast(context, url),
|
||||||
)
|
)
|
||||||
addAction(
|
addAction(
|
||||||
R.drawable.ic_close_24dp,
|
R.drawable.ic_close_24dp,
|
||||||
|
|
|
@ -1,195 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.data.updater
|
|
||||||
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.app.Service
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.IBinder
|
|
||||||
import android.os.PowerManager
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
|
||||||
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.acquireWakeLock
|
|
||||||
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
|
||||||
import kotlinx.coroutines.CancellationException
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import okhttp3.internal.http2.ErrorCode
|
|
||||||
import okhttp3.internal.http2.StreamResetException
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class AppUpdateService : Service() {
|
|
||||||
|
|
||||||
private val network: NetworkHelper by injectLazy()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wake lock that will be held until the service is destroyed.
|
|
||||||
*/
|
|
||||||
private lateinit var wakeLock: PowerManager.WakeLock
|
|
||||||
private lateinit var notifier: AppUpdateNotifier
|
|
||||||
|
|
||||||
private val job = SupervisorJob()
|
|
||||||
private val serviceScope = CoroutineScope(Dispatchers.IO + job)
|
|
||||||
|
|
||||||
override fun onCreate() {
|
|
||||||
notifier = AppUpdateNotifier(this)
|
|
||||||
wakeLock = acquireWakeLock(javaClass.name)
|
|
||||||
|
|
||||||
startForeground(Notifications.ID_APP_UPDATER, notifier.onDownloadStarted().build())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method needs to be implemented, but it's not used/needed.
|
|
||||||
*/
|
|
||||||
override fun onBind(intent: Intent): IBinder? = null
|
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
|
||||||
if (intent == null) return START_NOT_STICKY
|
|
||||||
|
|
||||||
val url = intent.getStringExtra(EXTRA_DOWNLOAD_URL) ?: return START_NOT_STICKY
|
|
||||||
val title = intent.getStringExtra(EXTRA_DOWNLOAD_TITLE) ?: getString(R.string.app_name)
|
|
||||||
|
|
||||||
serviceScope.launch {
|
|
||||||
downloadApk(title, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
job.invokeOnCompletion { stopSelf(startId) }
|
|
||||||
return START_NOT_STICKY
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun stopService(name: Intent?): Boolean {
|
|
||||||
destroyJob()
|
|
||||||
return super.stopService(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
destroyJob()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun destroyJob() {
|
|
||||||
serviceScope.cancel()
|
|
||||||
job.cancel()
|
|
||||||
if (wakeLock.isHeld) {
|
|
||||||
wakeLock.release()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(externalCacheDir, "update.apk")
|
|
||||||
|
|
||||||
if (response.isSuccessful) {
|
|
||||||
response.body.source().saveTo(apkFile)
|
|
||||||
} else {
|
|
||||||
response.close()
|
|
||||||
throw Exception("Unsuccessful response")
|
|
||||||
}
|
|
||||||
notifier.cancel()
|
|
||||||
notifier.promptInstall(apkFile.getUriCompat(this))
|
|
||||||
} 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 {
|
|
||||||
|
|
||||||
internal const val EXTRA_DOWNLOAD_URL = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_URL"
|
|
||||||
internal const val EXTRA_DOWNLOAD_TITLE = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_TITLE"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the status of the service.
|
|
||||||
*
|
|
||||||
* @param context the application context.
|
|
||||||
* @return true if the service is running, false otherwise.
|
|
||||||
*/
|
|
||||||
private fun isRunning(context: Context): Boolean =
|
|
||||||
context.isServiceRunning(AppUpdateService::class.java)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads a new update and let the user install the new version from a notification.
|
|
||||||
*
|
|
||||||
* @param context the application context.
|
|
||||||
* @param url the url to the new update.
|
|
||||||
*/
|
|
||||||
fun start(context: Context, url: String, title: String? = context.getString(R.string.app_name)) {
|
|
||||||
if (isRunning(context)) return
|
|
||||||
|
|
||||||
Intent(context, AppUpdateService::class.java).apply {
|
|
||||||
putExtra(EXTRA_DOWNLOAD_TITLE, title)
|
|
||||||
putExtra(EXTRA_DOWNLOAD_URL, url)
|
|
||||||
ContextCompat.startForegroundService(context, this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the service.
|
|
||||||
*
|
|
||||||
* @param context the application context
|
|
||||||
*/
|
|
||||||
fun stop(context: Context) {
|
|
||||||
context.stopService(Intent(context, AppUpdateService::class.java))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns [PendingIntent] that starts a service which downloads the apk specified in url.
|
|
||||||
*
|
|
||||||
* @param url the url to the new update.
|
|
||||||
* @return [PendingIntent]
|
|
||||||
*/
|
|
||||||
internal fun downloadApkPendingService(context: Context, url: String): PendingIntent {
|
|
||||||
return Intent(context, AppUpdateService::class.java).run {
|
|
||||||
putExtra(EXTRA_DOWNLOAD_URL, url)
|
|
||||||
PendingIntent.getService(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.presentation.more.NewUpdateScreen
|
import eu.kanade.presentation.more.NewUpdateScreen
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.data.updater.AppUpdateService
|
import eu.kanade.tachiyomi.data.updater.AppUpdateDownloadJob
|
||||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||||
|
|
||||||
class NewUpdateScreen(
|
class NewUpdateScreen(
|
||||||
|
@ -31,7 +31,7 @@ class NewUpdateScreen(
|
||||||
onOpenInBrowser = { context.openInBrowser(releaseLink) },
|
onOpenInBrowser = { context.openInBrowser(releaseLink) },
|
||||||
onRejectUpdate = navigator::pop,
|
onRejectUpdate = navigator::pop,
|
||||||
onAcceptUpdate = {
|
onAcceptUpdate = {
|
||||||
AppUpdateService.start(
|
AppUpdateDownloadJob.start(
|
||||||
context = context,
|
context = context,
|
||||||
url = downloadLink,
|
url = downloadLink,
|
||||||
title = versionName,
|
title = versionName,
|
||||||
|
|
Reference in a new issue