Convert app updater to foreground service
This commit is contained in:
parent
08ba805bbd
commit
788ea052fc
3 changed files with 87 additions and 28 deletions
|
@ -33,14 +33,15 @@ internal class UpdaterNotifier(private val context: Context) {
|
|||
*
|
||||
* @param title tile of notification.
|
||||
*/
|
||||
fun onDownloadStarted(title: String) {
|
||||
fun onDownloadStarted(title: String? = null): NotificationCompat.Builder {
|
||||
with(notificationBuilder) {
|
||||
setContentTitle(title)
|
||||
title?.let { setContentTitle(title) }
|
||||
setContentText(context.getString(R.string.update_check_notification_download_in_progress))
|
||||
setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
setOngoing(true)
|
||||
}
|
||||
notificationBuilder.show()
|
||||
return notificationBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,49 +1,96 @@
|
|||
package eu.kanade.tachiyomi.data.updater
|
||||
|
||||
import android.app.IntentService
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
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.newCallWithProgress
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
||||
import java.io.File
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class UpdaterService : IntentService(UpdaterService::class.java.name) {
|
||||
class UpdaterService : Service() {
|
||||
|
||||
private val network: NetworkHelper by injectLazy()
|
||||
|
||||
/**
|
||||
* Notifier for the updater state and progress.
|
||||
* Wake lock that will be held until the service is destroyed.
|
||||
*/
|
||||
private val notifier by lazy { UpdaterNotifier(this) }
|
||||
private lateinit var wakeLock: PowerManager.WakeLock
|
||||
|
||||
override fun onHandleIntent(intent: Intent?) {
|
||||
if (intent == null) return
|
||||
private lateinit var notifier: UpdaterNotifier
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
notifier = UpdaterNotifier(this)
|
||||
|
||||
startForeground(Notifications.ID_UPDATER, notifier.onDownloadStarted().build())
|
||||
|
||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
||||
PowerManager.PARTIAL_WAKE_LOCK, "${javaClass.name}:WakeLock"
|
||||
)
|
||||
wakeLock.acquire()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
val url = intent.getStringExtra(EXTRA_DOWNLOAD_URL) ?: return
|
||||
|
||||
launchIO {
|
||||
downloadApk(title, url)
|
||||
}
|
||||
|
||||
stopSelf(startId)
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun stopService(name: Intent?): Boolean {
|
||||
destroyJob()
|
||||
return super.stopService(name)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
destroyJob()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun destroyJob() {
|
||||
if (wakeLock.isHeld) {
|
||||
wakeLock.release()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to start downloading apk of new update
|
||||
*
|
||||
* @param url url location of file
|
||||
*/
|
||||
private fun downloadApk(title: String, url: String) {
|
||||
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
|
||||
|
||||
|
@ -63,7 +110,7 @@ class UpdaterService : IntentService(UpdaterService::class.java.name) {
|
|||
|
||||
try {
|
||||
// Download the new update.
|
||||
val response = network.client.newCallWithProgress(GET(url), progressListener).execute()
|
||||
val response = network.client.newCallWithProgress(GET(url), progressListener).await()
|
||||
|
||||
// File where the apk will be saved.
|
||||
val apkFile = File(externalCacheDir, "update.apk")
|
||||
|
@ -82,27 +129,38 @@ class UpdaterService : IntentService(UpdaterService::class.java.name) {
|
|||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Download url.
|
||||
*/
|
||||
internal const val EXTRA_DOWNLOAD_URL = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_URL"
|
||||
|
||||
/**
|
||||
* Download title
|
||||
*/
|
||||
internal const val EXTRA_DOWNLOAD_URL = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_URL"
|
||||
internal const val EXTRA_DOWNLOAD_TITLE = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_TITLE"
|
||||
|
||||
/**
|
||||
* Downloads a new update and let the user install the new version from a notification.
|
||||
* Returns the status of the service.
|
||||
*
|
||||
* @param context the application context.
|
||||
* @param url the url to the new update.
|
||||
* @return true if the service is running, false otherwise.
|
||||
*/
|
||||
fun downloadUpdate(context: Context, url: String, title: String = context.getString(R.string.app_name)) {
|
||||
private fun isRunning(context: Context): Boolean =
|
||||
context.isServiceRunning(UpdaterService::class.java)
|
||||
|
||||
/**
|
||||
* Make a backup from library
|
||||
*
|
||||
* @param context context of application
|
||||
* @param uri path of Uri
|
||||
* @param flags determines what to backup
|
||||
*/
|
||||
fun start(context: Context, url: String, title: String = context.getString(R.string.app_name)) {
|
||||
if (!isRunning(context)) {
|
||||
val intent = Intent(context, UpdaterService::class.java).apply {
|
||||
putExtra(EXTRA_DOWNLOAD_TITLE, title)
|
||||
putExtra(EXTRA_DOWNLOAD_URL, url)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
context.startService(intent)
|
||||
} else {
|
||||
context.startForegroundService(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -187,7 +187,7 @@ class AboutController : SettingsController() {
|
|||
if (appContext != null) {
|
||||
// Start download
|
||||
val url = args.getString(URL_KEY) ?: ""
|
||||
UpdaterService.downloadUpdate(appContext, url)
|
||||
UpdaterService.start(appContext, url)
|
||||
}
|
||||
}
|
||||
.negativeButton(R.string.update_check_ignore)
|
||||
|
|
Reference in a new issue