Add Cancel button to App Update Notification (#7309)

* Add cancel button in app update download notif

Since stuck downloads are a common issue and only solution until now was
to force close the app or download and update the app manually by
downloading from GitHub (which clears the notif away)

Based on commit
4dea924337

Co-authored-by: Jays2Kings <8617760+Jays2Kings@users.noreply.github.com>

* Linting by Android Studio

* commit PR Review Suggestion

Update app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt

Co-authored-by: arkon <arkon@users.noreply.github.com>

* Use `launchIO`

copied this over from how j2k was doing it. Launching in IO Thread like
how it was before this PR is sufficient

* Clear previous actions before adding `Cancel`

Otherwise, it led to two identical Cancel buttons

Co-authored-by: Jays2Kings <8617760+Jays2Kings@users.noreply.github.com>
Co-authored-by: arkon <arkon@users.noreply.github.com>
This commit is contained in:
nicki 2022-06-16 03:37:01 +05:30 committed by GitHub
parent 284880d096
commit fdf384b809
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 4 deletions

View file

@ -16,6 +16,7 @@ import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.updater.AppUpdateService
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController
@ -82,6 +83,8 @@ class NotificationReceiver : BroadcastReceiver() {
)
// Cancel library update and dismiss notification
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context, Notifications.ID_LIBRARY_PROGRESS)
// Cancel downloading app update
ACTION_CANCEL_APP_UPDATE_DOWNLOAD -> cancelDownloadAppUpdate(context)
// Open reader activity
ACTION_OPEN_CHAPTER -> {
openChapter(
@ -218,6 +221,10 @@ class NotificationReceiver : BroadcastReceiver() {
ContextCompat.getMainExecutor(context).execute { dismissNotification(context, notificationId) }
}
private fun cancelDownloadAppUpdate(context: Context) {
AppUpdateService.stop(context)
}
/**
* Method called when user wants to mark manga chapters as read
*
@ -279,6 +286,8 @@ class NotificationReceiver : BroadcastReceiver() {
private const val ACTION_CANCEL_LIBRARY_UPDATE = "$ID.$NAME.CANCEL_LIBRARY_UPDATE"
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_OPEN_CHAPTER = "$ID.$NAME.ACTION_OPEN_CHAPTER"
private const val ACTION_DOWNLOAD_CHAPTER = "$ID.$NAME.ACTION_DOWNLOAD_CHAPTER"
@ -508,6 +517,16 @@ class NotificationReceiver : BroadcastReceiver() {
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
}
/**
*
*/
internal fun cancelUpdateDownloadPendingBroadcast(context: Context): PendingIntent {
val intent = Intent(context, NotificationReceiver::class.java).apply {
action = ACTION_CANCEL_APP_UPDATE_DOWNLOAD
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
}
/**
* Returns [PendingIntent] that opens the extensions controller.
*

View file

@ -88,6 +88,13 @@ internal class AppUpdateNotifier(private val context: Context) {
setContentText(context.getString(R.string.update_check_notification_download_in_progress))
setSmallIcon(android.R.drawable.stat_sys_download)
setOngoing(true)
clearActions()
addAction(
R.drawable.ic_close_24dp,
context.getString(R.string.action_cancel),
NotificationReceiver.cancelUpdateDownloadPendingBroadcast(context),
)
}
notificationBuilder.show()
return notificationBuilder
@ -162,4 +169,8 @@ internal class AppUpdateNotifier(private val context: Context) {
}
notificationBuilder.show(Notifications.ID_APP_UPDATER)
}
fun cancel() {
NotificationReceiver.dismissNotification(context, Notifications.ID_APP_UPDATER)
}
}

View file

@ -21,7 +21,12 @@ 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.logcat
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Job
import logcat.LogPriority
import okhttp3.Call
import okhttp3.internal.http2.ErrorCode
import okhttp3.internal.http2.StreamResetException
import uy.kohesive.injekt.injectLazy
import java.io.File
@ -36,6 +41,10 @@ class AppUpdateService : Service() {
private lateinit var notifier: AppUpdateNotifier
private var runningJob: Job? = null
private var runningCall: Call? = null
override fun onCreate() {
super.onCreate()
@ -56,11 +65,11 @@ class AppUpdateService : Service() {
val url = intent.getStringExtra(EXTRA_DOWNLOAD_URL) ?: return START_NOT_STICKY
val title = intent.getStringExtra(EXTRA_DOWNLOAD_TITLE) ?: getString(R.string.app_name)
launchIO {
runningJob = launchIO {
downloadApk(title, url)
}
stopSelf(startId)
runningJob?.invokeOnCompletion { stopSelf(startId) }
return START_NOT_STICKY
}
@ -75,6 +84,8 @@ class AppUpdateService : Service() {
}
private fun destroyJob() {
runningJob?.cancel()
runningCall?.cancel()
if (wakeLock.isHeld) {
wakeLock.release()
}
@ -109,7 +120,9 @@ class AppUpdateService : Service() {
try {
// 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.
val apkFile = File(externalCacheDir, "update.apk")
@ -123,9 +136,15 @@ class AppUpdateService : Service() {
notifier.onDownloadFinished(apkFile.getUriCompat(this))
} catch (error: Exception) {
logcat(LogPriority.ERROR, error)
if (error is CancellationException ||
(error is StreamResetException && error.errorCode == ErrorCode.CANCEL)
) {
notifier.cancel()
} else {
notifier.onDownloadError(url)
}
}
}
companion object {
@ -157,6 +176,15 @@ class AppUpdateService : Service() {
}
}
/**
* 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.
*