signal app for wearos; works with/without a molly client companion
- Kotlin 89.9%
- C 7%
- Shell 2.3%
- Makefile 0.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The endpoint flags messages with a downloaded image attachment (querying attachments directly, since the conversation reader doesn't populate the slide deck) and includes image-only messages. On demand, the watch requests a thumbnail by attachment id; Molly decrypts the attachment, downscales it (longest edge 320px, JPEG capped under the MessageClient size limit), and the bridge relays the bytes. The watch decodes and renders the image inline, with a 📷 placeholder while it loads. Thumbnails are cached in memory only (never persisted), keeping decrypted image bytes out of watch storage. Verified on-device: real photos render inline in conversations (11-18KB thumbnails delivered). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JSqhgY5GUKUyVbCqvYjaee |
||
| gradle/wrapper | ||
| native-utils | ||
| phone | ||
| shared | ||
| wear | ||
| .gitignore | ||
| build.gradle.kts | ||
| gradle.properties | ||
| gradlew | ||
| README.md | ||
| settings.gradle.kts | ||
signal-watchapp
Signal on an Android (Wear OS) watch, built as a phone/watch pair. The watch never touches Signal's servers or crypto; the phone does all the work and the watch is a thin UI over the encrypted Bluetooth link.
Architecture (Tier 1 — notification bridge)
┌─────────────┐ notifications ┌──────────────────┐ Wearable Data Layer ┌───────────┐
│ Signal / │ ───────────────► │ :phone │ ◄───────────────────► │ :wear │
│ Molly (app) │ ◄─────────────── │ SignalWear Bridge│ (MessageClient, │ SignalWear│
└─────────────┘ RemoteInput └──────────────────┘ BT, device-to- └───────────┘
reply injection device only)
:phone— a small bridge app (not a Signal fork). ANotificationListenerServicemirrors Signal's MessagingStyle notifications into an in-memory conversation store; replies from the watch are injected back through the notification's ownRemoteInputaction, so Signal itself sends the message. Nothing extra talks to Signal's servers.:wear— Compose for Wear OS app: conversation list, message view, reply via the system voice/keyboard input, mark-as-read.:shared— JSON wire protocol between the two (kotlinx-serialization).
Both APKs share the net.deprekated.signalwear applicationId — the Wearable
Data Layer only routes between same-package, same-signature apps. Debug builds
of both are signed with the same debug keystore, so this works out of the box.
Known Tier 1 limitations (by design)
- Only conversations that produce notifications are visible; no deep history.
- Dismissing/reading a notification on the phone makes that conversation read-only on the watch until the next message arrives.
- Can't start a brand-new conversation from the watch.
- Message plaintext is mirrored to the watch (that's the point, but know it).
Tier 2 (planned): replace the notification bridge with a Molly-based fork running as a linked device, keeping this watch app and wire protocol unchanged — only the phone-side data source swaps.
Building
./gradlew :phone:assembleDebug :wear:assembleDebug
Requires JDK 17 and an Android SDK with platform 36 (local.properties
points at ~/Android/Sdk).
Installing
adb install phone/build/outputs/apk/debug/phone-debug.apk(on the phone)adb install wear/build/outputs/apk/debug/wear-debug.apk(on the watch — pair viaadb pair/ wireless debugging on the watch)- Open SignalWear Bridge on the phone and grant notification access.
- Open SignalWear on the watch; conversations appear as Signal notifications arrive.