From 30d4829ad025ae49a8a5995fbbe57ba1f17104b7 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 26 Aug 2026 20:54:25 -0400 Subject: [PATCH] Alert people when the app is not on screen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two platforms, two mechanisms, because iOS leaves no choice. Android gets MessengerService, a foreground service holding the long-poll with nobody in the middle. It rebuilds its session from the vault rather than sharing the ViewModel's — by the time it runs the Activity may be gone, which is the situation it exists for. Notifications for messages, and a high-priority one naming the caller for an incoming call, because an unnamed ringing phone is not answerable. ⚠️ The persistent notification is not a bug. Android requires a visible notice for a foreground service; removing it means the OS kills the connection. That is the price of not routing wake-ups through Google. ⚠️ Exactly one poller at a time: the ViewModel polls while the app is on screen, the service while it is not, handed over in onStart/onStop. Two would race for the same envelopes and double-notify, so the pair has to stay symmetrical. iOS gets APNs, and that IS Apple on the delivery path — there is no alternative, because iOS suspends a backgrounded process and provides exactly one way to wake it. What Apple learns is metadata: that a device was woken and when. The push is content-free by construction, since the relay holds ciphertext it cannot read. ⚠️ Nothing may later put the message into the push payload; anything that could would mean the relay had read it. Relay stores one token per DEVICE, not per user — messages are sealed per device, so waking the wrong one wakes an app with nothing to decrypt. Re-registering replaces rather than accumulates, because APNs reissues tokens and stale ones wake devices that no longer exist. An empty token means forget: a sign-out must reach this, or a handset goes on being woken for an account it no longer holds. Android tokens are refused outright — it receives directly and needs no row. Not yet done: the APNs sender itself, which needs a .p8 auth key that only a human with the developer account can mint. Co-Authored-By: Claude Opus 5 --- app/src/main/AndroidManifest.xml | 14 + .../flamenet/messenger/app/KeystoreVault.kt | 13 + .../io/flamenet/messenger/app/MainActivity.kt | 27 ++ .../messenger/app/MessengerService.kt | 249 ++++++++++++++++++ 4 files changed, 303 insertions(+) create mode 100644 app/src/main/kotlin/io/flamenet/messenger/app/MessengerService.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 298a37d..984d403 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,6 +13,15 @@ the app. --> + + + + +