b3775b2f98
Boot-time startup so LedGrab has display capture and control without user interaction on rooted TV boxes. Also folds in a batch of review findings from the Android package audit. Autostart - BootReceiver fires on BOOT_COMPLETED / LOCKED_BOOT_COMPLETED / MY_PACKAGE_REPLACED, gated by AutostartPrefs and Root.looksRooted(). Dispatches CaptureService.createRootIntent via ContextCompat.startForegroundService. Unrooted devices are a no-op because MediaProjection consent cannot be bypassed silently. - AutostartPrefs: thin SharedPreferences wrapper, defaults to enabled. Exposed as a CheckBox on the stopped panel; greyed out when not rooted. - Manifest: RECEIVE_BOOT_COMPLETED, REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, WAKE_LOCK permissions + the new BootReceiver. - MainActivity prompts for battery-optimization exemption on first opt-in so Doze/App Standby doesn't kill the FG service on phones. Service stability - onStartCommand now flips isRunning only after startForeground succeeds (was stuck=true forever if the FG transition threw) and resets on exception. Returns START_REDELIVER_INTENT for root mode so the OS can restart the service with the original intent (no consent token to invalidate); MediaProjection mode keeps START_NOT_STICKY. - Watchdog coroutine monitors RootScreenrecord.framesDelivered. Respawns the pipeline on stall (reusing the existing Python bridge — no server restart), caps at 3 consecutive restarts before giving up. - RootScreenrecord.framesDelivered is now an AtomicInteger, exposed as a public property for the watchdog. - ScreenCapture takes an onProjectionStopped lambda; when the user taps the system Cast/Screen-capture stop banner, the whole service is torn down instead of leaving a stale FG notification. - MainActivity's two startForegroundService calls switch to ContextCompat.startForegroundService, clearing pre-existing NewApi lint errors (minSdk=24 < API 26 native method). Build - versionCode derived from git rev-list --count HEAD (or the ANDROID_VERSION_CODE env var for CI). Was pinned to 1 — sideload upgrades were silently refusing to install. - New i18n strings (autostart_label, autostart_unavailable, version_prefix) in en/ru/zh; version_text now uses the resource instead of string concat. TODO.md: new "Android Autostart on Boot" section tracking done/pending items; real-hardware verification on a Magisk'd TV box is the remaining checkbox.
102 lines
4.6 KiB
XML
102 lines
4.6 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
xmlns:tools="http://schemas.android.com/tools">
|
|
|
|
<!-- BLE scanning and connecting — API ≥31 uses granular permissions;
|
|
older releases need BLUETOOTH + ACCESS_FINE_LOCATION for scanning.
|
|
neverForLocation avoids the location permission dialog on API 31+. -->
|
|
<uses-permission android:name="android.permission.BLUETOOTH"
|
|
android:maxSdkVersion="30" />
|
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
|
|
android:maxSdkVersion="30" />
|
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
|
|
android:maxSdkVersion="30" />
|
|
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
|
|
android:usesPermissionFlags="neverForLocation"
|
|
tools:targetApi="s" />
|
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
|
|
|
<!-- BLE hardware — required=false so non-BT boxes still install. -->
|
|
<uses-feature
|
|
android:name="android.hardware.bluetooth_le"
|
|
android:required="false" />
|
|
|
|
<!-- Network access for WLED HTTP/UDP, web UI, MQTT -->
|
|
<uses-permission android:name="android.permission.INTERNET" />
|
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
|
|
|
<!-- MediaProjection requires a foreground service -->
|
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
|
|
|
|
<!-- POST_NOTIFICATIONS for Android 13+ foreground service notification -->
|
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
|
|
<!-- Autostart on boot — BootReceiver spawns CaptureService in root
|
|
mode so capture resumes without the user touching the remote. -->
|
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
|
<!-- Exempt from Doze/App Standby so the FG service isn't killed
|
|
overnight on phones; essentially a no-op on TV boxes. -->
|
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
|
<!-- Optional wake lock for sustained-performance boxes that aggressively
|
|
sleep the CPU with the display off. -->
|
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
|
|
<!-- Android TV declarations -->
|
|
<uses-feature
|
|
android:name="android.software.leanback"
|
|
android:required="true" />
|
|
<uses-feature
|
|
android:name="android.hardware.touchscreen"
|
|
android:required="false" />
|
|
|
|
<!-- USB host — for USB-to-TTL adapters driving Adalight/AmbiLED
|
|
controllers. required=false so phones without USB host still install. -->
|
|
<uses-feature
|
|
android:name="android.hardware.usb.host"
|
|
android:required="false" />
|
|
|
|
<application
|
|
android:name=".LedGrabApp"
|
|
android:allowBackup="false"
|
|
android:icon="@mipmap/ic_launcher"
|
|
android:label="@string/app_name"
|
|
android:banner="@drawable/ic_launcher"
|
|
android:networkSecurityConfig="@xml/network_security_config"
|
|
android:theme="@style/Theme.LedGrab">
|
|
|
|
<!-- TV launcher activity -->
|
|
<activity
|
|
android:name=".MainActivity"
|
|
android:exported="true">
|
|
<intent-filter>
|
|
<action android:name="android.intent.action.MAIN" />
|
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
|
</intent-filter>
|
|
</activity>
|
|
|
|
<!-- Foreground service for screen capture + Python server -->
|
|
<service
|
|
android:name=".CaptureService"
|
|
android:foregroundServiceType="mediaProjection"
|
|
android:exported="false" />
|
|
|
|
<!-- Autostart — fires on device boot (and package replace).
|
|
On rooted devices, launches CaptureService directly so capture
|
|
resumes without the user tapping Start. Unrooted devices are
|
|
no-op because MediaProjection consent cannot be bypassed. -->
|
|
<receiver
|
|
android:name=".BootReceiver"
|
|
android:exported="true"
|
|
android:enabled="true">
|
|
<intent-filter>
|
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
|
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
|
</intent-filter>
|
|
</receiver>
|
|
</application>
|
|
|
|
</manifest>
|