Show an installing notification for auto app updates

Also show a button in the notification to open the app once updated
Closes #1545
This commit is contained in:
Jays2Kings 2023-04-16 16:36:35 -04:00
parent 2ca170d403
commit ebe8edb110
5 changed files with 48 additions and 3 deletions

View file

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.data.notification package eu.kanade.tachiyomi.data.notification
import android.app.Notification
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationChannelGroup import android.app.NotificationChannelGroup
import android.app.NotificationManager import android.app.NotificationManager
@ -21,8 +22,10 @@ object Notifications {
const val ID_UPDATER = 1 const val ID_UPDATER = 1
const val ID_DOWNLOAD_IMAGE = 2 const val ID_DOWNLOAD_IMAGE = 2
const val ID_INSTALL = 3 const val ID_INSTALL = 3
const val CHANNEL_INSTALLING = "installing_channel"
const val CHANNEL_UPDATED = "updated_channel" const val CHANNEL_UPDATED = "updated_channel"
const val ID_INSTALLED = -6 const val ID_INSTALLED = -6
const val GROUP_APP_UPDATES = "eu.kanade.tachiyomi.APP_UPDATES"
/** /**
* Notification channel and ids used by the downloader. * Notification channel and ids used by the downloader.
@ -108,6 +111,7 @@ object Notifications {
GROUP_EXTENSION_UPDATES, GROUP_EXTENSION_UPDATES,
context.getString(R.string.extension_updates), context.getString(R.string.extension_updates),
), ),
NotificationChannelGroup(GROUP_APP_UPDATES, context.getString(R.string.app_updates)),
NotificationChannelGroup(GROUP_LIBRARY, context.getString(R.string.library)), NotificationChannelGroup(GROUP_LIBRARY, context.getString(R.string.library)),
).forEach(context.notificationManager::createNotificationChannelGroup) ).forEach(context.notificationManager::createNotificationChannelGroup)
@ -188,7 +192,9 @@ object Notifications {
CHANNEL_INCOGNITO_MODE, CHANNEL_INCOGNITO_MODE,
context.getString(R.string.incognito_mode), context.getString(R.string.incognito_mode),
NotificationManager.IMPORTANCE_LOW, NotificationManager.IMPORTANCE_LOW,
), ).apply {
lockscreenVisibility = Notification.VISIBILITY_SECRET
},
NotificationChannel( NotificationChannel(
CHANNEL_EXT_PROGRESS, CHANNEL_EXT_PROGRESS,
context.getString(R.string.updating_extensions), context.getString(R.string.updating_extensions),
@ -205,12 +211,23 @@ object Notifications {
).apply { ).apply {
group = GROUP_EXTENSION_UPDATES group = GROUP_EXTENSION_UPDATES
}, },
NotificationChannel(
CHANNEL_INSTALLING,
context.getString(R.string.installing),
NotificationManager.IMPORTANCE_HIGH,
).apply {
setShowBadge(false)
setSound(null, null)
enableVibration(false)
group = GROUP_APP_UPDATES
},
NotificationChannel( NotificationChannel(
CHANNEL_UPDATED, CHANNEL_UPDATED,
context.getString(R.string.update_completed), context.getString(R.string.update_completed),
NotificationManager.IMPORTANCE_HIGH, NotificationManager.IMPORTANCE_HIGH,
).apply { ).apply {
setShowBadge(false) setShowBadge(false)
group = GROUP_APP_UPDATES
}, },
) )
context.notificationManager.createNotificationChannels(channels) context.notificationManager.createNotificationChannels(channels)

View file

@ -38,7 +38,9 @@ class AppUpdateBroadcast : BroadcastReceiver() {
if (status != PackageInstaller.STATUS_FAILURE_ABORTED) { if (status != PackageInstaller.STATUS_FAILURE_ABORTED) {
context.toast(R.string.could_not_install_update) context.toast(R.string.could_not_install_update)
val uri = intent.getStringExtra(AppUpdateService.EXTRA_FILE_URI) ?: return val uri = intent.getStringExtra(AppUpdateService.EXTRA_FILE_URI) ?: return
AppUpdateNotifier(context.localeContext).onInstallError(uri.toUri()) val appUpdateNotifier = AppUpdateNotifier(context.localeContext)
appUpdateNotifier.cancelInstallNotification()
appUpdateNotifier.onInstallError(uri.toUri())
} }
} }
} }

View file

@ -141,6 +141,17 @@ internal class AppUpdateNotifier(private val context: Context) {
notificationBuilder.show() notificationBuilder.show()
} }
fun onInstalling() {
with(NotificationCompat.Builder(context, Notifications.CHANNEL_INSTALLING)) {
setContentTitle(context.getString(R.string.installing))
setSmallIcon(android.R.drawable.stat_sys_download)
setProgress(0, 0, true)
setOnlyAlertOnce(true)
clearActions()
show(Notifications.ID_INSTALL)
}
}
/** /**
* Call when apk download is finished. * Call when apk download is finished.
* *
@ -179,7 +190,8 @@ internal class AppUpdateNotifier(private val context: Context) {
*/ */
fun onInstallFinished() { fun onInstallFinished() {
with(NotificationCompat.Builder(context, Notifications.CHANNEL_UPDATED)) { with(NotificationCompat.Builder(context, Notifications.CHANNEL_UPDATED)) {
setContentTitle(context.getString(R.string.updated_to_, BuildConfig.VERSION_NAME)) setContentTitle(context.getString(R.string.update_completed))
setContentText(context.getString(R.string.updated_to_, BuildConfig.VERSION_NAME))
setSmallIcon(R.drawable.ic_tachij2k_notification) setSmallIcon(R.drawable.ic_tachij2k_notification)
setAutoCancel(true) setAutoCancel(true)
setOngoing(false) setOngoing(false)
@ -192,6 +204,11 @@ internal class AppUpdateNotifier(private val context: Context) {
) )
setContentIntent(pendingIntent) setContentIntent(pendingIntent)
clearActions() clearActions()
addAction(
R.drawable.ic_system_update_24dp,
context.getString(R.string.open),
pendingIntent,
)
addReleasePageAction() addReleasePageAction()
show(Notifications.ID_INSTALLED) show(Notifications.ID_INSTALLED)
} }
@ -258,4 +275,8 @@ internal class AppUpdateNotifier(private val context: Context) {
fun cancel() { fun cancel() {
NotificationReceiver.dismissNotification(context, Notifications.ID_UPDATER) NotificationReceiver.dismissNotification(context, Notifications.ID_UPDATER)
} }
fun cancelInstallNotification() {
NotificationReceiver.dismissNotification(context, Notifications.ID_INSTALL)
}
} }

View file

@ -200,6 +200,7 @@ class AppUpdateService : Service() {
val pendingIntent = PendingIntent.getBroadcast(this, -10053, newIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE) val pendingIntent = PendingIntent.getBroadcast(this, -10053, newIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
val statusReceiver = pendingIntent.intentSender val statusReceiver = pendingIntent.intentSender
session.commit(statusReceiver) session.commit(statusReceiver)
notifier.onInstalling()
data.close() data.close()
val hasNotification by lazy { val hasNotification by lazy {
@ -210,6 +211,7 @@ class AppUpdateService : Service() {
// If the package manager crashes for whatever reason (china phone) set a timeout // If the package manager crashes for whatever reason (china phone) set a timeout
// and let the user manually install // and let the user manually install
if (packageInstaller.getSessionInfo(sessionId) == null && !hasNotification) { if (packageInstaller.getSessionInfo(sessionId) == null && !hasNotification) {
notifier.cancelInstallNotification()
notifier.onDownloadFinished(file.getUriCompat(this@AppUpdateService)) notifier.onDownloadFinished(file.getUriCompat(this@AppUpdateService))
PreferenceManager.getDefaultSharedPreferences(this@AppUpdateService).edit { PreferenceManager.getDefaultSharedPreferences(this@AppUpdateService).edit {
remove(NOTIFY_ON_INSTALL_KEY) remove(NOTIFY_ON_INSTALL_KEY)
@ -220,6 +222,7 @@ class AppUpdateService : Service() {
// Either install package can't be found (probably bots) or there's a security exception // Either install package can't be found (probably bots) or there's a security exception
// with the download manager. Nothing we can workaround. // with the download manager. Nothing we can workaround.
toast(error.message) toast(error.message)
notifier.cancelInstallNotification()
notifier.onDownloadFinished(file.getUriCompat(this)) notifier.onDownloadFinished(file.getUriCompat(this))
PreferenceManager.getDefaultSharedPreferences(this).edit { PreferenceManager.getDefaultSharedPreferences(this).edit {
remove(NOTIFY_ON_INSTALL_KEY) remove(NOTIFY_ON_INSTALL_KEY)

View file

@ -727,6 +727,7 @@
<string name="system_default">System default</string> <string name="system_default">System default</string>
<string name="date_format">Date format</string> <string name="date_format">Date format</string>
<string name="check_for_updates">Check for updates</string> <string name="check_for_updates">Check for updates</string>
<string name="app_updates">App updates</string>
<string name="updated_to_">Updated to v%1$s</string> <string name="updated_to_">Updated to v%1$s</string>
<string name="secure_screen">Secure screen</string> <string name="secure_screen">Secure screen</string>
<string name="secure_screen_summary">Secure screen hides app contents when switching apps and block screenshots</string> <string name="secure_screen_summary">Secure screen hides app contents when switching apps and block screenshots</string>
@ -1131,6 +1132,7 @@
<string name="no_animation">No animation</string> <string name="no_animation">No animation</string>
<string name="normal">Normal</string> <string name="normal">Normal</string>
<string name="oldest">Oldest</string> <string name="oldest">Oldest</string>
<string name="open">Open</string>
<string name="open_in_app">Open in app</string> <string name="open_in_app">Open in app</string>
<string name="open_in_browser">Open in browser</string> <string name="open_in_browser">Open in browser</string>
<string name="open_log">Open log</string> <string name="open_log">Open log</string>