Restructure notification channels by intent and importance
Notifications were too intrusive: install-success and export sat on IMPORTANT_HIGH channels and produced heads-up alerts for every app, while genuine download failures were buried in the IMPORTANCE_MIN downloads channel where they were easily missed. Restructure the channels around user intent: - Download progress -> MIN, silent, no badge - Installed apps -> LOW, silent (was HIGH) - Updates available -> DEFAULT, silent - App export -> LOW, silent (was HIGH) - Errors & alerts -> HIGH (new, the only heads-up channel) Failed downloads, installer-status errors and the unarchive auth prompt now route to the high-importance alerts channel so they aren't lost, while successful installs/exports stay quiet. Android ignores importance edits on an already-created channel, so the install/export channels get new IDs and the retired IDs (including the folded-in account channel) are deleted on next launch.
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -32,38 +32,42 @@ object NotificationUtil {
|
||||
|
||||
fun createNotificationChannel(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val notificationManager = context.getSystemService<NotificationManager>()
|
||||
val notificationManager = context.getSystemService<NotificationManager>()!!
|
||||
|
||||
// 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<NotificationChannel>()
|
||||
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))
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
<string name="device_miui_extra">"Optionally you can choose Native installer, but then you can not install bundled (split) APKs, so choice is yours."</string>
|
||||
<string name="dialog_title_self_update">"New update available"</string>
|
||||
<string name="dialog_desc_native_split">"You can not install bundled (split) apps via Native Installer. Change your installer to Session, Services or Root."</string>
|
||||
<string name="notification_channel_account">Account-related notification</string>
|
||||
<string name="notification_channel_alerts">Errors & alerts</string>
|
||||
<string name="notification_channel_export">App export notification</string>
|
||||
<string name="notification_channel_install">Install notification</string>
|
||||
<string name="notification_channel_downloads">Downloads notification</string>
|
||||
|
||||
Reference in New Issue
Block a user