Skip to content

fix: dismiss the full-battery alert when the charger comes out - #266

Open
almothafar wants to merge 1 commit into
masterfrom
claude/battery-notification-persist-e1iw8m
Open

fix: dismiss the full-battery alert when the charger comes out#266
almothafar wants to merge 1 commit into
masterfrom
claude/battery-notification-persist-e1iw8m

Conversation

@almothafar

Copy link
Copy Markdown
Owner

The "Battery fully charged" notification stayed on screen after unplugging.

The bug

decideChargingOrFull treated BATTERY_STATUS_FULL as the whole trigger, never asking whether a charger was actually connected. Plenty of devices keep reporting that status while sitting at 100% with the cable already out, so on unplug:

  1. PowerConnectionReceiver.handleChargerDisconnected cancels the notification and clears fullNotified to re-arm the next charge session.
  2. The very next ACTION_BATTERY_CHANGED — still reporting FULL, now against a freshly cleared flag — posts the alert straight back.

The alert is cleared and immediately re-posted, which reads as a notification that refuses to go away. With the sticky-notification preference on it carries FLAG_NO_CLEAR, so it can't be swiped either.

A second path reached the same symptom: when the process is killed mid-charge (doze, OEM task killers) nobody sees the unplug broadcast, so nothing ever clears the alert.

The fix

The full alert is now bounded by the charger, not by the status.

  • BatteryLevelReceiver reads EXTRA_PLUGGED and passes it into the decision core; the alert fires only on full && plugged, so off the charger it cannot re-post itself.
  • A shown full alert is dismissed from the plugged state rather than from the unplug transition alone, so a transition missed while the process was dead still resolves on the next broadcast instead of stranding the notification until the following charge. The same step re-arms the episode, matching what PowerConnectionReceiver already does on the transition it does see.
  • Dismissal runs before dispatch in onReceive: level alerts share one notification ID, so an alert decided on the same broadcast (a critical one, on a battery unplugged at full that then drained) must replace the stale notification rather than be cancelled after it.

Unchanged: the once-per-charge behaviour, the (warning, FULL_PERCENTAGE] re-arm band, and re-firing when a charger is connected at an already-full battery — each pinned by a test.

Tests

Five new cases in BatteryLevelReceiverDecisionTest covering the regression itself (unplugged while still reporting FULL), the dismissal of a stale alert on both the charging-or-full and the discharge branch, the critical-alert-survives-the-dismissal ordering, and the re-plug case. testDebugUnitTest and lintDebug both pass.

Also drops an unused constant (FRESH) in the test file.


Generated by Claude Code

The "Battery fully charged" alert kept coming back after unplugging.

The level-alert decision treated BATTERY_STATUS_FULL as the whole trigger,
but plenty of devices keep reporting that status while sitting at 100% with
the cable already out. So on unplug PowerConnectionReceiver cleared the
alert and re-armed the episode, and the very next ACTION_BATTERY_CHANGED —
still reporting FULL — posted it straight back. With the sticky-notification
preference on it could not even be swiped away.

The alert is now bounded by the charger rather than by the status: it only
fires while plugged in, and a shown one is dismissed as soon as the plugged
state says the charger is out. That dismissal is state-driven rather than
tied to the unplug broadcast alone, so a transition missed while the process
was dead (doze, OEM task killers) still resolves on the next broadcast
instead of stranding the notification until the following charge.

Dismissal happens before dispatch in the receiver: level alerts share one
notification ID, so an alert decided on the same broadcast (a critical one
on a battery that unplugged full and then drained) must replace the stale
notification, not be cancelled after it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VvXe4CxGMYwGSC3UgUDru
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants