Fixed
-
⌨️ "Return to Start Page on inactivity" fires while typing in a text field (#195): In WebView mode the "Return to Start Page on inactivity" timer is reset by a
user-interactionmessage that page-injected JavaScript posts on user activity. That message was only wired to pointer events (click,scroll,touchstart,touchmove,touchend) — typing with the on-screen keyboard produces keyboard/input events instead, so the timer kept counting down and could return the user to the start page mid-typing. It only appeared on "some fields on some sites" because some inputs incidentally emit touch/scroll events (autocomplete dropdowns, fields that scroll into view) which masked the gap. Fixed by also resetting the timer onkeydown,input, andcompositionupdateevents (capture phase, sharing the existing 200 ms throttle). All three are needed because Android soft keyboards with predictive text firekeydownwithkeyCode 229and often skip per-character key events, whileinput/compositionupdatefire reliably for every character (including IME/autosuggest composition). Same-origin only — inputs inside cross-origin iframes remain unreachable from the injected script, as with every other interaction listener. Reported and fixed by @ShroomKing (#196). -
🔇 Web page audio/video keeps playing in the background and becomes uncontrollable (#177): With a web radio or video playing in WebView mode, the audio could keep going after the screensaver appeared, the screen turned off, or the app was backgrounded — and since FreeKiosk overrides the volume keys in kiosk mode, users (often elderly) had no way to stop it short of force-closing the app. Root cause: react-native-webview's
onHostPause()is a no-op, so the Android WebView never pauses its media when the app is hidden, and FreeKiosk had no media-pause logic of its own; in "Keep Screen On" mode the screensaver is merely an overlay drawn on top of the still-running page, so the audio played on, unreachable underneath. Fixed by pausing the content WebView when the page is hidden: a new nativeKioskModule.pauseWebView()/resumeWebView()calls Android'sWebView.onPause()/onResume()on the main WebView only (resolved by node handle, so the screensaver's own web/video screensaver is never affected), complemented by a JS-level pause of<audio>/<video>elements for reliability across OEM WebViews. Triggered on screensaver activation, screen-off, and app-background; the renderer resumes on return (media stays paused so nothing auto-restarts). Controlled by a new opt-in setting Display → Web Media → "Pause audio/video when hidden" (default on); turn it off to keep web audio playing continuously (e.g. an intentional web-radio dashboard). Reported by @dbee01. -
💥 App crashes during motion detection when the camera view is torn down mid-capture (
ViewNotFoundError, reported on v1.2.19): With motion detection enabled, a periodiccamera.takePhoto()runs in a background coroutine that first resolves the nativeCameraViewby its view tag. If the camera view was unmounted between the call and its resolution (display-mode change, motion detection toggled off, screen teardown),CameraViewModule.findCameraView()threwViewNotFoundError. This is distinct from the cameraless-device init crash fixed in #187: the exception was thrown inside the UI-thread Handler callback ofrunOnUiThreadAndWait()and never routed back to the suspended coroutine, so it escaped as an uncaught exception on the main thread and crashed the whole app — before the existing JStry/catchinMotionDetector(which already expects and swallowsfindCameraViewerrors) could ever see a promise rejection. Fixed in thereact-native-vision-camerapatch with two coordinated changes: (1)runOnUiThreadAndWait()now wraps the call and forwards failures to the coroutine viacontinuation.resumeWith(Result.failure(e))instead of throwing on the Handler thread; (2)CameraViewModule.takePhoto()now callsfindCameraView()inside itswithPromiseblock — necessary because the module'sbackgroundCoroutineScopehas no exception handler, so without this the (now coroutine-level) exception would simply crash on the camera executor thread instead. With both,takePhoto()rejects cleanly and the existing JS handler absorbs it, so motion detection continues uninterrupted. -
💥 App crashes with
IllegalArgumentExceptionwhen a custom User-Agent contains illegal characters (reported on v1.2.19): If the custom User-Agent configured in Display settings contained a character that is illegal in an HTTP header value (e.g. a stray newline or control character from a copy-paste), Chromium'sAwSettings.setUserAgentString()threwIllegalArgumentException— on the Fabric mount thread, so it crashed the whole app and could not be caught from JS. Fixed in thereact-native-webviewpatch by guarding the User-Agent assignment inRNCWebViewManagerImpl: an invalid value is now logged and the WebView falls back to the default User-Agent instead of crashing. -
🔧 ADB config silently ignored when only REST API / MQTT / option extras are provided (#193): The documented
adb shell am start … --es rest_api_enabled "true" --es pin "1234"command did nothing — no toast, no log, nothing applied.handleAdbConfig()bailed out early with a guard that only checked the four "content" extras (lock_package,url,config,mqtt_broker_url), returningfalsebefore it ever read the PIN or any of the ~25 individual option extras (REST API, MQTT,status_bar,back_button_mode,screensaver_enabled,managed_apps, …). So any config that set only those options was discarded. Fixed by treating the intent as an ADB config command when any recognized extra is present, not just the content keys. The previously required--es config '{}'workaround is no longer needed. Reported by @BoussonKarel. -
💥 App crashes on launch with
IllegalArgumentException: Invalid task, not in foregroundwhen starting the kiosk lock task (reported on v1.2.19):MainActivity.onCreate()callscheckAndStartLockTask()→startLockTask(), butstartLockTask()requires the task to be the foreground task at that instant. WhenonCreate()runs while MainActivity is still backgrounded (boot, or the external-app-at-boot path that deliberately moves the task to back), the platform throwsIllegalArgumentException("Invalid task, not in foreground"). In the Device Owner branch this was only wrapped incatch (SecurityException)— andIllegalArgumentExceptionis not aSecurityException, so it escaped and crashed the app on launch. Fixed by routing everystartLockTask()call through a new defensivetryStartLockTask()helper that catches the not-in-foreground failure (IllegalArgumentException/IllegalStateException) instead of crashing, flags the attempt as pending, and retries once the activity actually gains window focus (onWindowFocusChanged(hasFocus = true)— the most reliable foreground signal), so the kiosk lock still engages as soon as the app is genuinely in the foreground. -
💤 Screensaver never activates in External App mode (#190): With a screensaver + inactivity timer configured, the screensaver worked in WebView mode but never triggered once an external app was launched — and on devices with a short system screen timeout the OS locked the screen instead. Root cause: screensaver activation was driven by a JS
setTimeout, but React Native freezes JS timers while the activity is backgrounded — and in External App mode FreeKiosk is backgrounded the whole time behind the launched app, so the timer never fired. Fixed (phase 1) by running the inactivity countdown natively inOverlayService(which already observes every tap via its watch-outside-touch overlay and keeps running in the background): on expiry it emitsinactivityExpiredNative, and FreeKiosk runs the exact same activation path (motion pre-check → bring-to-front → screensaver) it used before. The native timer re-arms on each tap and on screensaver dismissal, and is disarmed during the motion pre-check, while the screensaver is active, and during scheduled sleep so it cannot double-fire. The JS timer still drives WebView/media modes unchanged. By design, External App mode delegates screen on/off to the system (FreeKiosk's "Keep Screen On" override is WebView/media only), so the screensaver only appears before the OS turns the screen off if the Android screen timeout is ≥ the inactivity delay (or "Never"); an info hint explaining this was added to the Screensaver settings section in External App mode. Reported by @elcomandante. -
🔔 Notification panel and status bar stop working after a reboot in multi-app mode (#191): When the notification panel / status bar were enabled, they worked until the device was rebooted, then became unavailable. Root cause: the lock-task features are applied in two stages —
BootLockActivitystarts the lock task at boot withGLOBAL_ACTIONSonly, relying onMainActivity.enableKioskRestrictions()to upgrade toNOTIFICATIONS/SYSTEM_INFOafterwards. In multi-app mode an external app takes the foreground at boot while MainActivity stays backgrounded, so that upgrade was delayed or never applied — the kiosk stayed stuck on the boot-timeGLOBAL_ACTIONS-only state with notifications and status bar disabled. Fixed by havingBootLockActivityread the same settings (@kiosk_allow_notifications,@kiosk_allow_system_info,@kiosk_allow_power_button) and apply the full feature set directly at boot. Also fixed a related bug inAppLauncherModule: it enabledLOCK_TASK_FEATURE_NOTIFICATIONSwithoutLOCK_TASK_FEATURE_HOME, which Android requires together — the missing flag madesetLockTaskFeatures()throw and silently abort the entire feature update when launching an external app. (Note: on some OEM ROMs a separate "background pop-up / display floating window" permission may also need to be granted for the kiosk to relaunch correctly at boot.) Reported by @23575437. -
⌨️ Soft keyboard stays visible when the screensaver activates (#135): In "Keep Screen On" mode the screensaver draws an overlay (dim/URL/video) on top of the page while the screen stays physically on — so
ACTION_SCREEN_OFFnever fires and the screen-off keyboard-dismiss (added in #135 v1.2.19) never ran. The follow-up attempt addedKeyboard.dismiss()at screensaver activation, but that is React Native's API and only closes keyboards owned by RNTextInputs; a keyboard raised by an<input>inside the WebView (e.g. a web login field in Force Numeric mode) was untouched and stayed visible behind the screensaver. Fixed by dismissing the keyboard at the window level viaInputMethodManager.hideSoftInputFromWindow()+clearFocus()(new nativeKioskModule.hideKeyboard()), which closes the keyboard regardless of whether it belongs to a WebView or a RN view. Triggered from auseEffecton screensaver activation so it covers every activation path (inactivity timer, motion pre-check, MQTT/REST screen-off, scheduled sleep). The screen-off path (ScreenStateReceiver) now shares the same helper (KeyboardUtils). Reported by @asfreitas17.