JoykooSmartApp/CLAUDE.md
caspar 2f88432776
All checks were successful
APK-BUILD/pipeline/head This commit looks good
Add intent-output scanner support and key event logging
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>
2026-10-08 12:39:16 -04:00

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:

  1. NoSoftKeyboardWebView.onCheckIsTextEditor() → false
  2. EditorInfo flags IME_FLAG_NO_EXTRACT_UI | IME_FLAG_NO_FULLSCREEN in onCreateInputConnection()
  3. InputMethodManager.hideSoftInputFromWindow() posted after each InputConnection request and on page load / window focus
  4. JavaScript injection setting inputmode="none" on all <input>, <textarea>, and contenteditable elements via MutationObserver
  5. 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)

  1. sudo dnf install java-17-openjdk-devel — only the JRE is installed, need javac
  2. Android SDK cmdline-tools — download to ~/Android/Sdk/, then install:
    • platform-tools
    • platforms;android-34
    • build-tools;34.0.0
  3. 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
    
  4. ./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 load
  • ALLOWED_HOSTS — domains that stay inside the WebView
  • BACK_PRESS_EXIT_COUNT / BACK_PRESS_WINDOW_MS — back-button exit guard
  • ADMIN_TAP_COUNT / ADMIN_TAP_WINDOW_MS — hidden admin exit gesture (7 taps top-left corner)

Navigation Rules

  • URLs on joykoo.mx or smart.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.