A mode's own drain-rate bucket starts empty until it accumulates history,
so toggling ANC into an unlearned mode fell straight through to Apple's
optimistic spec rating while the mode just left showed its worse measured
rate. Result: enabling ANC could make the displayed time jump up ~1h.
Fill an empty ANC bucket at display time with the less-optimistic of the
mode-agnostic UNKNOWN reading and a sibling mode's learned rate, scaled by
the ratio of the two modes' rated drain. Scoped to spec'd models and
device-supported modes; picks the best-evidenced sibling, tie-broken by
closest rated drain then recency. No persistence or UI change.
The existing spec ceiling and display clamp still backstop the borrowed rate.
- Show the time until the case is full inside its charging chip, learned from
the case's own rising level with the existing charge-band model; no rating
exists for case charging, so the first charge learns before it shows
- Derive a case battery health from observed transfer efficiency: pod percent
gained per case percent spent while docked and unplugged, corrected by each
pod's own health, compared against Apple's "with charging case" totals
- Case data is only genuine while a pod is docked — both transports silently
freeze the last value otherwise. Battery updates now flag whether the case
entry is live, and BLE gains strict same-frame case accessors, so estimates
never learn from frozen echoes
- The case deliberately gets no runtime estimate: idle-then-burst drain has no
meaningful hourly rate
- Mark the case metrics as experimental in the Battery settings card
- Show a "Still determining — check back after a few more listening sessions"
placeholder under Battery Health in the device info sheet while the estimate
is still accumulating data, so the feature is discoverable from day one; no
placeholder for profiles without a paired device, where it could never resolve
- Reorder the Battery card: time remaining & health settings first, then a
divider, then the charging-side settings (charge limit, charged notification)
- Mention the battery-health component in the estimate toggle and reset texts
- Ground the charge-band boundaries in Apple's documented fast-to-80%/trickle
charging behavior and standard lithium CC/CV charging references
- Replace the single linear charge rate with a three-band model (bulk / taper /
trickle) matching lithium CC/CV charging: each band learns its own rate, the
ETA walks the remaining bands, and the spec seed gets a taper haircut for the
slow bands — no more over-promising above 80%
- Base the battery-health figure exclusively on drain observed while the pod is
worn, audio is playing, AND this device is the system's audio sink; idle wear
previously diluted health upward against Apple's listening ratings
- Listening segments are flushed for persistence the moment their gate breaks
(playback stop, docking, transport flip) instead of being discarded with the
cleared window
- The time-remaining estimate keeps learning from all usage — actual current
drain, idle included, is the right basis for "how long will they last"
- The gauge line under the percentage now always shows the runtime estimate
("if used now") even while charging; the time-until-charged moved into the
charging chip itself ("Charging · 25m"), so the two can't be confused
- Battery health is now computed and shown per pod (Left/Right paired row in
the info sheet, mirroring the serial rows) — single-pod listening habits or
a replaced earbud make the sides genuinely diverge, and a combined figure
would mask a failing pod
- While charging, the gauge showed the bare runtime projection when no charge
rate existed yet — "1% · 4m" next to a charging chip reads as a four-minute
charge. The line now shows the "until charged" ETA or nothing
- Seed the charge rate from Apple's published quick-charge claims ("5 minutes
in the case provides around 1 hour of listening"), normalized against the
rated listening hours, so the ETA is present from the very first charge; a
live fit still takes over within minutes
- While a pod charges, fit its rising level and show the time until full in the
gauge instead of the runtime estimate; learned charge rates are persisted per
slot so the ETA appears immediately on later charges
- Suppress the charge ETA during Optimized Battery Charging holds, the final
trickle phase, and whenever the level stalls longer than one visible step
should take (granularity-aware: 1% AAP steps vs 10% BLE steps)
- Clear a slot's fit window when its readings switch between AAP and BLE — the
granularity jump would otherwise read as a fake level step
- Derive a battery-health percentage (median of accumulated drain rates vs the
model's rated life) and show it in the device info sheet; the info button now
also appears for BLE-only devices once health data exists
- Tag learned rates with the model they came from so re-pointing a profile at
different hardware starts learning fresh instead of inheriting foreign rates
- Track how many sessions blended into each learned rate and require three
before a health figure is shown
- Replace the global estimate toggle with a per-device toggle stored on the profile
- Seed the estimate from each model's rated battery life and show it immediately, using
the rating as a hard upper bound on displayed life while the measured rate converges
- When the ANC mode is unknown, seed from the shorter of a model's ANC-on/off ratings
- Show a projection while charging ("if used now") without ever learning from a rising battery
- Consolidate charge limit, "notify when charged", the estimate toggle and reset into one
Battery card; the charge notification now works for any live device, not only classic
audio connections
- Smooth the displayed time asymmetrically (drop fast, rise slow) so a faster-than-rated
drain stops over-promising within a couple of updates
Without tint, white PNG product icons (AirPods photos) are invisible on
light notification backgrounds. Restore src_in tint with notification_icon_tint
(a reliable day/night color resource) in both the PodInfoItemIcon.Notification
style (covers small layouts) and the big layout product ImageViews that do
not use that style.
Remove Theme.Material3.DynamicColors.DayNight from the notification
container style; it does not resolve correctly in the notification host
process, causing light-mode colors to appear in dark mode. Replace all
?attr/colorAccent and ?android:attr/textColorPrimary refs in RemoteViews
layouts with explicit day/night color resources (notification_icon_tint)
and TextAppearance.Compat.Notification.Title defaults. Change tintMode
from multiply to src_in for status glyphs; remove tint from product PNG
icons to prevent silhouette rendering.
Fixes#613