Skip to content

Commit 8016d96

Browse files
committed
FullCharge: Rebalance notification channel importance and naming
The reconnect-gesture channel drops from DEFAULT to LOW so it lands in the shade's silent section. DEFAULT bought nothing: all four foreground-service notifications share SESSION_ID and set onlyAlertOnce, so the reconnect countdown never re-alerted and the importance only produced one alert when the service went foreground. LOW keeps the status-bar icon that makes an armed gesture discoverable. The recovery channel goes the other way, DEFAULT to HIGH, and its notification gains CATEGORY_ERROR. It fires when the protective policy could not be restored, so the battery charges unprotected until the user intervenes — it was ranked below the charge alarm, a convenience reminder. It is rare, auto-cancels, and is withdrawn as soon as a restore succeeds. Neither importance change reaches an existing install: a channel's importance is fixed once created. That is deliberate — no migration channel ids while the app is pre-launch. The session channel is renamed "Temporary full charge" -> "Full charge and restore" because recovering() shares it with session(), so it covers both lifting the limit and putting it back. Its id stays temporary_full_charge; ids are permanent and changing one would reset the channel's settings. Names and descriptions, unlike importance, do update on an existing channel. Also extracts the two hardcoded English channel descriptions to strings.xml and adds the missing one for the recovery channel, which was the only channel describing itself with a bare name.
1 parent 17a86b6 commit 8016d96

2 files changed

Lines changed: 42 additions & 10 deletions

File tree

app/src/main/java/eu/darken/amply/fullcharge/core/SessionNotifications.kt

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,64 @@ import eu.darken.amply.main.ui.MainActivity
1818
object SessionNotifications {
1919
const val SESSION_ID = 4101
2020
private const val RECOVERY_ID = 4102
21+
// Channel ids are invisible to the user and permanent — changing one resets that channel's
22+
// settings — so this keeps its original id while its display name has moved on.
2123
private const val SESSION_CHANNEL = "temporary_full_charge"
2224
private const val GESTURE_CHANNEL = "reconnect_gesture"
2325
private const val RECOVERY_CHANNEL = "charge_policy_recovery"
2426
private const val MONITOR_CHANNEL = "background_monitor"
2527

2628
fun ensureChannels(context: Context) {
2729
val manager = context.getSystemService(NotificationManager::class.java)
30+
// Covers the whole temporary-override lifecycle — lifting the limit and putting it back —
31+
// because [recovering] shares it with [session]. Unlike importance, a channel's name and
32+
// description do update on an existing channel, so widening the wording reaches installs
33+
// that already have it.
2834
manager.createNotificationChannel(
2935
NotificationChannel(
3036
SESSION_CHANNEL,
3137
context.getString(R.string.session_channel_name),
3238
NotificationManager.IMPORTANCE_LOW,
3339
).apply {
34-
description = "Shows while Amply temporarily allows charging to 100%"
40+
description = context.getString(R.string.session_channel_description)
3541
setShowBadge(false)
3642
},
3743
)
38-
// Its own channel at DEFAULT importance so the persistent reconnect monitor is
39-
// reliably visible in the status bar (the shared low channel was easy to miss).
44+
// Its own channel, kept separate from the session so the user can silence one without the
45+
// other, but LOW: the gesture notification is a passive standing cue that can sit there for
46+
// hours, so it belongs in the shade's silent section. DEFAULT bought nothing anyway — all
47+
// notifications here share SESSION_ID and set onlyAlertOnce, so the reconnect countdown
48+
// never re-alerted; the importance only produced one ding when the service went foreground.
49+
// LOW still keeps a status-bar icon, which is what makes an armed gesture discoverable.
50+
// Importance is fixed once a channel exists, so this only takes effect on a fresh install —
51+
// deliberately not migrated with a new channel id while the app is pre-launch.
4052
manager.createNotificationChannel(
4153
NotificationChannel(
4254
GESTURE_CHANNEL,
4355
context.getString(R.string.gesture_channel_name),
44-
NotificationManager.IMPORTANCE_DEFAULT,
56+
NotificationManager.IMPORTANCE_LOW,
4557
).apply {
46-
description = "Shows while the reconnect-for-100% gesture is watching for a replug"
58+
description = context.getString(R.string.gesture_channel_description)
4759
setShowBadge(false)
4860
},
4961
)
62+
// HIGH, matching the charge alarm: this fires when the protective policy could NOT be
63+
// restored, so the battery charges unprotected until the user intervenes — the exact
64+
// failure the app exists to prevent, and one that otherwise goes unnoticed overnight. It
65+
// would be backwards for a convenience reminder to out-rank it. Rare, auto-cancelling, and
66+
// withdrawn the moment a restore succeeds, so the heads-up costs nothing when all is well.
5067
manager.createNotificationChannel(
5168
NotificationChannel(
5269
RECOVERY_CHANNEL,
5370
context.getString(R.string.recovery_channel_name),
54-
NotificationManager.IMPORTANCE_DEFAULT,
55-
),
71+
NotificationManager.IMPORTANCE_HIGH,
72+
).apply {
73+
description = context.getString(R.string.recovery_channel_description)
74+
},
5675
)
57-
// Quiet channel for the "alive only to observe battery" case (e.g. charge alarm). LOW so the
58-
// background foreground-service notification doesn't draw attention like the gesture cue.
76+
// Quiet channel for the "alive only to observe battery" case (e.g. charge alarm). Separate
77+
// from the gesture channel despite sharing LOW, so silencing the watcher's presence entirely
78+
// does not also hide the gesture that the user opted into.
5979
manager.createNotificationChannel(
6080
NotificationChannel(
6181
MONITOR_CHANNEL,
@@ -191,6 +211,12 @@ object SessionNotifications {
191211
return builder.build()
192212
}
193213

214+
/**
215+
* Progress while a restore converges on the charging hardware. Deliberately shares
216+
* [SESSION_CHANNEL] with [session] rather than the alerting recovery channel: this is the
217+
* passive end of the same override the user started, and the recovery channel is HIGH, which
218+
* would make it heads-up on every boot that owes a restore.
219+
*/
194220
fun recovering(context: Context): Notification {
195221
ensureChannels(context)
196222
val openPendingIntent = PendingIntent.getActivity(
@@ -236,6 +262,9 @@ object SessionNotifications {
236262
.setContentTitle(context.getString(R.string.recovery_notification_title))
237263
.setContentText(context.getString(bodyRes))
238264
.setContentIntent(openIntent)
265+
// The only notification here reporting a failed state, so it is the only one
266+
// that should rank and filter as an error rather than as service noise.
267+
.setCategory(NotificationCompat.CATEGORY_ERROR)
239268
.setAutoCancel(true)
240269
.build(),
241270
)

app/src/main/res/values/strings.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
<string name="tile_active">Restore limit</string>
55
<string name="tile_override_active">Temporary override active</string>
66
<string name="widget_description">Amply charge controls</string>
7-
<string name="session_channel_name">Temporary full charge</string>
7+
<string name="session_channel_name">Full charge and restore</string>
8+
<string name="session_channel_description" formatted="false">Shows while Amply is allowing a full charge, and while it restores your limit afterwards</string>
89
<string name="session_notification_title" formatted="false">Charging to 100% once</string>
910
<string name="session_notification_armed">Waiting for a charger</string>
1011
<string name="session_notification_active">Charge protection returns at 100% or when unplugged.</string>
1112
<string name="session_notification_restore">Restore now</string>
1213
<string name="gesture_channel_name">Reconnect gesture</string>
14+
<string name="gesture_channel_description" formatted="false">Shows while the reconnect-for-100% gesture is watching for a replug</string>
1315
<string name="gesture_notification_title">Reconnect gesture is on</string>
1416
<string name="gesture_notification_waiting">Waiting for a quick unplug and reconnect while your charge limit is holding.</string>
1517
<string name="gesture_notification_waiting_limit">Waiting for a quick unplug and reconnect at your %1$d%% limit.</string>
@@ -20,6 +22,7 @@
2022
<string name="gesture_notification_waiting_any_level">Waiting for a quick unplug and reconnect at any charge level.</string>
2123
<string name="gesture_notification_disable_hint">You can turn this notification off (long-press it) without stopping the gesture.</string>
2224
<string name="recovery_channel_name">Charge policy recovery</string>
25+
<string name="recovery_channel_description">Alerts you when your protective charge limit could not be restored</string>
2326
<string name="recovery_notification_title">Charge limit needs attention</string>
2427
<string name="recovery_notification_body">Open Amply and restart Shizuku to restore your protective policy.</string>
2528
<string name="recovery_notification_body_convergence">The protective policy was rewritten, but the charging hardware has not confirmed it yet. Open Amply to check.</string>

0 commit comments

Comments
 (0)