Агент Android — Эксплуатация
Жизненный цикл
Boot → MyReceiver (BOOT_COMPLETED) → AutoStartUp service → MainActivity
│
▼
Heartbeat на сервер
│
┌───────────┴────────────┐
▼ ▼
Сервер отвечает «0» Нет интернета / не
(авторизовано) авторизовано → повтор
│
▼
PlayerActivity (fullscreen)
│
▼
Читает локальный playlist.txt
│
▼
Воспроизводит по кругу MP4 / JPG / PNG
Синхронизация контента
Фоновая служба AutoStartUp:
- Опрашивает сервер каждые N секунд (настраивается).
- Сравнивает список файлов на сервере с локальными.
- Скачивает отсутствующие или изменившиеся, проверяя целостность по CRC32. Когда файл скачан полностью, рядом с ним создаётся файл
.ok. - Перезаписывает
playlist.txt(JSON) с текущим порядком и временем показа каждого элемента. - Плеер перечитывает
playlist.txtв начале каждого витка цикла — изменения применяются без перезапуска приложения.
Поддерживаемые форматы
| Тип | Подробности |
|---|---|
| Видео | MP4 (H.264). Воспроизводится целиком на каждом витке. |
| Статичное изображение | JPG, PNG. Время задаётся в playlist. |
| GIF | Распознаётся, но пропускается (не воспроизводится). |
| Fallback | Если контента нет, показывается изображение по умолчанию (sat.jpg). |
Режимы отображения
Два layout на выбор в настройках Admin:
- Растяжение на весь экран (
relative_layout_video) — использует весь экран, может искажать пропорции. - Letterbox (
player_content) — сохраняет исходные пропорции, при необходимости добавляет полосы.
Отчёт о состоянии
При каждом heartbeat агент отправляет:
accio=esticViu— «я жив» — проверяет авторизацию.accio=gps(каждую минуту, не только координаты) — включает модель (Build.DEVICE), версию Android (Build.VERSION.SDK_INT), uptime (SystemClock.elapsedRealtime(), включая время в deep-sleep), уровень сигнала и время следующей перезагрузки.accio=estat&estat=N— состояние загрузки / воспроизведения:- 0 — не начато
- 1 — загрузка
- 2 — загружено
- 3 — воспроизведение
Именно эти значения вы видите в столбце Статус playlist панели.
Удалённые снимки экрана
В панели пункт Действия → Снимок экрана запускает снимок экрана устройства. Сервер добавляет флаг (screenshot:1) в следующий ответ gps (≤ 60 с); AutoStartUp обнаруживает его и передаёт задачу ScreenshotCapture.
Агент пробует три способа по порядку, от наиболее к наименее функциональному:
Способ 1 — AccessibilityService (рекомендуется, требует однократной настройки)
ScreenshotAccessibilityService — это системная служба, которая снимает весь экран устройства: включая system UI, другие приложения, диалоги ошибок / ANR, экран блокировки и, что особенно важно, диалог «приложение остановлено», если kiosk аварийно завершился. Она переживает сбои Activity / Service, потому что Android автоматически перезапускает привязки служб специальных возможностей.
Требования:
- Android ≥ 11 (API 30). На более ранних версиях этот способ пропускается.
- Однократное включение на каждом устройстве:
- Settings → Accessibility → Установленные приложения → Digital Signage RDS
- Включить переключатель. Android предупредит, что служба сможет читать и обрабатывать события — подтвердите.
- После включения больше ничего делать не нужно; служба автоматически привязывается заново при запуске.
Если служба не включена, агент при запуске записывает в 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.
Способ 2 — Кадр воспроизводимого медиафайла (PlayerActivity)
Если AccessibilityService не активна и текущий режим — playlist, агент:
- Делает снимок в UI-потоке текущего файла и позиции воспроизведения
- В
HandlerThreadдекодирует:- изображение (
.jpg/.png) →BitmapFactory.decodeFile - видео →
MediaMetadataRetriever.getFrameAtTime(posMs, OPTION_CLOSEST)
- изображение (
Это позволяет избежать проблемы чёрного прямоугольника, вызванной тем, что PixelCopy(Window) не может прочитать аппаратный overlay SurfaceView, в котором отрисовывается видео.
Способ 3 — PixelCopy окна (KioskBrowserActivity / резервный вариант)
Для режима Web (WebView, без аппаратного overlay) или как последнее средство: PixelCopy.request(Window, …) на API ≥ 26 — снимает WebView/Surface с аппаратным ускорением. View.draw(Canvas) на API 24-25.
Общее для всех трёх способов
- JPEG с качеством 70 (обычно ~150-400 КБ).
- Подписывается HMAC-SHA256 v2 и загружается на
/suport/upload_screenshot.php. - Не требует
MediaProjection: способы 2 и 3 снимают собственный контент; способ 1 — системная служба, легитимно разрешённая администратором.
Подробности процесса в панели.
Восстановление после сбоев
MyExceptionHandler перехватывает необработанные исключения и автоматически перезапускает приложение. Это гарантирует, что устройство вернётся к воспроизведению контента даже после разового сбоя.
Логи
Агент отправляет операционные логи на сервер. Чтобы посмотреть их в панели: Устройства → Действия → Логи.
Обновления
Сейчас APK проверяет наличие последней версии и, если она новее, скачивает новый APK с сервера (descarregar_apk.php). Точное поведение зависит от настроек производителя; в некоторых внедрениях обновление выполняется удалённо со стороны Promotienda.
Известные ограничения
- В Android 8+ фоновые службы ограничены — агенту могут потребоваться дополнительные разрешения, чтобы поддерживать синхронизацию при выключенном экране.
- В Android 10+ scoped storage требует использовать
MANAGE_EXTERNAL_STORAGEили MediaStore. Если ваше устройство новое и приложение не может писать на диск, обратитесь в службу поддержки.
Используемые HTTP-эндпоинты
| Endpoint | Назначение |
|---|---|
suport/WebServiceTablet.php?accio=esticViu |
Heartbeat / авторизация |
suport/WebServiceTablet.php?accio=estat&estat=N |
Отчёт о состоянии playlist |
descarregar_apk.php |
Автообновление APK |