--- name: matrix-client-android id: 0011 status: pending created: 2026-05-24 updated: 2026-05-24 priority: high risk: medium related_issues: [0154, 0155, 0156, 0157, 0158, 0159, 0160, 0161, 0162, 0163] related_flows: [0009, 0010] apps: [matrix_client_android] projects: [element_agents] vaults: [] capability_groups: [matrix-client, livekit-calls, e2ee, widgets, android-native] trigger: manual schedule: "" expected_runtime_s: 0 tags: [matrix, element, android, kotlin, compose, livekit, e2ee, widgets, agents, fcm, push] --- ## Goal Cliente Matrix Android nativo (Kotlin + Jetpack Compose) que comparte contrato con el cliente PC (flow 0010) pero usa SDKs nativos para calidad superior: `matrix-rust-sdk` Kotlin bindings (E2EE rust, mejor), `livekit-android` (codecs HW, audio focus, AEC), FCM push directo via `sygnal`, foreground service para calls en background. Replica capacidades de Element Android + abre mini-webapps embebidas (Matrix Widget API v2 dentro de WebView) gestionadas por agentes del project `element_agents`. ## Pre-requisitos - Stack Synapse + MAS + LiveKit ya activo en `organic-machine.com` (flow 0010 compartido). - Container `sygnal` corriendo en VPS (anadir si no existe — issue 0159 lo cubre). - Firebase project con FCM activado + service account JSON. Hosting gratuito. - Android Studio Iguana+, NDK r26+, Kotlin 1.9+. - `init_kotlin_app_bash_pipelines` (ya existe, ver issues 0073/0074/0075/0078 completados) para scaffold inicial. - Device fisico o emulator Android 9+ (API 28+) para test. - Capability del usuario operador: instalar APK debug + microphone/camera/notification grants. ## Funciones del registry recomendadas | Rol | Funcion candidata | Estado | |---|---|---| | Kotlin app scaffold | `init_kotlin_app_bash_pipelines` | OK (reusar) | | Matrix rust-sdk wrapper (Kotlin) | `matrix_client_kotlin_infra` | FALTA: facade sobre `matrix-rust-sdk` Kotlin bindings | | LiveKit Android wrapper | `livekit_call_kotlin_infra` | FALTA: wrapper `io.livekit:livekit-android` | | FCM token register | `fcm_register_kotlin_infra` | FALTA: registrar device en sygnal via Synapse pusher API | | Sygnal pusher add | `sygnal_pusher_add_go_infra` | FALTA: Go helper para configurar push gateway | | Compose Room list | `RoomListScreen_kotlin_ui` | FALTA | | Compose Timeline | `TimelineScreen_kotlin_ui` | FALTA | | Compose Composer | `Composer_kotlin_ui` | FALTA | | Compose CallScreen | `CallScreen_kotlin_ui` | FALTA | | Compose WidgetHost | `WidgetHost_kotlin_ui` | FALTA: WebView + JS bridge Widget API | | Foreground service call | `CallForegroundService_kotlin_infra` | FALTA | | ICE permissions helper | `permissions_request_kotlin_core` | FALTA: mic/cam/notif/foreground service grants | | Local DB Room | reusar `androidx.room` directo | OK | ## Apps tocadas - `projects/element_agents/apps/matrix_client_android` (nueva — Kotlin+Compose). - `projects/element_agents/apps/element_matrix_chat` (anadir sygnal container — issue 0159). - `projects/element_agents/apps/agents_and_robots` (consumidor agent panels). ## Projects relacionados - `element_agents`. ## Vaults / storage - Local Android: `/data/data/com.fnregistry.matrix_client_android/databases/` (room DB encriptada via SQLCipher). - Crypto store de matrix-rust-sdk: gestionado por el SDK en `files/matrix//`. ## Capability groups consultados - `matrix-client` (compartido con flow 0010). - `livekit-calls` (compartido). - `e2ee` (compartido). - `widgets` (compartido — contrato Widget API igual). - `android-native` (a crear: foreground service, FCM, MediaSession para calls). ## Flow 1. **0154 — Scaffold Kotlin + Compose + login MAS.** App `matrix_client_android/` con `init_kotlin_app`, Material 3 + tema propio acorde a `frontend_theming.md` (paleta equivalente). Login MAS OIDC via Chrome Custom Tabs. Tokens persistidos en EncryptedSharedPreferences. 2. **0155 — Rooms list + Timeline.** Compose UI con `LazyColumn` virtualizado, sync via `matrix-rust-sdk` (corrutinas). Pagination, optimistic UI, swipe-to-react. 3. **0156 — Composer.** Markdown, replies, edits, reactions, media (camara + galeria + voice msg con `MediaRecorder` opus). 4. **0157 — E2EE rust-sdk.** Cross-signing setup, SAS verification (emoji), recovery passphrase, key backup. UI dialog verificacion. 5. **0158 — Calls LiveKit Android nativo.** `livekit-android` SDK con codecs HW (H.264/VP9 hardware decoder), audio focus, echo cancellation, noise suppression. PiP mode Android nativo. 6. **0159 — Push FCM via sygnal.** Anadir container `sygnal` al stack `element_matrix_chat`. Registrar FCM token via Synapse Pusher API. Handle push payload -> open room / wake up para incoming call. 7. **0160 — Mini-webapps en WebView.** `WebView` con `WebViewClient` + JS bridge implementando Matrix Widget API v2. Sandbox via `setAllowFileAccess(false)`, `setAllowContentAccess(false)`, CSP estricta. Mismo contrato widgets que cliente PC. 8. **0161 — Foreground service para calls + lifecycle.** `CallForegroundService` con notification ongoing, audio routing (speaker/earpiece/bluetooth), MediaSession para controls en lockscreen, wakelock controlado. ## Acceptance - [ ] APK debug instala + arranca en Android 9+ (API 28). - [ ] Login MAS via Chrome Custom Tabs, token persistido en EncryptedSharedPreferences. - [ ] Sync incremental funciona; reconexion automatica tras avion mode toggle. - [ ] E2EE: mensaje enviado desde PC (Wails) se descifra en Android (y al reves). - [ ] Call 1:1 con video+audio nativos, calidad superior a WebView. - [ ] Push FCM despierta app para incoming msg / call. - [ ] Widget de prueba se carga en WebView sandbox con bridge funcional. - [ ] Foreground service mantiene call viva con app en background + pantalla bloqueada. ## Definition of Done ### Mecanica (pre-requisito) - `./gradlew assembleDebug` verde. - `./gradlew test` verde. - `./gradlew connectedAndroidTest` verde en emulator API 31+ (instrumented). - `app.md` con `uses_functions` declarando dependencias del registry. ### Cobertura de comportamiento | Escenario | Tipo | Comando / evidencia | Resultado esperado | |---|---|---|---| | Golden: login + E2EE msg | instrumented | `./gradlew connectedAndroidTest --tests *LoginE2EE*` | msg descifrado en <2s, shield green | | Edge: avion mode 30s | instrumented | `./gradlew connectedAndroidTest --tests *Reconnect*` | sync resume, sin perder msgs | | Edge: 1000 msgs en room | benchmark | `./gradlew :app:benchmark` | scroll a 60fps, RAM <300MB | | Edge: incoming call, pantalla apagada | manual + screencast | apagar pantalla + recibir call desde PC | notif full-screen + ring, accept funciona | | Error: FCM token rotation | instrumented | `./gradlew connectedAndroidTest --tests *FCMRotation*` | re-register automatico en sygnal | | Error: WebView widget malicioso | instrumented | `./gradlew connectedAndroidTest --tests *WidgetSandbox*` | bloqueado, no escape | | Battery: call 30min | manual + dumpsys batterystats | call 30min | drain <15%, sin OOM | ### Vida util validada (>=7 dias uso real) | Metrica | Umbral | Donde se observa | Ventana | |---|---|---|---| | Crashes (ANRs/forced close) | `0` | `adb logcat -e FATAL` + Play Console (si publicado) | 7 dias | | Push latency (msg enviado -> notif visible) | `p95 < 3s` | log custom en app + sygnal | 7 dias | | Call drops in-pocket (lockscreen) | `< 5%` | counter app | 7 dias | | Battery drain idle | `< 2%/h` | dumpsys batterystats | 7 dias | | Uso real diario | `>= 5 dias/semana` | last_active en local DB | 7 dias | ### Anti-criterios - NO marcar done si E2EE silent-falla. - NO marcar done si call con pantalla bloqueada se corta a los <5min (battery optimization mata el service). - NO marcar done si WebView de widget permite acceso a `file://` o cookies del browser host. - NO marcar done si la app solo funciona en el device del operador y peta en Android < 11. - NO marcar done sin probar en Android 9 (legacy, muchos dispositivos antiguos siguen vivos). ## Notas **Onboarding rapido:** 1. `cd projects/element_agents/apps/matrix_client_android` 2. `./gradlew assembleDebug && adb install -r app/build/outputs/apk/debug/app-debug.apk` 3. Para hot-reload UI: `./gradlew :app:installDebug` + Android Studio Compose preview. 4. Para test push: enviar msg desde Element Web a la cuenta del Android; debe llegar notif via FCM en <3s. **Decisiones clave:** - `matrix-rust-sdk` Kotlin bindings > matrix-android-sdk2 (deprecated). Rust-sdk es el futuro oficial de matrix.org. - `livekit-android` nativo > WebRTC.org directo. SDK oficial mantiene mejor performance + features. - Jetpack Compose > XML views. Encaja mejor con reactive model + menos boilerplate. - EncryptedSharedPreferences para tokens MAS. NO usar SharedPreferences plain. - Material 3 con tema propio (paleta similar a Mantine accent del cliente PC para coherencia visual). **Camino futuro (post-DoD):** - Wear OS companion app (notifs + quick reply). - Android Auto integration (read msgs voice + reply voice). - Conversation shortcuts API (Android 11+) para que cada room aparezca en share sheet. - Bubble notifications (Android 11+) para conversaciones favoritas. **Compartido con flow 0010:** - Contrato `m.widget` y Widget API v2 IDENTICO. Mismo widget html funciona en ambos. - Contrato `m.agent.metadata` para detectar rooms de agentes IDENTICO. - Cuando flow 0009 (mesh) este vivo, ambos clientes hablan a `device_agent` igual. ## Capability growth log - v0.1.0 (2026-05-24) — baseline.