mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-09 05:25:08 +01:00
Add cancel button in notification to cancel download of updated version
Since if a download gets stuck theres no way to cancel it (then again updating form GitHub would clear this out)
This commit is contained in:
parent
3255fac29e
commit
4dea924337
@ -19,6 +19,7 @@ import eu.kanade.tachiyomi.data.download.DownloadManager
|
|||||||
import eu.kanade.tachiyomi.data.download.DownloadService
|
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.data.updater.UpdaterService
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
||||||
@ -72,6 +73,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
)
|
)
|
||||||
// Cancel library update and dismiss notification
|
// Cancel library update and dismiss notification
|
||||||
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context)
|
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context)
|
||||||
|
ACTION_CANCEL_UPDATE_DOWNLOAD -> cancelDownloadUpdate(context)
|
||||||
ACTION_CANCEL_RESTORE -> cancelRestoreUpdate(context)
|
ACTION_CANCEL_RESTORE -> cancelRestoreUpdate(context)
|
||||||
// Share backup file
|
// Share backup file
|
||||||
ACTION_SHARE_BACKUP ->
|
ACTION_SHARE_BACKUP ->
|
||||||
@ -262,6 +264,10 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
Handler().post { dismissNotification(context, Notifications.ID_RESTORE_PROGRESS) }
|
Handler().post { dismissNotification(context, Notifications.ID_RESTORE_PROGRESS) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun cancelDownloadUpdate(context: Context) {
|
||||||
|
UpdaterService.stop(context)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val NAME = "NotificationReceiver"
|
private const val NAME = "NotificationReceiver"
|
||||||
|
|
||||||
@ -600,6 +606,19 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [PendingIntent] that cancels the download for a Tachiyomi update
|
||||||
|
*
|
||||||
|
* @param context context of application
|
||||||
|
* @return [PendingIntent]
|
||||||
|
*/
|
||||||
|
internal fun cancelUpdateDownloadPendingBroadcast(context: Context): PendingIntent {
|
||||||
|
val intent = Intent(context, NotificationReceiver::class.java).apply {
|
||||||
|
action = ACTION_CANCEL_UPDATE_DOWNLOAD
|
||||||
|
}
|
||||||
|
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns [PendingIntent] that starts a share activity for a backup file.
|
* Returns [PendingIntent] that starts a share activity for a backup file.
|
||||||
*
|
*
|
||||||
|
@ -99,6 +99,12 @@ internal class UpdaterNotifier(private val context: Context) {
|
|||||||
setOngoing(true)
|
setOngoing(true)
|
||||||
clearActions()
|
clearActions()
|
||||||
|
|
||||||
|
// Cancel action
|
||||||
|
addAction(
|
||||||
|
R.drawable.ic_close_24dp,
|
||||||
|
context.getString(R.string.cancel),
|
||||||
|
NotificationReceiver.cancelUpdateDownloadPendingBroadcast(context)
|
||||||
|
)
|
||||||
addReleasePageAction()
|
addReleasePageAction()
|
||||||
}
|
}
|
||||||
notificationBuilder.show()
|
notificationBuilder.show()
|
||||||
@ -179,5 +185,8 @@ internal class UpdaterNotifier(private val context: Context) {
|
|||||||
}
|
}
|
||||||
notificationBuilder.show(Notifications.ID_UPDATER)
|
notificationBuilder.show(Notifications.ID_UPDATER)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun cancel() {
|
||||||
|
NotificationReceiver.dismissNotification(context, Notifications.ID_UPDATER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,17 @@ import eu.kanade.tachiyomi.network.await
|
|||||||
import eu.kanade.tachiyomi.network.newCallWithProgress
|
import eu.kanade.tachiyomi.network.newCallWithProgress
|
||||||
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.acquireWakeLock
|
||||||
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
import eu.kanade.tachiyomi.util.system.isServiceRunning
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.CancellationException
|
||||||
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import okhttp3.Call
|
||||||
|
import okhttp3.internal.http2.ErrorCode
|
||||||
|
import okhttp3.internal.http2.StreamResetException
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -36,17 +43,17 @@ class UpdaterService : Service() {
|
|||||||
|
|
||||||
private lateinit var notifier: UpdaterNotifier
|
private lateinit var notifier: UpdaterNotifier
|
||||||
|
|
||||||
|
private var runningJob: Job? = null
|
||||||
|
|
||||||
|
private var runningCall: Call? = null
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
notifier = UpdaterNotifier(this)
|
notifier = UpdaterNotifier(this)
|
||||||
|
|
||||||
startForeground(Notifications.ID_UPDATER, notifier.onDownloadStarted(getString(R.string.app_name)).build())
|
startForeground(Notifications.ID_UPDATER, notifier.onDownloadStarted(getString(R.string.app_name)).build())
|
||||||
|
|
||||||
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
|
wakeLock = acquireWakeLock(javaClass.name)
|
||||||
PowerManager.PARTIAL_WAKE_LOCK,
|
|
||||||
"${javaClass.name}:WakeLock"
|
|
||||||
)
|
|
||||||
wakeLock.acquire()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,14 +64,20 @@ class UpdaterService : Service() {
|
|||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
if (intent == null) return START_NOT_STICKY
|
if (intent == null) return START_NOT_STICKY
|
||||||
|
|
||||||
|
val handler = CoroutineExceptionHandler { _, exception ->
|
||||||
|
Timber.e(exception)
|
||||||
|
stopSelf(startId)
|
||||||
|
}
|
||||||
|
|
||||||
val url = intent.getStringExtra(EXTRA_DOWNLOAD_URL) ?: 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)
|
||||||
|
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
runningJob = GlobalScope.launch(handler) {
|
||||||
downloadApk(title, url)
|
downloadApk(title, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
stopSelf(startId)
|
runningJob?.invokeOnCompletion { stopSelf(startId) }
|
||||||
|
|
||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +92,8 @@ class UpdaterService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun destroyJob() {
|
private fun destroyJob() {
|
||||||
|
runningJob?.cancel()
|
||||||
|
runningCall?.cancel()
|
||||||
if (wakeLock.isHeld) {
|
if (wakeLock.isHeld) {
|
||||||
wakeLock.release()
|
wakeLock.release()
|
||||||
}
|
}
|
||||||
@ -113,7 +128,9 @@ class UpdaterService : Service() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Download the new update.
|
// Download the new update.
|
||||||
val response = network.client.newCallWithProgress(GET(url), progressListener).await()
|
val call = network.client.newCallWithProgress(GET(url), progressListener)
|
||||||
|
runningCall = call
|
||||||
|
val response = call.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")
|
||||||
@ -127,9 +144,15 @@ class UpdaterService : Service() {
|
|||||||
notifier.onDownloadFinished(apkFile.getUriCompat(this))
|
notifier.onDownloadFinished(apkFile.getUriCompat(this))
|
||||||
} catch (error: Exception) {
|
} catch (error: Exception) {
|
||||||
Timber.e(error)
|
Timber.e(error)
|
||||||
|
if (error is CancellationException ||
|
||||||
|
(error is StreamResetException && error.errorCode == ErrorCode.CANCEL)
|
||||||
|
) {
|
||||||
|
notifier.cancel()
|
||||||
|
} else {
|
||||||
notifier.onDownloadError(url)
|
notifier.onDownloadError(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@ -164,6 +187,15 @@ class UpdaterService : Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the service.
|
||||||
|
*
|
||||||
|
* @param context the application context.
|
||||||
|
*/
|
||||||
|
fun stop(context: Context) {
|
||||||
|
context.stopService(Intent(context, UpdaterService::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns [PendingIntent] that starts a service which downloads the apk specified in url.
|
* Returns [PendingIntent] that starts a service which downloads the apk specified in url.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user