Increment 7 — IMAP IDLE push.
- ImapClient.idle() holds a long-lived IMAP connection in IDLE. The server pushes
new-mail notifications during the blocking idle() call, which Jakarta dispatches to a
MessageCountListener (idle() does not itself return), so each push is forwarded to a
sync via a conflated channel. It syncs once on connect to catch up, and closes the
store from the cancellation handler to unblock idle().
- IdleService: a dataSync foreground service running one reconnecting IDLE loop per
account (exponential backoff) that triggers MailSyncer on each push, with an ongoing
"Watching for new mail" status notification.
- IdlePushManager starts/stops the service; LibreMailApplication observes the pushIdle
setting (the existing Advanced toggle) and reacts. Adds FOREGROUND_SERVICE and
FOREGROUND_SERVICE_DATA_SYNC permissions plus the service declaration.
- assemble/test/lint green; verified on the Android 17 emulator against GreenMail —
delivering a message while the app idled pushed an on-device notification within ~2s,
with no polling and no user action.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>