All checks were successful
APK-BUILD/pipeline/head This commit looks good
Scanners in "Intent output" mode deliver barcodes via broadcast, which nothing in the app received, so scans never reached any field. Add BroadcastScannerIntegration (Urovo, Newland and other common actions, configurable in AppConfig) and inject the text into the focused field, or the first visible search/text field, using the native value setter plus an input event so React-controlled inputs accept it. Optionally sends Enter afterwards (SCANNER_SEND_ENTER). Add a logging-only dispatchKeyEvent pass-through to diagnose why keystroke-mode scans don't reach the orders search field. Ignore SamplePage/ and update README and CLAUDE.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.5 KiB
3.5 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, gesture thresholds (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_TAP_COUNT/ADMIN_TAP_WINDOW_MS— hidden admin exit gesture (7 taps top-left corner)
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 exit: 7 rapid taps in top-left 60dp corner → confirmation dialog (PIN-ready stub)
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.