Fetchin Kiosk turns an Android tablet into a dedicated WebView kiosk for one HTTPS web system. It is built for public APK distribution: each installation configures its own page URL and administrator PIN on first launch, so the repository does not ship with a production URL, password, token, or secret.
| Area | Behavior |
|---|---|
| First-run setup | Collects HTTPS URL, admin PIN, and PIN confirmation before kiosk mode starts. |
| WebView lock-down | Allows only the configured HTTPS host and true subdomains. Blocks unsafe schemes and downloads. |
| Kiosk mode | Uses Android Device Owner, DevicePolicyManager, and Lock Task Mode when provisioned. |
| Admin access | Hidden gesture opens PIN challenge; valid PIN starts a temporary maintenance session. |
| PIN storage | Stores PBKDF2 hash and salt material in private app data, never plain-text PIN. |
| Public repo safety | No production URL, PIN, API key, token, certificate, or shared secret belongs in source. |
Fetchin Kiosk is an MVP-stage native Android app. The core WebView policy, first-run setup, admin PIN verification, Device Owner/Lock Task startup, and emulator validation are implemented. Real-device validation is still required before production use.
| Goal | Path |
|---|---|
| Try the app without kiosk security | Install APK, launch app, complete first-run setup. |
| Test real kiosk behavior in emulator | Wipe AVD, install APK, set Device Owner, launch app, verify Lock Task. |
| Build from source | Run assembleDebug, install app-debug.apk, then complete setup. |
| Prepare public release | Create local signing files, build release APK, then follow docs/RELEASE_GUIDE.md. |
Real kiosk security requires Device Owner + Lock Task Mode. Immersive mode, fullscreen UI, screen pinning, or hiding Android navigation is NOT enough.
Development builds may show this warning:
Development fallback: kiosk security is not active.
Device Owner: no
Lock Task permitted: no
That means Android can still show notifications, launcher, gestures, and system UI. It is expected until the device is provisioned as Device Owner.
No public release APK is attached yet. When releases start, download the latest APK from the GitHub Releases page and install it on the target Android device.
For local development builds:
adb install -r app\build\outputs\apk\debug\app-debug.apkOn first launch, enter:
- HTTPS page URL, for example
https://example.com. - Administrator PIN.
- PIN confirmation.
After saving setup, the app stores the URL and PBKDF2 PIN material in private app data, then starts the configured kiosk web page.
To reset setup on an unmanaged development install:
adb shell pm clear com.fetchin.kiosk.debugOn a Device Owner device, Android may block normal app data clearing or uninstall flows. If the administrator PIN is forgotten, you may need to remove Device Owner or factory reset the tablet.
Requirements:
| Tool | Version |
|---|---|
| JDK | 17 |
| Gradle wrapper | 9.6.1, included |
| Android Gradle Plugin | 9.2.1 |
| Compile SDK | 36 |
| Minimum SDK | 26 |
Build debug APK:
.\gradlew.bat assembleDebug --console=plainRun unit tests:
.\gradlew.bat testDebugUnitTest --console=plainRun lint:
.\gradlew.bat lintDebug --console=plainDevice Owner provisioning usually requires a clean factory-reset device with no personal account configured.
Debug build component:
adb shell dpm set-device-owner com.fetchin.kiosk.debug/com.fetchin.kiosk.admin.KioskDeviceAdminReceiverRelease build component:
adb shell dpm set-device-owner com.fetchin.kiosk/com.fetchin.kiosk.admin.KioskDeviceAdminReceiverLaunch debug build:
adb shell am start -n com.fetchin.kiosk.debug/com.fetchin.kiosk.MainActivityVerify Lock Task:
adb shell dumpsys activity activities | findstr /C:"mLockTaskModeState" /C:"mLockTaskPackages"Expected provisioned state:
mLockTaskModeState=LOCKED
u0:[com.fetchin.kiosk.debug]
The Android emulator can validate the basic Device Owner and Lock Task flow, but final confidence still requires target hardware.
Useful emulator flow:
adb install -r app\build\outputs\apk\debug\app-debug.apk
adb shell dpm set-device-owner com.fetchin.kiosk.debug/com.fetchin.kiosk.admin.KioskDeviceAdminReceiver
adb shell am start -n com.fetchin.kiosk.debug/com.fetchin.kiosk.MainActivity
adb shell dumpsys activity activities | findstr /C:"mLockTaskModeState" /C:"mLockTaskPackages"If set-device-owner fails because accounts exist, wipe the AVD and retry before adding any account.
Important emulator caveat: adb shell input KEYCODE_HOME is shell-injected input and can bypass behavior that a normal physical user cannot. Do not treat that as final kiosk escape validation.
| Situation | Recovery |
|---|---|
| Wrong URL during development | Clear app data or reinstall. |
| Forgotten PIN on unmanaged install | Clear app data or reinstall. |
| Forgotten PIN on Device Owner tablet | Remove Device Owner if possible, or factory reset. |
| Need to update APK | Use adb install -r during development; use controlled release process for production. |
| Package | Responsibility |
|---|---|
config |
First-run setup, local config, runtime AppConfig. |
web |
WebView settings, navigation policy, load/error handling. |
kiosk |
Device Owner status and Lock Task control. |
admin |
Hidden gesture, Device Admin receiver, PIN verifier. |
ui |
UI state model. |
security |
Safe event logging boundary. |
Detailed docs:
AGENTS.mdgoverns future agents and project rules.docs/ARCHITECTURE.mdexplains structure and flow.docs/SECURITY_MODEL.mddocuments threats and mitigations.docs/DEVICE_PROVISIONING.mdlists ADB provisioning commands.docs/RELEASE_GUIDE.mddescribes APK release preparation.docs/PROJECT_STATUS.mdtracks current validation state.
- First-run setup supports one configured URL host and true subdomains. Extra sibling API/CDN hosts need future setup UI if required.
- Real target tablet validation is still required.
- WebView renderer recovery needs real tablet validation.
- No MDM/EMM, QR provisioning, printing, camera, downloads, or file uploads yet.
- GitHub APK publishing is not configured yet.
Read AGENTS.md before changing code. Security-sensitive behavior must stay synchronized with docs/SECURITY_MODEL.md and docs/ARCHITECTURE.md.
Before handing off changes, run or document why you could not run:
.\gradlew.bat assembleDebug --console=plain
.\gradlew.bat testDebugUnitTest --console=plain
.\gradlew.bat lintDebug --console=plain