Notification Channels

Notification Channels and Permission

Since Android 8 (API 26) every notification belongs to a channel, and the user, not the app, controls each channel's importance, sound and visibility in system settings. Create one channel per kind of message, so someone can mute "Catalog sync" and keep "Price drops" (Notification Channels met the same idea from React Native 36,878 ). Creating an existing channel again changes nothing, so BookNest does it on every start, from BookNestApp.onCreate():

notify/Notifications.kt: two channels with different importanceKotlin
  fun createChannels(context: Context) {
    NotificationManagerCompat.from(context).createNotificationChannelsCompat(listOf(
      NotificationChannelCompat.Builder(DEALS, NotificationManagerCompat.IMPORTANCE_DEFAULT)
        .setName("Price drops")
        .setDescription("A book you might like is cheaper")
        .build(),
      NotificationChannelCompat.Builder(SYNC, NotificationManagerCompat.IMPORTANCE_LOW)
        .setName("Catalog sync")                    // silent, no heads-up
        .build(),
    ))
  }

Since Android 13, posting also needs the POST_NOTIFICATIONS runtime permission. An app targeting API 33+ decides when to ask (older targets get the dialog on their first channel), and the guidance is to ask when the user turns on a feature that needs it, never at first launch:

ui/AlertsScreen.kt: requesting the permission in context (excerpt)Kotlin
  var allowed by remember { mutableStateOf(BookNestNotifications.canPost(context)) }
  val askPermission = rememberLauncherForActivityResult(
    ActivityResultContracts.RequestPermission()
  ) { granted ->
    allowed = granted
    Log.i("BookNestNotify", "POST_NOTIFICATIONS granted=$granted")
  }
  ...
    if (!allowed && Build.VERSION.SDK_INT >= 33) {
      Button(onClick = { askPermission.launch(Manifest.permission.POST_NOTIFICATIONS) }) {
        Text("Turn on price alerts")
      }
    }
The notification permission dialog, and the widget pin request of Section 5.30.4
The notification permission dialog, and the widget pin request of Glance Widgets

After two denials the dialog stops appearing and the callback gets false at once; only a link to Settings.ACTION_APP_NOTIFICATION_SETTINGS helps then.