Show battery charge/drain rate ("9%/h") in details table and status notification (#108)#120
Merged
Conversation
…tus notification (#108) Adds a smoothed charge/drain rate (%/h) and a signed instantaneous current, derived best-effort and degrading gracefully: - BatteryRateTracker computes the rate over a trailing, persisted sample window (no polling timer — samples piggyback the existing battery broadcasts and the foreground refresh). Source A = averaged current / capacity; source B = level-change over time (capacity-free, so it still works on Kirin/HiSilicon devices where the charge counter is unreliable, #69/#94). Each output is gated on its own merit. - Details table: "Drain rate"/"Charge rate" and "Current" rows at the top, each shown only when trustworthy. The drain rate turns amber near the user's limit and red at/above it (discharging only); charging is left uncoloured in v1. - Ongoing notification: appends the rate to the status line ("85% . Discharging 9%/h . 32.0 C"), falling back to mA then the plain label. Gated by one new setting (default on). - Settings: the shared "high drain" limit (default 20%/h) — the red line here and the fast-drain alert trigger in #109 — plus the notification toggle. - CONTEXT.md records the vocabulary (Drain rate, Charge rate, Instantaneous current, Design capacity). New strings drafted in Arabic (values-ar) for review. Pure helpers (rate computation, current sign, plausibility, windowing, serialization) are unit-tested. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
16c3619 to
225d49a
Compare
Fixes from a review pass over the drain-rate feature: - parseSamples: close the overflow hole in the digit-length guards. A 10-digit int or 19-digit long passed validation but made parseInt/ parseLong throw, crashing the receiver on every broadcast while the pref was corrupted. Ints are now range-checked through a long (the full int range must stay accepted: the "no current" sentinel is Integer.MIN_VALUE itself); longs are capped at 18 digits. - record(): skip snapshots whose level/scale extras are invalid (-1), which read as 0% and would plant a bogus sample yielding a huge false drain rate against the next real reading. - record(): persist only when the window or direction actually changed, instead of rewriting the preferences file on every ACTION_BATTERY_ CHANGED (needless disk I/O in a battery app). - getRate(): age-trim the loaded window so a stale pre-restart window can't briefly surface as a current rate at service start. - Extract shared sameDirection/loadWindow/trimToWindow helpers so the record and read paths can't diverge on direction or freshness rules. - Reuse the rate computed by record() in the ongoing notification instead of re-reading and re-parsing the window in the same broadcast. - Clamp the stored drain limit to the slider's range on read; the bounds constants and pref_notification.xml now reference each other. Tests: overflow entries skipped without throwing, int boundary round-trip, invalid-level gating, age-trim (stale/future samples), and limit clamping. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012LC6Qt7Nr8MpJHXuszizNF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #108.
What
Adds a live, smoothed charge/drain rate (
%/h) and a signed instantaneous current.BatteryRateTracker— computes the rate over a trailing, persisted sample window. No polling timer: samples piggyback the existingACTION_BATTERY_CHANGEDbroadcasts and the MainActivity foreground refresh. Derivation degrades gracefully:Each output (rate, current) is gated on its own merit, per Battery health: show 'Unknown' + tappable info when the charge gauge is unreliable (vs design capacity) #94.
Drain rate/Charge rateandCurrentrows at the top, each shown only when trustworthy. The label flips with direction; the rate value is amber near the user's limit, red at/above it while discharging (charging left uncoloured in v1).85% · Discharging 9%/h · 32.0 °C), falling back to mA then the plain label. Gated by one new setting (default on).20%/h) that is the red line here and the fast-drain alert trigger in Fast-drain alert: warn when battery drains abnormally fast for a sustained time #109, plus the notification toggle.CONTEXT.mdrecords the vocabulary (Drain rate, Charge rate, Instantaneous current, Design capacity).Testing
testDebugUnitTestgreen.lintDebugclean; installed on the Kirin Mate 10 Pro.On-device notes
dumpsys battery→Charge counter: 99000≈ 99 mAh), sogetBatteryCapacityreturns 0 and source B (level-delta) carries the rate there — as the issue anticipated.BATTERY_PROPERTY_CURRENT_NOWis trustworthy on the Mate 10 Pro for theCurrentrow, and the drain-rate row + colouring after unplugging under real use.Needs review
values-ar) are my drafts — please review the wording for the new rows/settings.#109 (fast-drain alert) stacks on this branch and reuses the shared limit.