Bisher stand im Namensfeld die technische Kennung aus der Netz-Erkennung
(F8FCE10B4E6C@AS-AFTKA[AirPlay]) — auch wenn das Geraet laengst 'Fire-TV
Schlafzimmer' heisst. Jetzt in dieser Reihenfolge:
1. Name, den der Agent auf DIESEM Geraet traegt — Zuordnung ueber die IP, die
der Agent neu in host_hello mitmeldet (localIp()); Server reicht sie durch.
2. zuletzt hier eingegebener Name (localStorage je Satellit+IP).
3. Name aus der Erkennung, aber nur wenn menschenlesbar — Seriennummern, IPs
und Kennungen mit @/[]/: werden verworfen (Feld bleibt leer).
Android-Version 0.0.1.5.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ARIA Android-Agent
Ein nativer Android-Agent (eigene APK), der ARIA erlaubt, ein Smartphone
fernzusteuern — inkl. Bedienen fremder App-UIs (z.B. „ARIA, richte auf dem
Handy ein E-Mail-Konto ein"). Gegenstück zum Desktop-host-agent (Linux/macOS/
Windows), aber Android ist kein Unix-Shell-System — deshalb ein anderes
Action-Set (UI-Automation statt beliebiger Shell-Kommandos).
Verbindet sich wie die ARIA-App ausgehend zum RVS (gleicher Token/Raum),
Verbindungs-Setup per QR-Scan oder manueller Eingabe. Taucht in der
Diagnostic unter Satelliten → Host-Agenten 💻 auf (host_hello mit
os="Android …" + Android-Caps).
Warum nativ (Kotlin), nicht Termux/RN
- UI-Automation (fremde Apps bedienen) geht auf Android nur über einen AccessibilityService — den kann nur eine native App bereitstellen.
- Screenshots einer laufenden Session: MediaProjection (native).
- Dauerbetrieb: Foreground-Service mit Notification (native).
- Termux gäbe nur Shell +
termux-api(SMS/Anruf/Standort …), kein Bedienen anderer App-UIs. Für „E-Mail-Konto durchklicken" reicht das nicht.
Tech: Kotlin, OkHttp-WebSocket (RVS-Client), CameraX/ML-Kit (QR), AccessibilityService (Input), MediaProjection (Screenshot). Build via Docker (Android-SDK + Gradle) → APK. Nur Linux baut APKs (Docker), Deploy manuell.
Action-Set (host_command → host_result)
Android-spezifisch (statt exec/read/write des Desktop-Agents):
| Action | Was |
|---|---|
screenshot |
Bildschirmfoto (MediaProjection) — ARIA sieht den Schirm |
ui_dump |
Sichtbare UI als Baum (Texte, Buttons, Felder + Koordinaten) — ARIAs „Augen" für gezieltes Tippen |
ui_tap |
Tippen (x,y ODER auf ein Element aus ui_dump) |
ui_text |
Text in das fokussierte/angegebene Feld schreiben |
ui_swipe |
Wischen/Scrollen |
ui_key |
Systemtasten (BACK, HOME, ENTER …) |
app_launch |
App per Paketname starten (z.B. E-Mail-App) |
app_list |
installierte Apps auflisten |
info |
Gerät: Modell, Android-Version, Akku, Netz, IP |
notify |
Benachrichtigung anzeigen |
| (später) | sms_send, call, location, clipboard (je nach Bedarf + Berechtigung) |
ARIA-Flow „E-Mail einrichten": app_launch (Mail-App) → screenshot/ui_dump
(sehen, was da ist) → ui_tap/ui_text (durchklicken) → wieder ui_dump prüfen,
bis fertig. Genau das agentische Muster wie beim Endian-Fix, nur mit Handy-UI.
Fire TV / Android TV
Dieselbe APK läuft auf Handy und Stick — die TV-Fähigkeiten schalten sich
automatisch frei (caps enthalten dann tv). Zusätzlich auf dem TV:
| Action | Was |
|---|---|
notify |
Einblendung über dem laufenden Bild (Text/Bild) — ohne Netflix & Co. zu stoppen; oder als Sprache, je nach Einstellung (mode überschreibt) |
speak |
Sprachausgabe über die TV-Lautsprecher (ARIAs echte Stimme, sonst Geräte-TTS) |
volume |
Lautstärke setzen (percent) |
listen / listen_stop |
Mikrofon öffnen/schließen — ARIA-Sprachdialog auf dem Gerät |
ui_key |
zusätzlich D-Pad: up/down/left/right/ok, play_pause/next/prev, lauter/leiser/stumm |
Sprachdialog: Die App spricht das gleiche Protokoll wie die ARIA-App
(stt_stream_* rein, chat + audio_pcm raus) — serverseitig ist nichts
anzupassen. In den App-Einstellungen wählst Du, wie ARIA hier antwortet:
Einblendung (Standard) oder Sprache; sie kann es pro Anfrage überschreiben.
Turn-Ownership: Der RVS verteilt jede Antwort an alle Clients im Raum. Damit nicht Handy und Stick gleichzeitig losreden, gibt dieses Gerät nur aus, was aus seiner eigenen Frage entstanden ist.
Mikrofon der Fire-TV-Fernbedienung: Die Mikro-Taste ist systemseitig mit Alexa belegt; ob Fremd-Apps an das Remote-Mikro kommen, ist je nach Stick- Generation unterschiedlich und muss am Gerät ausprobiert werden. Sicher funktioniert der Sprech-Knopf in der App (OK-Taste) — und falls das Remote- Mikro nicht hergibt, tut es ein USB-Mikro am Stick.
Berechtigungen einmalig in der App: „Einblendung erlauben" (Über anderen Apps anzeigen) und beim ersten Sprechen das Mikrofon.
Ausrollen per Satellit (ohne Datei-Kopieren)
Statt die APK von Hand aufs Gerät zu schaufeln, kann ein Satellit sie per ADB über das Netz installieren:
- Am Fire TV: Einstellungen › Mein Fire TV › Entwickleroptionen › ADB-Debugging an.
- Diagnostic → Satelliten → scannen. ADB-fähige Geräte zeigen ein ADB-Tag und einen 📦-Button.
- 📦 → APK-URL (aus dem Gitea-Release) → Jetzt ausrollen. Beim ersten Mal erscheint auf dem TV „USB-Debugging zulassen?" → bestätigen (Haken „Immer erlauben"). Der Rollout wartet darauf und macht dann automatisch weiter.
Einrichtung ohne Tippen: Am Fire TV gibt es keine Kamera (kein QR-Scan) und
Host/Token mit der Fernbedienung einzugeben ist eine Qual. Deshalb ist im Rollout-
Dialog „Gleich einrichten" vorausgewählt: die Diagnostic kennt den RVS-Zugang
selbst und gibt ihn dem Agenten über dieselbe ADB-Verbindung mit
(adb.provision → am start mit Intent-Extras). Der Agent speichert die Daten,
startet den Dienst und ist sofort online — null Eingaben am Fernseher.
Das Token geht dabei serverseitig raus, es steht nie im Browser-Formular.
Mit „Status prüfen" (adb.status) siehst Du jederzeit, ob der Agent auf dem
Gerät installiert ist, welche Version läuft und ob der Dienst aktiv ist.
Sicherheitshinweis: Die Einrichtung per Intent geht an die (exportierte) Haupt-Activity. Wer ADB-Zugriff auf das Gerät hat, kann den Agenten damit umkonfigurieren — wer ADB hat, kontrolliert das Gerät ohnehin. Die App zeigt beim Empfang einen Hinweis („Von ARIA eingerichtet"), damit es nicht unbemerkt passiert. Auf einem dedizierten Stick ist das unkritisch; schalte ADB-Debugging nach dem Ausrollen ab, wenn Du ganz sicher gehen willst.
ARIA kann dasselbe: satellite_command mit action='adb.install',
params={'ip':'…','url':'…'}. Der Satellit lädt die APK einmal und kann sie
auf beliebig viele Sticks installieren.
⚠️ Gerät muss ENTSPERRT sein, damit ARIA es steuern kann. Gesten und Systemtasten (
ui_tap/ui_text/ui_swipe/ui_key/app_launch) greifen bei gesperrtem Bildschirm nicht — Android-Sicherheit. Der Agent erkennt das und meldet „Gerät ist gesperrt — bitte erst entsperren", statt still „ok" zu sagen. Sehen (screenshot,ui_dump,info) funktioniert dagegen auch bei gesperrtem Gerät.
Dauerbetrieb — Foreground-Service vs. Push (FCM)
Der Agent muss immer erreichbar sein, obwohl Android Hintergrundprozesse aggressiv killt (Doze, App-Standby, OEM-Batterie-Manager wie Xiaomi/Huawei). Zwei Wege, deine WhatsApp-Intuition trifft ins Schwarze:
A) Foreground-Service (persistente WebSocket) — der einfache Start:
- Dauerhafte RVS-Verbindung + Foreground-Notification („Agent aktiv").
- Braucht:
FOREGROUND_SERVICE, Akku-Optimierung ausnehmen (REQUEST_IGNORE_BATTERY_OPTIMIZATIONS— User whitelistet die App),RECEIVE_BOOT_COMPLETED+ BootReceiver (Neustart nach Reboot), Auto-Reconnect (haben wir im Protokoll schon). - Reutzt unser bestehendes
host_hello/host_command/host_result1:1. - Nachteil: etwas Akku; manche OEMs killen trotzdem → „Autostart" manuell erlauben.
B) Self-hosted Push (KEIN Google!) — genau wie WhatsApp, aber auf eigenem Server:
- UnifiedPush + self-hosted ntfy: Auf dem ARIA-Server läuft ntfy (freier, self-hostbarer Push-Server). Der Agent nutzt UnifiedPush (offener Standard, de-Google-Welt/F-Droid) mit dem ntfy-Distributor auf dem Handy. Will ARIA etwas, POSTet die Bridge/RVS an ntfy → weckt die App → sie holt den Befehl vom RVS, arbeitet, antwortet. Läuft auch auf Custom-ROMs OHNE Google Play Services.
- Akkuschonend wie FCM, aber ohne jede Google-Abhängigkeit. Nur ein Dienst mehr (ntfy) im Stack + der Push-Auslöser serverseitig.
C) FCM (Google) — optional: Wer ein Stock-Android mit Play Services hat und Googles Push-Kanal will, kann FCM statt ntfy nehmen (bester Akku auf GMS-Geräten). Braucht Firebase-Projekt + Play Services. Nur eine Option, keine Pflicht.
Custom-ROM ohne Google: → Weg A (eigener Socket) oder B (self-hosted ntfy). Beide brauchen KEIN Google. Für Stefans dediziertes Ziel-Handy ist A sogar oft die einfachste Dauerlösung (unser eigener „Push" über den RVS-Socket).
Hybrid (ideal, End-Ausbau): Im Leerlauf nur Push (max. Akku). Ein Push weckt die App → sie öffnet die RVS-Verbindung, hält sich per Wakelock für die Interaktion wach (mehrere Befehle flüssig, z.B. E-Mail-Setup durchklicken) → schläft nach ein paar Sekunden Ruhe wieder ein. So WhatsApp-Akku UND schnelle Multi-Befehl-Sessions. Der Push kommt dabei von B (self-hosted ntfy) oder C (FCM) — freie Wahl. Erste Push-Latenz aus tiefem Doze ~1–3 s; danach bleibt der Socket die Session offen.
Empfehlung: Meilenstein 1–3 mit A (Foreground-Service) — läuft sofort und nutzt alles Vorhandene, damit wir schnell einen funktionierenden Agenten haben, ganz ohne externe Dienste. Dann Push-Hybrid mit self-hosted ntfy (B) als Akku-Ausbau — KEIN Google. FCM (C) nur optional für Stock-Android. Action-Set/Protokoll bleiben identisch, nur der Wecker ändert sich.
Sicherheit
- Reagiert nur auf den eigenen RVS-Raum (Token); Setup per QR/manuell.
- CONTROL_ENABLED-Schalter in der App (Default AUS) — erst wenn Stefan es bewusst aktiviert, führt der Agent Aktionen aus.
- AccessibilityService + MediaProjection müssen vom User explizit in den Android-Einstellungen freigegeben werden (kein stiller Zugriff möglich).
- Alle Aktionen werden protokolliert (In-App-Log + optional an ARIA).
- Voller Gerätezugriff — nur auf eigenen/anvertrauten Geräten nutzen.
Meilensteine
- ✅ Verbinden + sichtbar — Gradle-Projekt, AndroidManifest, RVS-WS-Client,
Foreground-Service, Connect-UI (QR-Scan + manuell),
host_hello/host_ping. → Agent erscheint in der Diagnostic.infofunktioniert. - ✅ Sehen — MediaProjection-Screenshot (
ScreenCapturer, gleicher{format,bytes,base64}-Vertrag wie der Desktop-Agent →host_screenshot) +ui_dump(AriaAccessibilityService, nur lesend → Brain-Toolhost_ui_dump). Freigabe einmalig in der App: „Bildschirm-Zugriff erlauben" + „Bedienungshilfe öffnen". → ARIA sieht den Schirm und liest die UI-Elemente mit Koordinaten. - ✅ Steuern —
ui_tap/ui_text/ui_swipe/ui_key/app_launchüber den AccessibilityService (canPerformGestures,dispatchGesture,ACTION_SET_TEXT,performGlobalAction) → Brain-Toolshost_ui_tap/_text/_swipe/_key/host_app_launch. Tap-Koordinaten = die x/y ausui_dump(echte Pixel), NICHT aus dem (skalierten) Screenshot. → ARIA bedient Apps (E-Mail-Setup). - Feinschliff —
app_list/notify, Build-Härtung,release_agent.sh.
Bauen
APK-Builds laufen nur unter Linux — deshalb im Docker-Container. Du brauchst
nichts Android-spezifisches installiert, nur Docker. Android-SDK, Gradle und
Build-Tools zieht der Container selbst (Dockerfile.build).
cd host-agent/android
./build.sh
build.sh baut das Image aria-android-agent-build und lässt darin
gradle assembleDebug laufen. Ergebnis:
host-agent/android/dist/aria-android-agent.apk
Das ist ein Debug-APK: auto-signiert mit dem Android-Debug-Key, also direkt installierbar — ohne eigenen Keystore, ohne Play Store.
Auf dem Handy installieren
dist/aria-android-agent.apkaufs Zielgerät kopieren (USB, Cloud,adb install dist/aria-android-agent.apk, …).- Antippen → Android fragt nach „Unbekannte Quellen / Aus dieser Quelle installieren erlauben" → erlauben.
- App öffnen → verbinden (QR/manuell), „Steuerung erlauben" an, für M2 zusätzlich „Bildschirm-Zugriff erlauben" + „Bedienungshilfe öffnen".
Was der erste Build kostet
Der erste Lauf lädt viel (JDK-Image, Gradle, Android-SDK, Dependencies) und dauert entsprechend — mehrere Minuten. Folge-Builds sind schnell (Docker-Layer + Gradle-Cache im Image). Häufige Stolperer:
- Docker fehlt / kein Zugriff →
docker-Rechte prüfen (docker ps). - Overlay-on-Overlay auf einem Live-ISO („invalid argument" beim Image-Bau) — gleiches Problem wie beim Desktop-Agent auf dem Mint-Live-System; von einer installierten Linux-Kiste bauen.
- Kotlin-/Manifest-Fehler beim allerersten Bau eines neuen Meilensteins: den Gradle-Fehler posten, das glätten wir schnell.
Version setzen
Bis es release.sh gibt, wird die Version in app/build.gradle gepflegt
(versionCode / versionName). Aktuell 1 / 0.2.0 (M1+M2).
Release
Das APK ist kein Teil des Git-Trees (blaeht sonst die History dauerhaft auf) —
es wird als Release-Asset an einen Tag gehaengt. Das macht release_agent.sh
(liegt eine Ebene hoeher, in host-agent/):
cd host-agent
./release_agent.sh 0.2.0
Das Skript (wie die release.sh der Haupt-App, Version als Parameter):
- setzt die Version (
host_agent.py→AGENT_VERSION,app/build.gradle→versionName/versionCode), - baut Linux-Binary + Android-APK per Docker,
- committet den Version-Bump, taggt
agent-v<version>(eigener Namespace, kollidiert nicht mit den App-Tagsv<version>) und pusht, - legt ein Gitea-Release an und laedt die Assets hoch:
aria-host-agent-linux-x64,aria-host-agent-android-agent-v<version>.apk, optional-macos/-windows.exe(falls inhost-agent/dist/vorgebaut).
Gitea-Zugang (GITEA_URL, GITEA_REPO, GITEA_USER) kommt aus der Umgebung oder
einer .env; das Kennwort wird interaktiv abgefragt. Binaries landen unter
„Releases", nie im Tree.
Status: M1–M3 fertig — verbinden,
info,screenshot,ui_dump(sehen) undui_tap/ui_text/ui_swipe/ui_key/app_launch(steuern);release_agent.shvorhanden. Damit läuft der volle Ablauf sehen→steuern (z.B. E-Mail-Konto einrichten). Nächstes: Feinschliff (M4).