8574424fb7
Lint & Test / test (push) Successful in 2m10s
Adds a native Android TV application that runs the full LedGrab Python server in-process via Chaquopy. Captures the TV box screen using the MediaProjection API and exposes the existing web UI on the device's local network — users configure via phone/tablet browser. Android (new /android/ module): - Kotlin shell: MainActivity, CaptureService (foreground service), ScreenCapture (MediaProjection + ImageReader), PythonBridge (Chaquopy). - Polished Leanback-themed UI with QR code for easy web UI access. - AGP 8.9 + Chaquopy 17 + Gradle 8.11 (avoids the AGP 8.7 thread-lock bug). - Pre-built pydantic-core wheels for arm64-v8a, x86_64, x86 cross-compiled with maturin + Android NDK, linked against Chaquopy's libpython3.11.so. Python server platform guards: - New utils/platform.py with is_android()/is_windows()/is_linux() helpers. - Guard every top-level import of desktop-only packages (mss, psutil, sounddevice, pyserial, PyAudioWPatch, etc.) with try/except ImportError. - Android-incompatible calls gated with None-checks so the server runs on reduced capabilities on Android (no CPU/RAM metrics, no mss displays). - utils/image_codec.py gains a Pillow fallback for resize + JPEG encode when cv2 is unavailable; all internal cv2.resize callers migrated. - New android_entry.py start_server/stop_server invoked from Kotlin. - get_displays API falls back to best available engine when mss fails. New capture engines: - MediaProjectionEngine: receives RGBA frames pushed from Kotlin through a thread-safe queue; caches last frame for static-screen previews. - ScrcpyClientEngine: optional H.264 streaming via scrcpy-client library (priority 10, overrides the ADB-screencap engine when installed). Frontend: - Tab loaders previously required an apiKey; now correctly treat "auth disabled" as authenticated (Android has no auth by default). - Re-trigger the active tab's loader after loadServerInfo resolves authRequired, since initTabs runs earlier. - Add i18n keys for the demo / mediaprojection / scrcpy_client engines. Docs: - TODO.md: follow-ups for multi-ABI wheel rebuilds, CI pipeline, USB serial LED controllers, root-only capture, perf metrics abstraction. - CLAUDE.md: Android dependency sync policy (pip --exclude doesn't exist). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
93 lines
3.0 KiB
Kotlin
93 lines
3.0 KiB
Kotlin
plugins {
|
|
id("com.android.application")
|
|
id("org.jetbrains.kotlin.android")
|
|
id("com.chaquo.python")
|
|
}
|
|
|
|
android {
|
|
namespace = "com.ledgrab.android"
|
|
compileSdk = 34
|
|
|
|
defaultConfig {
|
|
applicationId = "com.ledgrab.android"
|
|
minSdk = 24 // Android 7.0 — covers nearly all TV boxes
|
|
targetSdk = 34
|
|
versionCode = 1
|
|
versionName = "0.3.0"
|
|
|
|
ndk {
|
|
// Temporarily x86 only for emulator testing with new wheel
|
|
abiFilters += listOf("x86")
|
|
}
|
|
}
|
|
|
|
buildTypes {
|
|
release {
|
|
isMinifyEnabled = false
|
|
}
|
|
}
|
|
|
|
compileOptions {
|
|
sourceCompatibility = JavaVersion.VERSION_17
|
|
targetCompatibility = JavaVersion.VERSION_17
|
|
}
|
|
|
|
kotlinOptions {
|
|
jvmTarget = "17"
|
|
}
|
|
}
|
|
|
|
chaquopy {
|
|
defaultConfig {
|
|
version = "3.11"
|
|
|
|
pip {
|
|
// Pre-built wheels directory (for pydantic-core etc.)
|
|
// Must use absolute file:// URI with forward slashes
|
|
options("--find-links", "file:///${rootDir.absolutePath.replace("\\", "/")}/wheels/")
|
|
|
|
// ── Android-compatible dependencies ─────────────────
|
|
// Listed explicitly because pyproject.toml includes
|
|
// desktop-only packages with no Android wheels.
|
|
// See CLAUDE.md "Android Dependency Sync" for policy.
|
|
install("fastapi")
|
|
install("uvicorn") // without [standard] — no uvloop/httptools
|
|
install("httpx")
|
|
install("numpy")
|
|
install("pydantic") // needs pydantic-core wheel in wheels/
|
|
install("pydantic-settings")
|
|
install("PyYAML")
|
|
install("structlog")
|
|
install("python-json-logger")
|
|
install("python-dateutil")
|
|
install("python-multipart")
|
|
install("jinja2")
|
|
install("zeroconf")
|
|
install("aiomqtt")
|
|
install("openrgb-python")
|
|
// opencv-python-headless: no cp311 Android wheel on Chaquopy.
|
|
// LedGrab's cv2 usage is guarded with try/except ImportError
|
|
// and falls back to numpy/Pillow alternatives on Android.
|
|
install("Pillow")
|
|
install("websockets")
|
|
}
|
|
}
|
|
}
|
|
|
|
// LedGrab Python source is included via a directory junction:
|
|
// android/app/src/main/python/ledgrab -> server/src/ledgrab
|
|
// This is the standard Chaquopy way to include local Python packages.
|
|
// Create the junction (run from repo root, no admin needed):
|
|
// cmd /c "mklink /J android\app\src\main\python\ledgrab server\src\ledgrab"
|
|
|
|
|
|
dependencies {
|
|
implementation("androidx.core:core-ktx:1.13.1")
|
|
implementation("androidx.appcompat:appcompat:1.7.0")
|
|
implementation("androidx.leanback:leanback:1.0.0")
|
|
implementation("com.google.android.material:material:1.12.0")
|
|
implementation("androidx.lifecycle:lifecycle-service:2.8.7")
|
|
// QR code generation for displaying server URL on TV
|
|
implementation("com.google.zxing:core:3.5.3")
|
|
}
|