Skip to content

Kirin (Mate 10 Pro): ongoing notification shows nonsense "Discharging −1 mA" — CURRENT_NOW reported in mA, not µA #152

Description

@almothafar

Symptom (observed on the Kirin Mate 10 Pro)

The ongoing status notification intermittently shows "Discharging −1 mA", while the details table correctly shows no Current row at all. Reported 2026-07-12.

Diagnosis

The Kirin/HiSilicon fuel gauge reports BATTERY_PROPERTY_CURRENT_NOW in mA instead of µA — the sibling of its charge-counter unit bug (#69/#94). A real draw of ~800 mA arrives as raw -800, which we interpret as −800 µA = −0.8 mA.

The gates in BatteryRateTracker.computeRate then behave exactly as written, on garbage input:

  • isPlausibleCurrentMicroAmps only rejects too-large readings (wrong unit in the other direction); a 1000×-too-small value looks perfectly plausible.
  • hasCurrent requires Math.round(|µA|/1000f) >= 1, i.e. raw ≥ 500. Under load (real 0.5–1.5 A) raw lands in 500–1499 → the display shows "−1 mA".

Why the notification shows it but the table doesn't

  1. NotificationService.statusWithRate falls back to mA whenever no %/h is available — notably during the source-B warm-up (~3 min after unplug / any window reset), exactly when the user tends to glance at the notification. On this device source A never runs (capacity reads 0), so every warm-up exposes the mA fallback.
  2. The notification refreshes on every broadcast (including screen-off/under-load moments where raw ≥ 500); the table only samples at app-open instants, where the reading is usually < 500 → hasCurrent false → row hidden. Same gates, different sampling moments around a borderline value.

Not affected

The %/h rate itself on this device: capacity is 0 there, so source A (current ÷ capacity) is already skipped and the rate comes from level-over-time (source B), which is unit-independent. Only the Current row and the notification's mA fallback are wrong.

Also note the general-device implication: on any device, a genuine sub-1.5 mA reading displayed as "−1 mA" is glance-noise, not information.

Fix

v1 — display floor (small, safe, do first)

Treat currents below a minimum display magnitude as "not worth showing": add MIN_DISPLAY_CURRENT_MA = 10 (constant in BatteryRateTracker) and require Math.round(|µA|/1000f) >= MIN_DISPLAY_CURRENT_MA in the hasCurrent gate.

  • Hides the Kirin nonsense entirely (misread values cap out at ~1–3 "mA").
  • Negligible loss on genuine-µA devices: sub-10 mA discharge happens only in deep sleep, when nobody is reading the notification anyway.
  • Update BatteryRateTrackerTest accordingly (the negligibleRate_roundsToZeroAndHides / currentZero_isHiddenWhileRateStillShown neighborhood; add a boundary case at 9/10 mA).

v2 — unit auto-calibration (optional follow-up; needs on-device verification)

Persistently track the maximum |raw| ever observed (across sessions, including while charging). If after meaningful observation it stays below ~20,000, the device cannot be reporting µA (that would mean it never exceeded 20 mA even while charging) → conclude mA units, scale readings ×1000, and show the real current on Kirin instead of hiding it. Genuine µA devices routinely exceed 100,000+.

  • Store the calibration flag + observed max in SharedPreferences; pure decision helper + tests.
  • Verify on the Mate 10 Pro before merging (confirm raw magnitudes: expect ~200–2000 discharging, ~1000–2000 charging).
  • If v2 lands, source A could also be enabled with scaled current on such devices where capacity is known — out of scope unless trivially free.

Affected code

Acceptance criteria (v1)

  • "−1/−2 mA" can no longer appear in the ongoing notification or the details table
  • Currents ≥ 10 mA display exactly as before
  • Boundary unit tests at the new floor
  • Verified on the Mate 10 Pro: notification falls back to the plain status label during warm-up instead of showing mA nonsense

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions