feat(sync): gate full-content fetch on Wi-Fi/battery; IDLE polls at low battery

Shared core: BatteryStatusProvider (BatteryManager one-shot +
ACTION_BATTERY_CHANGED flow) feeds SyncResourcePolicy, a pure,
unit-tested decision object; all gates are runtime-only and
self-reverting - no setting is ever mutated.

- #88: FetchPolicy now defaults to WIFI_ONLY in both the AppSettings
  default and the DataStore-read fallback, so fresh installs and
  never-touched existing installs stop bulk-downloading full content
  over cellular. An explicitly chosen policy is unaffected.
- #89: the aggressive body/attachment prefetch pauses for every
  FetchPolicy at <=20% battery in BOTH content-prefetch paths -
  MailSyncer's recent-window prefetch and MailBackfiller's
  full-history prefetch (#12) - resuming on the next sync once above
  the threshold; charging exempts. Header sync and backfill header
  paging (new-mail detection, notifications, history) are untouched.
- #90: IdleService watches battery and proactively closes its IDLE
  connections at <=20%, flipping the foreground notification to say
  mail is checked every 15 minutes (the always-scheduled periodic
  sync, re-asserted on entry); IDLE resumes at >=25% or on charger
  (hysteresis prevents threshold flapping) and catches up missed mail
  via idle()'s on-connect sync.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 23:18:18 -05:00
co-authored by Claude Fable 5
parent 89b2aca141
commit 26f9127d84
14 changed files with 620 additions and 36 deletions
+1
View File
@@ -180,6 +180,7 @@
<string name="notif_channel_push_status">Push (IMAP IDLE)</string>
<string name="notif_push_status_title">Watching for new mail</string>
<string name="notif_push_status_text">Connected for instant delivery</string>
<string name="notif_push_status_text_low_battery">Battery low — checking every 15 minutes until it recovers</string>
<!-- Settings -->
<string name="settings_accounts">Accounts</string>