# Kids' Android client — Phase 5.1 The core no-wipe block path of the kids' phone app (AGENTS.md §11 Phase 5, FR-16 + FR-17). A normal Gradle project with its own wrapper. The toolchain is **not** on `.13`; it builds on `.27`: ```bash ssh 192.168.20.27 '~/android/build.sh internet_use_control' ``` That pulls this repo from Gitea and runs `./gradlew assembleDebug`. It prints `APK=`; the debug APK is `android/app/build/outputs/apk/debug/app-debug.apk`. ## What it does | Piece | File | Job | |---|---|---| | Accessibility Service | `BlockAccessibilityService.kt` | Watches the foreground package (FR-16). | | Block overlay | `OverlayController.kt` | A full-screen `TYPE_APPLICATION_OVERLAY` window over a blocked app. | | Block rule | `BlockEngine.kt` | Blocked = locked **and** on the blocklist **and** not allowlisted (FR-4). | | Config transport | `MqttController.kt` | Subscribes, retained, to `restrict//config` on the 8883 TLS plane with the device's own credentials; publishes presence and tamper on `restrict//status`. | | Last state | `AppPrefs.kt` | The last config is kept on disk, so a broker-less device keeps its rules (FR-14). | | Tamper alert | `TamperReporter.kt` | Reports a disabled service, a revoked overlay permission, or a force-stop (FR-17). | | Status screen | `MainActivity.kt` | What is blocked, until when, and the health of the enforcement. | **No Device Owner. No factory reset. No managed profile.** The child can disable the client; the enforcement is the tamper alert, not the overlay. ## How the tamper alert reaches Sam The device's broker ACL only lets it write its own `status` topic, so the tamper report rides there: ```json {"online":true,"tamper":{"kind":"accessibility_disabled","detail":"the service was destroyed","at":"2026-10-13T08:00:00Z"}} ``` `internal/mqtt` parses it, `internal/alert` records a `tamper` alert and delivers it through Apprise, and `cmd/control` wires the two together. ## Test on the headless emulator ```bash ssh 192.168.20.27 '~/android/emu.sh start' ssh 192.168.20.27 '~/android/emu.sh wait' ssh 192.168.20.27 '~/android/emu.sh install /tmp/webrestrict-pre/android/app/build/outputs/apk/debug/app-debug.apk' PKG=au.audasmedia.webrestrict.kids adb shell appops set $PKG SYSTEM_ALERT_WINDOW allow adb shell settings put secure enabled_accessibility_services $PKG/$PKG.BlockAccessibilityService adb shell settings put secure accessibility_enabled 1 # Open a blocked app (the local default blocks Settings) and screenshot. adb shell am start -a android.settings.SETTINGS sleep 3 ssh 192.168.20.27 '~/android/emu.sh screenshot /tmp/shot.png' # Show the tamper alert: disable the service. adb shell settings put secure accessibility_enabled 0 adb logcat -d -s WebRestrictTamper ssh 192.168.20.27 '~/android/emu.sh stop' ```