diff --git a/app/src/main/java/com/aurora/Constants.kt b/app/src/main/java/com/aurora/Constants.kt index 29e9d0ce6..d42a65c56 100644 --- a/app/src/main/java/com/aurora/Constants.kt +++ b/app/src/main/java/com/aurora/Constants.kt @@ -42,11 +42,22 @@ object Constants { const val UPDATE_URL_NIGHTLY = "https://auroraoss.com/downloads/AuroraStore/Feeds/nightly_feed.json" - const val NOTIFICATION_CHANNEL_EXPORT = "NOTIFICATION_CHANNEL_EXPORT" - const val NOTIFICATION_CHANNEL_INSTALL = "NOTIFICATION_CHANNEL_INSTALL" + // Channel IDs carry a version suffix where the importance changed from a previous + // release: Android ignores importance edits on an already-created channel, so a new ID + // is the only way to roll out a lower importance. Retired IDs are listed in + // [LEGACY_NOTIFICATION_CHANNELS] so they can be deleted on next launch. + const val NOTIFICATION_CHANNEL_EXPORT = "NOTIFICATION_CHANNEL_EXPORT_V2" + const val NOTIFICATION_CHANNEL_INSTALL = "NOTIFICATION_CHANNEL_INSTALLED" const val NOTIFICATION_CHANNEL_DOWNLOADS = "NOTIFICATION_CHANNEL_DOWNLOADS" const val NOTIFICATION_CHANNEL_UPDATES = "NOTIFICATION_CHANNEL_UPDATES" - const val NOTIFICATION_CHANNEL_ACCOUNT = "NOTIFICATION_CHANNEL_ACCOUNT" + const val NOTIFICATION_CHANNEL_ALERTS = "NOTIFICATION_CHANNEL_ALERTS" + + // Channels removed or superseded by a higher-versioned ID; deleted on next launch. + val LEGACY_NOTIFICATION_CHANNELS = listOf( + "NOTIFICATION_CHANNEL_EXPORT", + "NOTIFICATION_CHANNEL_INSTALL", + "NOTIFICATION_CHANNEL_ACCOUNT" + ) const val GITLAB_URL = "https://gitlab.com/AuroraOSS/AuroraStore" const val URL_DISPENSER = "https://auroraoss.com/api/auth" diff --git a/app/src/main/java/com/aurora/store/util/NotificationUtil.kt b/app/src/main/java/com/aurora/store/util/NotificationUtil.kt index 36b6cea7a..a75b276d0 100644 --- a/app/src/main/java/com/aurora/store/util/NotificationUtil.kt +++ b/app/src/main/java/com/aurora/store/util/NotificationUtil.kt @@ -32,38 +32,42 @@ object NotificationUtil { fun createNotificationChannel(context: Context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val notificationManager = context.getSystemService() + val notificationManager = context.getSystemService()!! + + // Drop channels retired or superseded by a lower-importance replacement, so the + // user no longer sees stale entries in system settings. + Constants.LEGACY_NOTIFICATION_CHANNELS.forEach { + notificationManager.deleteNotificationChannel(it) + } + val channels = ArrayList() - channels.add( - NotificationChannel( - Constants.NOTIFICATION_CHANNEL_INSTALL, - context.getString(R.string.notification_channel_install), - NotificationManager.IMPORTANCE_HIGH - ).apply { - setSound(null, null) - } - ) - channels.add( - NotificationChannel( - Constants.NOTIFICATION_CHANNEL_EXPORT, - context.getString(R.string.notification_channel_export), - NotificationManager.IMPORTANCE_HIGH - ) - ) - channels.add( - NotificationChannel( - Constants.NOTIFICATION_CHANNEL_ACCOUNT, - context.getString(R.string.notification_channel_account), - NotificationManager.IMPORTANCE_HIGH - ) - ) + + // Quiet, ongoing progress for active downloads. MIN keeps it collapsed and out + // of the status bar where possible. channels.add( NotificationChannel( Constants.NOTIFICATION_CHANNEL_DOWNLOADS, context.getString(R.string.notification_channel_downloads), NotificationManager.IMPORTANCE_MIN - ) + ).apply { + setSound(null, null) + setShowBadge(false) + } ) + + // Silent confirmation that an app finished installing/updating. LOW so it lands + // in the shade without buzzing for every app during a bulk update. + channels.add( + NotificationChannel( + Constants.NOTIFICATION_CHANNEL_INSTALL, + context.getString(R.string.notification_channel_install), + NotificationManager.IMPORTANCE_LOW + ).apply { + setSound(null, null) + } + ) + + // New updates are available to install. DEFAULT but silent. channels.add( NotificationChannel( Constants.NOTIFICATION_CHANNEL_UPDATES, @@ -73,7 +77,29 @@ object NotificationUtil { setSound(null, null) } ) - notificationManager!!.createNotificationChannels(channels) + + // Background app export. LOW since it's user-initiated and non-urgent. + channels.add( + NotificationChannel( + Constants.NOTIFICATION_CHANNEL_EXPORT, + context.getString(R.string.notification_channel_export), + NotificationManager.IMPORTANCE_LOW + ).apply { + setSound(null, null) + } + ) + + // Things the user genuinely needs to act on: failed downloads/installs, pending + // user action and authentication prompts. HIGH so these aren't missed. + channels.add( + NotificationChannel( + Constants.NOTIFICATION_CHANNEL_ALERTS, + context.getString(R.string.notification_channel_alerts), + NotificationManager.IMPORTANCE_HIGH + ) + ) + + notificationManager.createNotificationChannels(channels) } } @@ -91,7 +117,14 @@ object NotificationUtil { largeIcon: Bitmap? = null, message: String? = null ): Notification { - val builder = NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_DOWNLOADS) + // Terminal failures go to the high-importance alerts channel so they aren't lost in + // the silent downloads channel; everything else stays quiet. + val channelId = if (download.status == DownloadStatus.FAILED) { + Constants.NOTIFICATION_CHANNEL_ALERTS + } else { + Constants.NOTIFICATION_CHANNEL_DOWNLOADS + } + val builder = NotificationCompat.Builder(context, channelId) builder.setSmallIcon(R.drawable.ic_notification_outlined) builder.setContentTitle(download.displayName) builder.setContentIntent(getContentIntentForDetails(context, download.packageName)) @@ -197,11 +230,12 @@ object NotificationUtil { packageName: String, displayName: String, content: String? - ): Notification = NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_INSTALL) + ): Notification = NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ALERTS) .setSmallIcon(R.drawable.ic_install) .setContentTitle(displayName) .setContentText(content) .setContentIntent(getContentIntentForDetails(context, packageName)) + .setCategory(Notification.CATEGORY_ERROR) .build() fun getUpdateNotification(context: Context): Notification = @@ -289,7 +323,7 @@ object NotificationUtil { .build() fun getUnarchiveAuthNotification(context: Context, packageName: String): Notification = - NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ACCOUNT) + NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ALERTS) .setSmallIcon(R.drawable.ic_account) .setContentTitle(context.getString(R.string.authentication_required_title)) .setContentText(context.getString(R.string.authentication_required_unarchive)) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8712221e4..81707e8b8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -211,7 +211,7 @@ "Optionally you can choose Native installer, but then you can not install bundled (split) APKs, so choice is yours." "New update available" "You can not install bundled (split) apps via Native Installer. Change your installer to Session, Services or Root." - Account-related notification + Errors & alerts App export notification Install notification Downloads notification