Android-Agent — Betrieb
Lebenszyklus
Boot → MyReceiver (BOOT_COMPLETED) → AutoStartUp service → MainActivity
│
▼
Heartbeat an den Server
│
┌───────────┴────────────┐
▼ ▼
Server antwortet "0" Kein Internet / nicht
(autorisiert) autorisiert → Neuversuch
│
▼
PlayerActivity (fullscreen)
│
▼
Liest lokale playlist.txt
│
▼
Spielt MP4 / JPG / PNG in Schleife ab
Synchronisierung der Inhalte
Der Hintergrunddienst AutoStartUp:
- Fragt den Server alle N Sekunden ab (konfigurierbar).
- Vergleicht die Dateiliste des Servers mit den lokalen Dateien.
- Lädt fehlende oder geänderte Dateien herunter und prüft die Integrität per CRC32. Sobald eine Datei vollständig geladen ist, wird daneben eine
.ok-Datei angelegt. - Schreibt
playlist.txt(JSON) mit der aktuellen Reihenfolge und den Zeiten je Element neu. - Der Player liest
playlist.txtzu Beginn jeder Schleifenrunde neu ein — Änderungen greifen ohne Neustart der App.
Unterstützte Formate
| Typ | Details |
|---|---|
| Video | MP4 (H.264). Wird in jeder Runde vollständig wiedergegeben. |
| Standbild | JPG, PNG. Anzeigedauer in der Playlist konfiguriert. |
| GIF | Wird erkannt, aber übersprungen (keine Wiedergabe). |
| Fallback | Ist kein Inhalt verfügbar, wird ein Standardbild angezeigt (sat.jpg). |
Anzeigemodi
Zwei Layouts, wählbar in den Admin-Einstellungen:
- Stretch auf Vollbild (
relative_layout_video) — nutzt den gesamten Bildschirm, kann das Seitenverhältnis verzerren. - Letterbox (
player_content) — behält das Originalverhältnis bei und ergänzt bei Bedarf Balken.
Statusmeldung
Bei jedem Heartbeat sendet der Agent:
accio=esticViu— "ich lebe" — prüft die Authentifizierung.accio=gps(jede Minute, nicht nur Koordinaten) — enthält Modell (Build.DEVICE), Android-Version (Build.VERSION.SDK_INT), Uptime (SystemClock.elapsedRealtime(), inklusive Deep-Sleep-Zeit), Empfang und nächsten Neustart.accio=estat&estat=N— Download-/Wiedergabestatus:- 0 — nicht gestartet
- 1 — wird heruntergeladen
- 2 — heruntergeladen
- 3 — Wiedergabe
Diese Werte sehen Sie in der Spalte Playlist-Status im Panel.
Remote-Screenshots
Über Aktionen → Screenshot im Panel lösen Sie eine Aufnahme des Geräts aus. Der Server hängt der nächsten gps-Antwort ein Flag (screenshot:1) an (≤ 60 s); AutoStartUp erkennt es und delegiert an ScreenshotCapture.
Der Agent versucht drei Wege in dieser Reihenfolge, vom leistungsfähigsten zum einfachsten:
Weg 1 — AccessibilityService (empfohlen, einmalige Einrichtung nötig)
ScreenshotAccessibilityService ist ein Systemdienst, der den gesamten Bildschirm des Geräts aufnimmt — inklusive System-UI, anderer Apps, Fehler-/ANR-Dialogen, Sperrbildschirm und, entscheidend, dem Dialog "app crashed", falls der Kiosk abgestürzt ist. Er übersteht Abstürze der Activity / des Service, weil Android die Bindings der Bedienungshilfen automatisch neu aufbaut.
Voraussetzungen:
- Android ≥ 11 (API 30). In älteren Versionen wird dieser Weg übersprungen.
- Einmalige Aktivierung pro Gerät:
- Settings → Accessibility → Installierte Apps → Digital Signage RDS
- Den Schalter aktivieren. Android weist darauf hin, dass der Dienst Ereignisse lesen und manipulieren kann — bestätigen Sie.
- Danach ist nichts weiter zu tun; der Dienst wird beim Start automatisch neu gebunden.
Ist der Dienst nicht aktiviert, protokolliert der Agent beim Start in agent.log:
[SCREENSHOT] Full-screen captures disabled — enable 'Digital Signage RDS' in
Settings → Accessibility for captures that work even when the
kiosk app is not foreground.
Weg 2 — Frame des laufenden Mediums (PlayerActivity)
Ist der AccessibilityService nicht aktiv und der aktive Modus playlist, geht der Agent so vor:
- Snapshot im UI-Thread der aktuellen Datei + Wiedergabeposition
- In einem
HandlerThreadwird dekodiert:- Bild (
.jpg/.png) →BitmapFactory.decodeFile - Video →
MediaMetadataRetriever.getFrameAtTime(posMs, OPTION_CLOSEST)
- Bild (
Damit wird das Problem des schwarzen Rechtecks umgangen, das durch PixelCopy(Window) entsteht, weil damit das Hardware-Overlay der SurfaceView, in der das Video gerendert wird, nicht ausgelesen werden kann.
Weg 3 — PixelCopy des Fensters (KioskBrowserActivity / Fallback)
Für den Web-Modus (WebView, ohne Hardware-Overlay) oder als letzte Möglichkeit: PixelCopy.request(Window, …) ab API 26 — nimmt GPU-beschleunigte WebView/Surface auf. View.draw(Canvas) bei API 24-25.
Allen drei Wegen gemeinsam
- JPEG in Qualität 70 (typischerweise ~150-400 KB).
- Mit HMAC-SHA256 v2 signiert und nach
/suport/upload_screenshot.phphochgeladen. - Kein
MediaProjectionerforderlich: Weg 2 und 3 nehmen eigene Inhalte auf; Weg 1 ist ein Systemdienst, der vom Administrator rechtmäßig freigegeben wurde.
Crash Recovery
MyExceptionHandler fängt unbehandelte Ausnahmen ab und startet die App automatisch neu. So gibt das Gerät auch nach einem einzelnen Fehler wieder Inhalte wieder.
Logs
Der Agent sendet Betriebs-Logs an den Server. Zum Ansehen im Panel: Geräte → Aktionen → Logs.
Updates
Das APK prüft derzeit auf die neueste Version und lädt bei Bedarf das neue APK vom Server herunter (descarregar_apk.php). Das genaue Verhalten hängt von der Konfiguration des Herstellers ab; in manchen Installationen erfolgt die Aktualisierung per Fernzugriff durch Promotienda.
Bekannte Einschränkungen
- Unter Android 8+ unterliegen Hintergrunddienste Einschränkungen — der Agent benötigt unter Umständen zusätzliche Berechtigungen, um die Synchronisierung bei ausgeschaltetem Bildschirm aufrechtzuerhalten.
- Unter Android 10+ erzwingt Scoped Storage die Nutzung von
MANAGE_EXTERNAL_STORAGEoder MediaStore. Wenn Ihr Gerät neu ist und die App nicht schreiben kann, wenden Sie sich an den Support.
Verwendete HTTP-Endpoints
| Endpoint | Funktion |
|---|---|
suport/WebServiceTablet.php?accio=esticViu |
Heartbeat / Auth |
suport/WebServiceTablet.php?accio=estat&estat=N |
Statusmeldung der Playlist |
descarregar_apk.php |
Auto-Update des APK |