From fdf384b8092d09f0a4e68c5688f9c1c1e94c80d0 Mon Sep 17 00:00:00 2001 From: nicki <72807749+curche@users.noreply.github.com> Date: Thu, 16 Jun 2022 03:37:01 +0530 Subject: [PATCH] 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 https://github.com/Jays2Kings/tachiyomiJ2K/commit/4dea924337ffd4a01342fa0b48da47c221d2b897 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 * 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 --- .../data/notification/NotificationReceiver.kt | 19 ++++++++++ .../data/updater/AppUpdateNotifier.kt | 11 ++++++ .../data/updater/AppUpdateService.kt | 36 ++++++++++++++++--- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt index 47039a174..7fc7415c8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt @@ -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. * diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt index 25b96cd02..ae8846c5a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateNotifier.kt @@ -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) + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt index 5a8808fcc..00ddbd2f7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateService.kt @@ -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,7 +136,13 @@ class AppUpdateService : Service() { notifier.onDownloadFinished(apkFile.getUriCompat(this)) } catch (error: Exception) { logcat(LogPriority.ERROR, error) - notifier.onDownloadError(url) + if (error is CancellationException || + (error is StreamResetException && error.errorCode == ErrorCode.CANCEL) + ) { + notifier.cancel() + } else { + notifier.onDownloadError(url) + } } } @@ -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. *