---
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/<userId>/`.

## 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.
