Summary
The Battery Insights screen always shows Charge Cycles: 0 and Health: 100%, regardless of how old the device/battery is. On a 3-year-old phone where other apps report ~86% health, this app shows 100%.
Root causes (three compounding problems)
1. The tracker almost never runs
BatteryHealthTracker.recordBatteryState() is only called from BatteryLevelReceiver.onReceive (BatteryLevelReceiver.java:60). Because battery monitoring only runs while the app is in the foreground (see the foreground-service / background-monitoring issue), recordBatteryState is rarely invoked, so cycle progress is essentially never recorded → cycles stay at 0.
2. The cycle-counting logic is too strict and lossy
BatteryHealthTracker.recordBatteryState (BatteryHealthTracker.java:67-97) only counts a cycle when the battery goes from <= 20% to >= 95% while the app is actively observing both ends. The class Javadoc claims "partial charges accumulate to form complete cycles," but the implementation does not accumulate partial charge — it requires a single full low→high swing. Most users top up before hitting 20% and unplug before 95%, so cycles are almost never counted even when monitoring works.
3. "Health %" is a fabricated estimate, not real data
getEstimatedHealthPercentage (BatteryHealthTracker.java:158-184) derives health purely from the (broken) cycle counter using a hard-coded degradation curve. With cycles stuck at 0 it always returns 100 - (0 * 5 / 300) = 100%. It never reads any real battery wear signal, so it can never match what hardware-aware apps report.
Proposed fix
- Fix background monitoring first (prerequisite) so state is actually recorded.
- Replace the fabricated estimate with real signals where available:
BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER (µAh) integrated over charge sessions to estimate full-charge-equivalent cycles and design-vs-current capacity.
- On Android 14+ (API 35
getBatteryCycleCount() via EXTRA_CYCLE_COUNT in ACTION_BATTERY_CHANGED) read the OS-reported cycle count directly.
- Derive health % from measured charge throughput vs. design capacity rather than a fixed curve.
- If a real signal isn't available, label the value as an estimate in the UI instead of presenting "100%" as fact.
Acceptance criteria
- Charge cycles increase over real usage (and/or reflect
EXTRA_CYCLE_COUNT where the OS provides it).
- Health % reflects measured wear and is not permanently pinned at 100%; if estimated, it is clearly labeled as an estimate.
Summary
The Battery Insights screen always shows Charge Cycles: 0 and Health: 100%, regardless of how old the device/battery is. On a 3-year-old phone where other apps report ~86% health, this app shows 100%.
Root causes (three compounding problems)
1. The tracker almost never runs
BatteryHealthTracker.recordBatteryState()is only called fromBatteryLevelReceiver.onReceive(BatteryLevelReceiver.java:60). Because battery monitoring only runs while the app is in the foreground (see the foreground-service / background-monitoring issue),recordBatteryStateis rarely invoked, so cycle progress is essentially never recorded → cycles stay at 0.2. The cycle-counting logic is too strict and lossy
BatteryHealthTracker.recordBatteryState(BatteryHealthTracker.java:67-97) only counts a cycle when the battery goes from<= 20%to>= 95%while the app is actively observing both ends. The class Javadoc claims "partial charges accumulate to form complete cycles," but the implementation does not accumulate partial charge — it requires a single full low→high swing. Most users top up before hitting 20% and unplug before 95%, so cycles are almost never counted even when monitoring works.3. "Health %" is a fabricated estimate, not real data
getEstimatedHealthPercentage(BatteryHealthTracker.java:158-184) derives health purely from the (broken) cycle counter using a hard-coded degradation curve. With cycles stuck at 0 it always returns100 - (0 * 5 / 300) = 100%. It never reads any real battery wear signal, so it can never match what hardware-aware apps report.Proposed fix
BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER(µAh) integrated over charge sessions to estimate full-charge-equivalent cycles and design-vs-current capacity.getBatteryCycleCount()viaEXTRA_CYCLE_COUNTinACTION_BATTERY_CHANGED) read the OS-reported cycle count directly.Acceptance criteria
EXTRA_CYCLE_COUNTwhere the OS provides it).