All checks were successful
APK-BUILD/pipeline/head This commit looks good
The 7-tap top-left corner gesture passed every tap through to the page, triggering site UI underneath it. Remove it entirely and open the admin dialog (exit / toggle soft keyboard) by either: - holding Volume Up + Volume Down together for 5 seconds; volume keys are consumed so they never reach the page, or - scanning AppConfig.ADMIN_BARCODE in Intent output mode, which opens the dialog instead of being injected into the page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.7 KiB
3.7 KiB
JoykooScanner — Android Barcode Scanner Kiosk App
What This Is
Native Android app (Kotlin) that wraps https://smart.joykoo.mx/ in a fullscreen WebView for dedicated Chinese industrial handheld barcode scanners. The scanner operates in HID/keyboard-wedge mode — it sends Android key events like a physical keyboard.
Critical Design Decision
The Android soft keyboard must NEVER appear. Keyboard suppression uses multiple layers — do not remove any of them:
NoSoftKeyboardWebView.onCheckIsTextEditor()→falseEditorInfoflagsIME_FLAG_NO_EXTRACT_UI | IME_FLAG_NO_FULLSCREENinonCreateInputConnection()InputMethodManager.hideSoftInputFromWindow()posted after each InputConnection request and on page load / window focus- JavaScript injection setting
inputmode="none"on all<input>,<textarea>, andcontenteditableelements viaMutationObserver - Manifest
windowSoftInputMode="stateAlwaysHidden|adjustNothing"
The real InputConnection from super.onCreateInputConnection() must be returned — returning null breaks hardware key input from the barcode scanner on devices like the Urovo CT58C.
Project Structure
app/src/main/java/mx/joykoo/scanner/
AppConfig.kt — URL, allowed hosts, admin triggers, scanner broadcasts (single config point)
MainActivity.kt — Fullscreen kiosk activity, WebView setup, navigation, lifecycle
NoSoftKeyboardWebView.kt — IME suppression via null InputConnection
ScannerIntegration.kt — Scanner lifecycle interface
BroadcastScannerIntegration.kt — Intent-output scans → JS injection (React-safe value setter)
Build
- Language: Kotlin, targeting JVM 1.8 bytecode
- SDK: compileSdk 34, minSdk 24, targetSdk 34
- Dependencies: androidx core-ktx, appcompat, webkit, swiperefreshlayout
- Gradle: 8.7 with Kotlin DSL, AGP 8.5.2, Kotlin 1.9.24
- Package:
mx.joykoo.scanner
Build prerequisites (not yet installed on this server)
sudo dnf install java-17-openjdk-devel— only the JRE is installed, need javac- Android SDK cmdline-tools — download to
~/Android/Sdk/, then install:platform-toolsplatforms;android-34build-tools;34.0.0
- Set env vars:
JAVA_HOME=/usr/lib/jvm/java-17-openjdk-17.0.20.1.1-1.2.el9.x86_64 ANDROID_HOME=~/Android/Sdk ./gradlew assembleDebug
Server environment (RHEL 9.8)
- JRE 17 installed at
/usr/lib/jvm/java-17-openjdk-17.0.20.1.1-1.2.el9.x86_64 - 323 GB free on /home, 5.5 GB free on /
- curl, wget, unzip, zip available
- No Android SDK present anywhere
Configuration
All configurable values are in AppConfig.kt:
HOME_URL— the webpage to loadALLOWED_HOSTS— domains that stay inside the WebViewBACK_PRESS_EXIT_COUNT/BACK_PRESS_WINDOW_MS— back-button exit guardADMIN_VOLUME_HOLD_MS— hold Volume Up + Volume Down this long to open the admin dialogADMIN_BARCODE— scanning this value (Intent mode) opens the admin dialog
Navigation Rules
- URLs on
joykoo.mxorsmart.joykoo.mx(and subdomains) load inside the WebView - All other URLs are silently blocked
- Back button goes back in WebView history; 3 rapid presses exits when no history
- Admin dialog (exit / toggle soft keyboard): hold both volume keys 5 s, or scan
ADMIN_BARCODE. Volume keys are consumed and never reach the page. No touch gestures — corner taps leaked through to site UI
Security
- HTTPS only, no cleartext, no SSL error bypass
- No JavaScript interfaces exposed
- No file:// or content:// access
- Network security config enforces system trust anchors only
- Domain allowlist in WebViewClient
UI Strings
Spanish (es) — this is for a Mexico-based company.