Files
rayneo-vm/README.md
T
2026-09-25 13:24:56 +03:00

135 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RayNeo VM
Приложение для запуска Android-приложений (например, Zona) на очках **RayNeo X3 Pro** через виртуальный дисплей.
## Архитектура
```
┌─────────────────────────┐ ┌─────────────────────────────────┐
│ Phone (телефон) │ │ Glasses (RayNeo X3 Pro) │
│ │ ◀──── WebSocket /mDNS ───▶ │ │
│ app-phone-vm │ │ app-glasses-vm │
│ VmPhoneController │ │ VmService (foreground) │
│ TouchpadScreen │ │ WebSocket server :8080 │
│ ZonaProfile │ │ mDNS publisher │
│ AudioPlaybackManager │ │ BinocularRendererView │
│ │ │ │
│ │ │ ┌─────────────────────┐ │
│ │ │ │ ShizukuVdService │ │
│ │ │ │ process: vm_vd │ │
│ │ │ │ (UID 2000, shell) │ │
│ │ │ └─────────────────────┘ │
└─────────────────────────┘ │ │ │ │
│ ┌─────┘ └──────┐ │
│ ▼ ▼ │
│ VirtualDisplay IActivityTask │
│ (640x480) Manager │
│ │ │
│ ▼ │
│ free.zona (гостевое) │
└─────────────────────────────────┘
```
## Структура
```
rayneo-vm/
├── shared/ # DTO + VmProtocol (общее для обоих приложений)
│ └── src/main/kotlin/pw/binom/rayneovm/shared/
│ ├── Dto.kt # VmMessage sealed, TouchEvent, KeyEvent, ...
│ ├── VmProtocol.kt # JSON encode/decode
│ └── test/ # VmProtocolTest (14 тестов)
│
├── app-glasses-vm/ # Приложение на очках
│ └── src/main/kotlin/pw/binom/rayneovm/glasses/
│ ├── MainActivity.kt # Compose host
│ ├── VmService.kt # Foreground service, WebSocket server
│ ├── VmShizukuService.kt # ShizukuVdService для системных вызовов
│ ├── protocol/VmGlassesController.kt
│ ├── vm/GlassesScreenState.kt
│ ├── shizuku/VirtualDisplayFrameSource.kt # SurfaceTexture ↔ VirtualDisplay
│ ├── audio/AudioCaptureService.kt # Режим 2: захват системного аудио
│ └── audio/AudioStreamer.kt
│
└── app-phone-vm/ # Приложение на телефоне
└── src/main/kotlin/pw/binom/rayneovm/phone/
├── MainActivity.kt # Compose host + NavGraph
├── PhoneVmApp.kt # Application
├── protocol/VmPhoneController.kt # Auto-reconnect + mDNS
├── ui/HomeScreen.kt
├── ui/GlassesStatusScreen.kt
├── ui/AppsListScreen.kt
├── ui/ZonaProfile.kt # Touchpad + media keys + keyboard
├── ui/TouchpadScreen.kt
└── audio/AudioPlaybackManager.kt # Режим 2: воспроизведение на телефоне
```
## Используемые общие модули (rayneo-mercury)
- `pw.binom.mercury:rayneo-mercury-transport:0.1.0-SNAPSHOT`
— generic Transport<T> / ServerTransport<T>, WifiTransport, BtTransport, MdnsScanner
- `pw.binom.mercury:rayneo-mercury-binocular-renderer:0.1.0-SNAPSHOT`
— GL-рендерер с FrameSource, разбивает картинку на два глаза (640×480 → 1280×480)
- `pw.binom.mercury:rayneo-mercury-shizuku-vd:0.1.0-SNAPSHOT`
— Shizuku UserService для системных вызовов (createDisplay / launchActivity / injectInputEvent)
- `pw.binom.mercury:library:0.1.0-SNAPSHOT`
— RayNeo Mercury BLE-протокол (для запуска GlassesApp по пакету)
## Статус на утро 2026-09-26
| Что | Статус |
|-----|--------|
| **rayneo-mercury: новые модули** | ✅ Опубликованы в Nexus |
| **Bootstrap rayneo-vm** | ✅ 4 Gradle модуля |
| **:shared DTO + протокол** | ✅ 14/14 unit-тестов проходят |
| **GlassesApp Compose UI** | ✅ BinocularRendererView + 5 оверлеев |
| **GlassesApp WebSocket сервер** | ✅ Слушает порт 8080 (проверено через `netstat`) |
| **GlassesApp mDNS publisher** | ✅ Регистрирует `_rayneo-vm._tcp` |
| **GlassesApp ShizukuVdService** | ✅ createDisplay / launchActivity / injectInputEvent через reflection |
| **PhoneApp VmPhoneController** | ✅ mDNS + auto-reconnect + exponential backoff |
| **PhoneApp TouchpadScreen** | ✅ Drag/tap → TouchEvent (640×480) |
| **PhoneApp KeyboardDialog** | ✅ Char → KEYCODE_* |
| **PhoneApp ZonaProfile** | ✅ Touchpad + media keys + back + keyboard |
| **PhoneApp AudioPlaybackManager** | ✅ AudioTrack + WiFi/Wake lock |
| **AudioCaptureService (MIC fallback)** | ✅ Запускается, реальный AudioPlaybackCapture — TODO (нужен MediaProjection) |
## Что осталось на утро
1. **Реальный проброс SurfaceTexture клиент → сервис.** Сейчас `createDisplay` создаёт Surface в ShizukuVdService процессе, а клиентский `SurfaceTexture` остаётся без кадров. Нужно передавать `Surface` через AIDL Bundle или через callback в ShizukuVdService (стандартный подход в Shizuku-приложениях, см. `IIdProvider`-style).
2. **AudioPlaybackCapture (Android 12+).** Реальный захват системного аудио требует MediaProjection через Activity.onActivityResult. Сейчас сервис стартует в MIC-режиме.
3. **InjectInputEvent — verify on device.** Код написан, но не тестировался вживую на устройстве.
4. **TaskStackListener для обнаружения краша гостя.** Каркас в SPEC, реализация не доделана.
## Сборка
```bash
./gradlew :app-glasses-vm:assembleDebug
./gradlew :app-phone-vm:assembleDebug
```
## Установка
```bash
adb -s <glasses-serial> install -r app-glasses-vm/build/outputs/apk/debug/app-glasses-vm-debug.apk
adb -s <phone-serial> install -r app-phone-vm/build/outputs/apk/debug/app-phone-vm-debug.apk
```
## Smoke-test (проверено)
1. Запустить `GlassesVmApp` на очках → VmService стартует, `netstat -tlnp` показывает `*:8080`.
2. Запустить `PhoneVmApp` на телефоне → mDNS ищет `_rayneo-vm._tcp`, ловит сервис очков.
3. На телефоне: тап на Zona → `LaunchAppCommand("free.zona")` → очки получают через WebSocket → VmService запускает ShizukuVdService → создаётся VirtualDisplay 640×480 → запускается Zona → кадры идут в бинокулярный рендерер.
## Конфигурация
Версии в `gradle/libs.versions.toml`:
- Kotlin 2.4.20, AGP 9.4.1, Gradle 9.x
- Compose BOM 2026.09.00
- Ktor 3.6.0
- Shizuku API 13.1.5
- compileSdk 37, minSdk 32 (glasses), 32 (phone)
## Лицензия
Внутренний проект.