Skip to content

POS Android

POS Android is the handheld client for mobile retail operations.

It is not the primary supermarket checkout client. Use it for:

  • handheld cashier
  • small merchants
  • queue-busting
  • supervisor approvals
  • mobile inventory-adjacent flows
  • generic Bluetooth, permission-bound USB-host printer-class and private-LAN raw-TCP ESC/POS receipt testing, external HID keyboard-wedge scanning, configurable foreground scanner broadcasts, offline camera barcode scanning, and future integrated-printer adapters

Current Responsibilities

  • barcode scan and basket building
  • item image confirmation after scan
  • customer lookup and loyalty redemption
  • mixed tender capture
  • receipt view and reprint
  • authenticated creation and opening of a signed public digital receipt link after server synchronization
  • shift control
  • offline-first local state with later sync

Offline Position

Android is the offline-first POS client in the product family.

  • local Room storage
  • cached catalog and item images
  • local sale queue
  • deterministic dependency-ordered sync and replay when connectivity returns
  • exact-body-signed batches of up to 50 offline-safe shift, sale, cash and refund mutations, with per-item outcomes and stable idempotency keys
  • a manager-gated refund return tray that selects original sale items, derives the partial amount from their remaining quantities, and can return only those quantities to stock
  • stale-job recovery, capped transient retries, and a blocked state for permanent conflicts
  • terminal-scoped manager retry/discard decisions consumed from a sanitized server queue; Room v15 preserves conflict metadata without storing raw server bodies or secrets
  • durable marked-reprint jobs with explicit operator retry after Bluetooth reconnect or permission repair
  • rapid external HID scan capture that rejects normal slow keyboard typing
  • exact action/category/extra-key scan-intent capture that requires a valid test scan before reporting integrated-scanner readiness
  • permission-on-use CameraX analysis with a bundled on-device ML Kit decoder and no image persistence or first-run model download
  • real battery, network, printer and scanner-readiness heartbeats at enrollment and periodic sync

Sales can remain offline, but supervisor-controlled actions cannot. Android sends the POS-specific supervisor PIN only to the authenticated POS API, never stores a PIN hash, and fails closed if the service is unavailable. This deliberately prevents a stolen or rooted handheld from brute-forcing a cached four-digit hash.

Customer-app prompt cancellation is also online-only. Android sends the pending tender UUID through the enrolled terminal request-proof contract, reloads the provider-authoritative sale, and keeps the tender captured if the customer paid before cancellation. It never queues an offline cancellation or offers the action for a provider that lacks a safe cancellation adapter. Room v16 persists the selected customer-app adapter's advertised cancellation operation with a false-by-default, data-preserving migration, so an older install never guesses support from the generic WALLET tender name.

Receipt Printer Foundation

The app now isolates printing behind a ReceiptPrinter interface. Generic Bluetooth Classic SPP, USB printer-class bulk OUT and private-LAN raw-TCP adapters emit a conservative ESC/POS stream with selectable 58 mm/32-column and 80 mm/48-column profiles, explicit reprint marking, bounded payload length, and control-character filtering. Room v12 retains print status, attempt count, safe failure guidance, printer identity, and printed time. This software path is verified by unit tests and debug/release builds; physical YCP-58, Ciontek, Sunmi, paper-out, reconnect, and Unicode/code-page behavior still require the hardware pilot.

Authoritative Close-of-Day Pack

After a supervisor closes and submits a shift, Android can retrieve its country-neutral server close pack. The client validates the current signing-key id/public key, exact canonical-payload SHA-256, detached Ed25519 signature, pack version, and store/terminal/session binding before showing it as verified. Room v14 preserves the canonical payload plus signature evidence and verification time for offline review. Device-generated CSV/PDF reports remain provisional working papers and are never presented as the authoritative finance record.

Printer readiness is based on actual configuration and a transport-specific probe: Android permission, Bluetooth state and bonded-device visibility for SPP; temporary device permission plus a successful USB-interface claim for USB; or a bounded connection to a private resolved address for raw TCP. A printer-driven drawer test is disabled by default, emits one bounded ESC/POS pulse and never enters the at-least-once print spool. Automatic cash-sale and cash-refund opening is a separate setting: it remains disabled until that one-shot pulse succeeds and the operator physically confirms that the exact drawer opened. Room v18 inserts an audit row before hardware I/O, uses a SHA-256 business-event digest to suppress duplicates, records confirmed, sent-unconfirmed, failed, or crash-ambiguous outcomes, and never replays a drawer action. A supervisor no-sale is online-only: the cashier submits a reason and supervisor credential, the server binds the approved override to the same organization, store, terminal, open shift, cashier, and SUPERVISOR_NO_SALE action for five minutes, then records an immutable zero-value NO_SALE cash movement before Android attempts one drawer pulse. The authorization is single-use and the movement/pulse identities are idempotent. If drawer automation is not physically qualified, the server audit still succeeds and Android sends no pulse. Scanner readiness is true only for an attached HID scanner, a scan-intent adapter that has received a valid scan, or a camera with runtime permission that has successfully decoded a valid barcode in the current process. Merely having a camera or saving an intent profile does not count. Integrated printer SDKs and physical drawer qualification remain hardware/pilot work.

Room v17 caches authoritative refund headers and line allocations. This lets the handheld subtract already completed return quantities after reconnect, hide a second request while provider reconciliation is active, and generate a new retry-stable idempotency key for each cumulative partial refund. Drawer expectation changes use the server-reported cash-tender refund delta rather than assuming every refund was paid entirely in cash.

Hardware-backed terminal enrollment

New Android enrollments generate the terminal signing key with a server-derived, domain-separated attestation challenge and send the leaf-first DER certificate chain with the existing proof-of-possession request. Exact activation retries reuse the same pre-enrollment key; a new activation rotates only an unbound pre-enrollment key. An already bound terminal is never silently rotated.

The locally persisted binding is reconciled against the authenticated bootstrap after every successful sign-in and during the 15-minute WorkManager cycle. A server-revoked terminal, or one no longer present in the operator's authoritative merchant/store view, is marked inactive locally without deleting offline transaction history. Re-enrollment can then create a fresh attested key and terminal identity. Matching a lane or terminal code is never enough to adopt a replacement device: once issued, the opaque server terminal UUID is the binding identity.

The POS service verifies evidence on the server. A verified result requires the submitted terminal key to match the attested leaf, a valid chain to one of the configured Android attestation roots, a fresh successful revocation lookup, the expected activation challenge, TEE or StrongBox security levels, signing purpose with SHA-256, generated-key origin, locked verified boot, and the configured Android package and signing-certificate digest. The certificate chain is not stored; only status, security level, trust-anchor hash, and verification time are retained.

Rollout modes are DISABLED, AUDIT, and REQUIRED_ANDROID_HARDWARE. Test defaults to AUDIT, which never labels unverified evidence as trusted. Required mode fails closed and refuses to start without an Android signing-certificate digest. Web terminals and vendor HARDWARE_POS devices remain outside Android enforcement so future vendor attestation adapters can use the same country-neutral boundary.

When to Use Android Instead of Cashier Web

Use Android when the lane is not a fixed supermarket counter:

  • mobile checkout
  • aisle or queue-busting checkout
  • supervisor device
  • branch manager backup terminal
  • smaller merchants without a countertop POS station

Design Rule

Do not force supermarkets to use handheld terminals as their primary cashier interface. Countertop lanes belong to POS Cashier Web; Android remains the mobile companion.