Stop per-app download notification chatter during installs
The download worker posted a separate per-app notification for every internal phase transition, keyed by package hash and distinct from the ongoing foreground progress notification. In practice this meant: - a blank, non-dismissable notification while "purchasing" (no branch rendered it), and - a transient "download complete" notice for every app that was then immediately replaced by the install-success notification. During a bulk update this produced a burst of redundant notifications. Suppress the purchasing/verifying phases (the ongoing progress notification already conveys activity) and only surface completion when the user must act on it (apps that can't be installed silently get a tap-to-install notice). Silently-installable apps now go straight to a single "installed" notification. Also clear any stale per-app notification on these phases and on cancellation, fixing a leak where a cancelled download left its last notification behind, and refresh the foreground notification to an "Installing" state so the user sees a clean downloading -> installing progression instead of a download bar stuck at 100%.
This commit is contained in:
@@ -252,6 +252,10 @@ class DownloadWorker @AssistedInject constructor(
|
||||
private suspend fun onSuccess(): Result {
|
||||
return withContext(NonCancellable) {
|
||||
return@withContext try {
|
||||
// Update the ongoing foreground notification to reflect the install phase,
|
||||
// so the user sees a clean "Downloading -> Installing" progression instead of
|
||||
// a stale download bar lingering at 100%.
|
||||
notifyStatus(DownloadStatus.INSTALLING, isProgress = true)
|
||||
appInstaller.getPreferredInstaller(notifyOnFallback = true).install(download)
|
||||
Result.success()
|
||||
} catch (exception: Exception) {
|
||||
@@ -537,13 +541,35 @@ class DownloadWorker @AssistedInject constructor(
|
||||
downloadDao.updateStatus(download.packageName, status)
|
||||
|
||||
when (status) {
|
||||
// Internal phases the user doesn't need a separate notification for: the ongoing
|
||||
// foreground progress notification already conveys that work is in progress.
|
||||
// Clear any stale per-app notification (e.g. a prior failure being retried) so it
|
||||
// doesn't linger.
|
||||
DownloadStatus.PURCHASING,
|
||||
DownloadStatus.VERIFYING,
|
||||
DownloadStatus.CANCELLED -> return
|
||||
DownloadStatus.CANCELLED -> {
|
||||
notificationManager.cancel(download.packageName.hashCode())
|
||||
return
|
||||
}
|
||||
|
||||
DownloadStatus.COMPLETED -> {
|
||||
// Mark progress as 100 manually to avoid race conditions
|
||||
download.progress = 100
|
||||
downloadDao.updateProgress(download.packageName, 100, 0, 0)
|
||||
|
||||
// Silently-installable apps install automatically and get a single
|
||||
// "installed" notification afterwards, so a separate "download complete"
|
||||
// notice is just noise. Only surface completion when the user must act on it
|
||||
// (tap to install).
|
||||
val needsUserAction = !AppInstaller.canInstallSilently(
|
||||
context,
|
||||
download.packageName,
|
||||
download.targetSdk
|
||||
)
|
||||
if (!needsUserAction) {
|
||||
notificationManager.cancel(download.packageName.hashCode())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
|
||||
@@ -208,6 +208,15 @@ object NotificationUtil {
|
||||
)
|
||||
}
|
||||
|
||||
DownloadStatus.INSTALLING -> {
|
||||
builder.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
builder.setContentText(context.getString(R.string.status_installing))
|
||||
builder.setOngoing(true)
|
||||
builder.setCategory(Notification.CATEGORY_PROGRESS)
|
||||
builder.setProgress(100, 100, true)
|
||||
builder.foregroundServiceBehavior = NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
return builder.build()
|
||||
|
||||
Reference in New Issue
Block a user