Convert app updater to foreground service
This commit is contained in:
parent
08ba805bbd
commit
788ea052fc
@ -33,14 +33,15 @@ internal class UpdaterNotifier(private val context: Context) {
|
|||||||
*
|
*
|
||||||
* @param title tile of notification.
|
* @param title tile of notification.
|
||||||
*/
|
*/
|
||||||
fun onDownloadStarted(title: String) {
|
fun onDownloadStarted(title: String? = null): NotificationCompat.Builder {
|
||||||
with(notificationBuilder) {
|
with(notificationBuilder) {
|
||||||
setContentTitle(title)
|
title?.let { setContentTitle(title) }
|
||||||
setContentText(context.getString(R.string.update_check_notification_download_in_progress))
|
setContentText(context.getString(R.string.update_check_notification_download_in_progress))
|
||||||
setSmallIcon(android.R.drawable.stat_sys_download)
|
setSmallIcon(android.R.drawable.stat_sys_download)
|
||||||
setOngoing(true)
|
setOngoing(true)
|
||||||
}
|
}
|
||||||
notificationBuilder.show()
|
notificationBuilder.show()
|
||||||
|
return notificationBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,49 +1,96 @@
|
|||||||
package eu.kanade.tachiyomi.data.updater
|
package eu.kanade.tachiyomi.data.updater
|
||||||
|
|
||||||
import android.app.IntentService
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
|
import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
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.BuildConfig
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.network.ProgressListener
|
import eu.kanade.tachiyomi.network.ProgressListener
|
||||||
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.network.newCallWithProgress
|
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.getUriCompat
|
||||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||||
|
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class UpdaterService : IntentService(UpdaterService::class.java.name) {
|
class UpdaterService : Service() {
|
||||||
|
|
||||||
private val network: NetworkHelper by injectLazy()
|
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?) {
|
private lateinit var notifier: UpdaterNotifier
|
||||||
if (intent == null) return
|
|
||||||
|
|
||||||
|
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 title = intent.getStringExtra(EXTRA_DOWNLOAD_TITLE) ?: getString(R.string.app_name)
|
||||||
val url = intent.getStringExtra(EXTRA_DOWNLOAD_URL) ?: return
|
|
||||||
|
launchIO {
|
||||||
downloadApk(title, url)
|
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
|
* Called to start downloading apk of new update
|
||||||
*
|
*
|
||||||
* @param url url location of file
|
* @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.
|
// Show notification download starting.
|
||||||
notifier.onDownloadStarted(title)
|
notifier.onDownloadStarted(title)
|
||||||
|
|
||||||
val progressListener = object : ProgressListener {
|
val progressListener = object : ProgressListener {
|
||||||
|
|
||||||
// Progress of the download
|
// Progress of the download
|
||||||
var savedProgress = 0
|
var savedProgress = 0
|
||||||
|
|
||||||
@ -63,7 +110,7 @@ class UpdaterService : IntentService(UpdaterService::class.java.name) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Download the new update.
|
// 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.
|
// File where the apk will be saved.
|
||||||
val apkFile = File(externalCacheDir, "update.apk")
|
val apkFile = File(externalCacheDir, "update.apk")
|
||||||
@ -82,27 +129,38 @@ class UpdaterService : IntentService(UpdaterService::class.java.name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
|
||||||
* Download url.
|
|
||||||
*/
|
|
||||||
internal const val EXTRA_DOWNLOAD_URL = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_URL"
|
|
||||||
|
|
||||||
/**
|
internal const val EXTRA_DOWNLOAD_URL = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_URL"
|
||||||
* Download title
|
|
||||||
*/
|
|
||||||
internal const val EXTRA_DOWNLOAD_TITLE = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_TITLE"
|
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 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 {
|
val intent = Intent(context, UpdaterService::class.java).apply {
|
||||||
putExtra(EXTRA_DOWNLOAD_TITLE, title)
|
putExtra(EXTRA_DOWNLOAD_TITLE, title)
|
||||||
putExtra(EXTRA_DOWNLOAD_URL, url)
|
putExtra(EXTRA_DOWNLOAD_URL, url)
|
||||||
}
|
}
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
context.startService(intent)
|
context.startService(intent)
|
||||||
|
} else {
|
||||||
|
context.startForegroundService(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,7 +187,7 @@ class AboutController : SettingsController() {
|
|||||||
if (appContext != null) {
|
if (appContext != null) {
|
||||||
// Start download
|
// Start download
|
||||||
val url = args.getString(URL_KEY) ?: ""
|
val url = args.getString(URL_KEY) ?: ""
|
||||||
UpdaterService.downloadUpdate(appContext, url)
|
UpdaterService.start(appContext, url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.negativeButton(R.string.update_check_ignore)
|
.negativeButton(R.string.update_check_ignore)
|
||||||
|
Loading…
Reference in New Issue
Block a user