git.iko.soy/opencode-android
on 9f0326a help sign in
65 lines 3.3 kB history raw
1package soy.iko.opencode.notification
3import android.app.NotificationChannel
4import android.app.NotificationManager
5import android.content.Context
6import soy.iko.opencode.R
8/**
9 * The app's notification channels. Created once at startup (idempotent — recreating an
10 * existing channel is a no-op). Two channels keep user control granular:
11 *
12 * - [STATUS]: low-importance, no sound. Used by the foreground service's persistent
13 * "agent running" indicator.
14 * - [COMPLETED]: default importance. Used when a background session finishes a run.
15 * - [PERMISSION]: high importance (heads-up + sound). Used when a paused tool run needs
16 * the user's approval — the whole point is to reach the user who has walked away, so it
17 * interrupts rather than sitting silently in the shade.
18 * - [ERROR]: default importance. Used when a background run fails.
19 */
20object NotificationChannels {
21 const val STATUS = "run_status"
22 const val COMPLETED = "session_completed"
23 const val PERMISSION = "permission_request"
24 const val ERROR = "session_error"
25 const val UNREAD = "unread_badge"
27 fun create(context: Context) {
28 val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager ?: return
29 nm.createNotificationChannel(
30 NotificationChannel(STATUS, context.getString(R.string.notif_channel_status), NotificationManager.IMPORTANCE_LOW).apply {
31 description = context.getString(R.string.notif_channel_status_desc)
32 setShowBadge(false)
33 },
34 )
35 nm.createNotificationChannel(
36 NotificationChannel(COMPLETED, context.getString(R.string.notif_channel_completed), NotificationManager.IMPORTANCE_DEFAULT).apply {
37 description = context.getString(R.string.notif_channel_completed_desc)
38 },
39 )
40 nm.createNotificationChannel(
41 NotificationChannel(PERMISSION, context.getString(R.string.notif_channel_permission), NotificationManager.IMPORTANCE_HIGH).apply {
42 description = context.getString(R.string.notif_channel_permission_desc)
43 },
44 )
45 nm.createNotificationChannel(
46 // HIGH importance so a failed run stands out from a completed one by
47 // sound/vibration — both are actionable, but a failure is time-sensitive.
48 NotificationChannel(ERROR, context.getString(R.string.notif_channel_error), NotificationManager.IMPORTANCE_HIGH).apply {
49 description = context.getString(R.string.notif_channel_error_desc)
50 },
51 )
52 // A silent, badge-only channel that carries the launcher icon's unread count (the only
53 // way to badge the launcher icon on Android is via a notification on a badge-enabled
54 // channel). Low importance + no sound/vibration so it never alerts; setShowBadge(true)
55 // so its number renders on the launcher icon.
56 nm.createNotificationChannel(
57 NotificationChannel(UNREAD, context.getString(R.string.notif_channel_unread), NotificationManager.IMPORTANCE_MIN).apply {
58 description = context.getString(R.string.notif_channel_unread_desc)
59 setShowBadge(true)
60 setSound(null, null)
61 enableVibration(false)
62 },
63 )
64 }