# Lemenzo Messages 1.0

Privacy-first Android 16 SMS/MMS system app for LemenzoOS.

Locked naming:
- Project folder / Soong module: `LemenzoMessenger`
- Android package: `com.lemenzo.messenger`
- Launcher/app drawer label: `Messages`
- In-app product title: `Lemenzo Messages`

Production candidate scope includes SMS/MMS send/receive, multipart status tracking, dual-SIM choice, drafts, notifications with reply/mark-read, MMS attachments, contact resolution/photos, unread counts, contact-name search, default-SMS role handling, delivery reports, privacy-controlled notification previews, retry handling, keyboard-safe composers and the locked Lemenzo premium dark UI.

Build targets:

```bash
m LemenzoMessenger
m LemenzoMessengerTests
```

A successful build is not final production approval. Physical Pixel testing is still required for SMS/MMS carrier behavior, dual-SIM, notification privacy, contact picker, attachments, IME movement and pixel-level visual comparison with the approved mockup.

Performance work in this candidate includes refresh coalescing, duplicate-render suppression, in-memory search over the latest provider snapshot, cached canonical/contact presentation, pending-state refreshes without unnecessary telephony reloads, and asynchronous downscaled MMS thumbnails. Swipe gestures use Android touch-slop plus horizontal direction locking so vertical scrolling remains authoritative.

## Large-history performance architecture (v4.6)

- Inbox uses framework `ListView` virtualization instead of materializing every conversation row.
- Conversation timeline uses framework `ListView` virtualization and keeps only visible message rows as Views.
- Initial thread load is bounded to 300 messages; older history is fetched in 300-message pages when the user reaches the top.
- Provider refreshes reload only the active bounded window instead of the entire thread history.
- Contact names/photos for the inbox are prefetched in one ContactsProvider scan and cached.
- MMS thumbnails are loaded off the UI thread and kept in a bounded 16 MiB LRU cache.
- Existing refresh coalescing, render signatures, async provider work and swipe direction-lock remain enabled.
- No new third-party/AndroidX runtime dependency was introduced for this performance work.

## Large-history performance hardening

The daily-use message UI uses bounded provider pages and recycled ListView rows. Older history uses a stable `(date, id)` keyset cursor per protocol, so equal timestamps cannot prematurely end paging. Provider refreshes merge the newest page into the active history window instead of discarding already-loaded older pages. Contact presentation prefetch skips cached numbers, and MMS thumbnails stay in a bounded LRU cache.

Retry UI hardening: failed SMS/MMS now render a dedicated status row beneath the outgoing bubble using the locked Lemenzo danger color (#FF5A67) plus an explicit high-visibility Retry control with a 40dp minimum touch target. Retry is no longer represented by tiny red text inside the blue bubble.

## v4.9 responsiveness hardening
- Contact picker database scan runs off the main/UI thread.
- Compose and conversation attachment metadata/thumbnail loading runs off the UI thread.
- Normal SMS/MMS send dispatch runs on a background executor, including MMS preprocessing.
- Send buttons are guarded against double-submit while dispatch is in flight.
- Send dispatch has its own executor, so slow MMS preprocessing cannot starve message/database refresh work.
- Contact picker results are cached for the lifetime of the compose screen and duplicate concurrent provider scans are suppressed.
- Inbox contact photos are thumbnail-decoded on a bounded background executor with an 8 MB LRU cache and recycled-row token checks.
- Conversation header contact lookup/photo decoding is off the UI thread and reuses the bounded thumbnail cache.


## v5.2 dual-SIM and receiver performance hardening
- Incoming and outgoing SMS rows persist the originating/selected subscription ID (`sub_id`) so dual-SIM history keeps the correct SIM association.
- Multipart send tracking carries the subscription ID through final sent-row persistence.
- SMS delivery, send-status, notification reply/mark-read, WAP-push, MMS-download and MMS-send receiver follow-up work uses a small bounded background executor via `BroadcastReceiver.goAsync()`.
- MMS PDU/file/provider parsing and contact resolution no longer run directly on the receiver main thread.
- Conversation-list swipe semantics are explicitly locked: swipe reveals Delete; tapping Delete commits the action. Message/full-thread destructive actions inside a conversation keep confirmation dialogs.

## v5.3 conversation deletion correctness hardening

- Conversation deletion now uses the unified `content://mms-sms/conversations/<threadId>` provider path.
- Empty Telephony thread rows are cleaned through `content://mms-sms/conversations/obsolete`.
- Empty orphan threads are filtered from the inbox so a deleted conversation cannot reappear as `Unknown`.
- Legacy per-protocol SMS/MMS deletion is retained only as a compatibility fallback.
- Source validation now gates against regressions in this delete flow.
