Dragon Guard Handheld unifies barcode scanning and UHF RFID reading under a single, mode-aware service contract. Every view model that needs scan data subscribes to one interface —Documentation Index
Fetch the complete documentation index at: https://mintlify.com/CodexaCP/DG_APK/llms.txt
Use this file to discover all available pages before exploring further.
IScanCaptureService — and never touches hardware directly. Switching between a plain barcode gun, a single-tag RFID read, a continuous inventory sweep, or a combined Hybrid session is a one-line async call. The two concrete adapters that sit beneath the service (KeyboardWedgeScanAdapter and VendorRfidScanAdapter) handle the physical layer in isolation, keeping all Android-specific broadcast wiring away from shared business logic.
Scan Modes
TheScanMode enum controls which physical channel is active and how results are routed.
| Value | Int | Description |
|---|---|---|
Barcode | 0 | Keyboard-wedge barcode only. RFID hardware is not activated. |
RfidSingle | 1 | Android RFID hardware reads one tag, then the session self-terminates. |
RfidInventory | 2 | Continuous UHF sweep. Session runs until StopSessionAsync is called or the policy MaxReadsPerOperation cap is hit. |
Hybrid | 3 | Both channels active. Barcode input and RFID tags both surface through their respective events. |
IScanCaptureService Interface
IScanCaptureService is the sole scanning contract consumed by view models and other services. It is registered as a singleton in the DI container.
Because
IScanCaptureService is a singleton, event subscriptions persist across navigation. Always unsubscribe handlers in OnDisappearing (or equivalent) to avoid duplicate callbacks and memory leaks.Properties
| Property | Type | Description |
|---|---|---|
CurrentMode | ScanMode | The active scan mode set by the most recent SetModeAsync or StartSessionAsync call. |
IsSessionActive | bool | true while a scan session is running. Updated by adapter events. |
CanUseRfid | bool | Set by ApplyRfidPolicy. Gates all RFID session starts. |
CanOperateWithoutRfid | bool | When true and RFID is unavailable, StartSessionAsync downgrades to Barcode mode instead of blocking. Default: true. |
RfidHardwareStatus | string | Human-readable hardware status token. Initial value: "NO_RFID_PROFILE". Other values: READY, RFID_NOT_SUPPORTED, RFID_DISABLED_BY_POLICY, DEVICE_NOT_AUTHORIZED. |
Methods
InitializeAsync(CancellationToken)
Initializes the underlying hardware adapter. On Android, registers the ScanBroadcastReceiver for RFID broadcast intents, configures the RFID output mode to EPC bank (mode 0), suppresses the trailing Enter/Tab keystroke the wedge otherwise injects, and subscribes to AndroidKeyboardWedge trigger events. Calling this more than once is safe — the adapter short-circuits if already initialized.
SetModeAsync(ScanMode, CancellationToken)
Updates CurrentMode and propagates the new mode down to the vendor adapter. Does not start or stop a session.
StartSessionAsync(ScanSessionRequest, CancellationToken)
Starts a capture session for the mode specified in ScanSessionRequest. Contains RFID policy enforcement:
Barcodemode — marks the session active immediately and firesSessionStartedwithout involving the RFID hardware.- RFID/Hybrid mode,
CanUseRfid = false,CanOperateWithoutRfid = true— firesErrorOccurredwith a degradation message, then starts a barcode-only session automatically. - RFID/Hybrid mode,
CanUseRfid = false,CanOperateWithoutRfid = false— firesErrorOccurredand does not start a session. - RFID/Hybrid mode,
CanUseRfid = true— delegates toVendorRfidScanAdapter.StartSessionAsyncon Android.
StopSessionAsync(CancellationToken)
Stops the active session. For Barcode mode this is purely in-memory. For RFID/Hybrid modes on Android it sends STOP_BARCODE_RFID to the system ScanService and restores the physical trigger binding to the 2D barcode decoder.
HandleKeyboardInputAsync(string?, CancellationToken)
Feeds a string from a keyboard-wedge scanner into the KeyboardWedgeScanAdapter. Only processes input when CurrentMode is Barcode or Hybrid. On a valid non-whitespace value it creates a ScanResult with ScanType = "BARCODE" and Symbology = "KEYBOARD_WEDGE", then raises CodeScanned.
ApplyRfidPolicy(bool, bool, string)
Stores the three RFID capability flags derived from RfidHandheldContextDto. Call this once after fetching the handheld context before starting any RFID session.
Events
| Event | Args type | Raised by |
|---|---|---|
CodeScanned | CodeScannedEventArgs | Keyboard-wedge barcode reads (Barcode or Hybrid mode). Carries Result (ScanResult). |
TagObserved | TagObservedEventArgs | Each distinct EPC emitted by the RFID adapter. Carries Result (ScanResult). |
SessionStarted | ScanSessionEventArgs | When a session becomes active. IsActive = true. Also carries Mode (ScanMode) and Message (human-readable status string). |
SessionStopped | ScanSessionEventArgs | When a session ends (manual stop, single-read auto-stop, or policy cap). IsActive = false. Also carries Mode and Message. |
TriggerStateChanged | TriggerStateChangedEventArgs | Physical trigger key pressed (IsPressed = true) or released (IsPressed = false). Also carries Mode (ScanMode) showing which mode was active when the trigger fired. Android only. |
ErrorOccurred | ScanErrorEventArgs | RFID unavailability, adapter failures, or policy blocking. Carries Message (string) and optional Exception (Exception?). |
ScanResult Record
Every scan event delivers a ScanResult instance via its EventArgs.
| Field | Notes |
|---|---|
Id | Unique per read. Use for deduplication in UI lists. |
ScanType | "BARCODE" for wedge reads, "RFID" for UHF reads. |
Mode | The ScanMode active when the read occurred. |
RawValue | Unmodified data from the hardware. |
NormalizedValue | Trimmed; RFID values are additionally upper-cased. |
Epc | Set for RFID results. Not the same as ItemNo — use GET /api/rfid/tags/resolve/{epc} to map it. |
Barcode | Set for keyboard-wedge results. |
Symbology | "KEYBOARD_WEDGE" for wedge scans; "com.rscja.scanner.uhf" for UHF. |
Rssi | Signal strength in dBm. Null for barcode reads. Use DisplayRssi for safe rendering. |
Antenna | Antenna identifier from the RFID hardware. May be null. |
SeenCount | Number of times the same tag has been observed in the current session (deduplication counter). |
DeviceId | Handheld device identifier when provided by the adapter. |
MetadataJson | Reserved for vendor-specific extra fields. |
DisplayValue | Returns Epc if set, otherwise NormalizedValue. Safe for all display bindings. |
DisplayRssi | Returns the RSSI integer as a string, or "-" when unavailable. |
ScanSessionRequest Record
Reason is a free-text label that appears in session event messages and aids log correlation. Pass the module or screen name (e.g. "Item Inquiry", "Sandbox").
Scan Adapters
The service composes two adapters. Both are instantiated insideScanCaptureService — they are not registered in DI directly.
KeyboardWedgeScanAdapter
Handles barcode input delivered as keyboard characters by USB/Bluetooth scanner guns. Wraps raw string input in a
ScanResult with ScanType = "BARCODE" and Symbology = "KEYBOARD_WEDGE". Active in Barcode and Hybrid modes. Platform-agnostic — works on all targets.VendorRfidScanAdapter
Android-only (
#if ANDROID). Integrates the CHAINWAY C72 (RSCJA) UHF module via the system ScanService broadcast API. Binds physical trigger keys (keycodes 139, 293, 294) for pistol-style operation. Reads EPC bank (mode 0). Supports single-shot and continuous inventory with configurable deduplication windows and per-session read caps from RfidEffectivePolicyContextDto.Vendor RFID SDK
The RFID adapter is backed by the vendor AAR binding at:ScanService (com.rscja.scanner). Direct DeviceAPI / JNI init() calls return -1 at runtime because ScanService already holds the serial port (/dev/ttyS1). The integration therefore uses the ScanService broadcast API exclusively:
| Intent Action | Purpose |
|---|---|
ENABLE_FUNCTION_BARCODE_RFID (function=11) | Enables the UHF thread (RFID_UHF=true) in ScanService. Also re-sent at the start of every StartSessionAsync call to re-arm the UHF module if InfoWedge has flipped RFID_UHF back to false since InitializeAsync. |
START_BARCODE_RFID (function=11) | Begins a UHF inventory read. Also sent on every physical trigger-press while a session is active. |
STOP_BARCODE_RFID (function=11) | Stops the UHF inventory. Also sent on trigger-release in RfidInventory mode (pauses continuous reads without ending the session). |
SCAN_RESULT_BROADCAST_RFID | Routes RFID results to the app’s broadcast receiver. Configured once in InitializeAsync with resultAction = com.rscja.scanner.action.scanner.RFID and data = "data". |
UHF_MODE (mode=0) | Selects EPC bank output. Mode 0 = EPC (default); mode 1 = TID. Set once in InitializeAsync. |
CONTINUOUS_SCAN_RFID (isContinuous) | Sets single-shot (isContinuous=false) vs. continuous (true) mode. Sent on each StartSessionAsync. |
CONTINUOUS_SCAN_INTERVAL_TIME_RFID (intervalTime=300) | Sets the inter-read interval to 300 ms for continuous inventory sessions. Not sent for RfidSingle. |
SCAN_KEY_CONFIG_BARCODE_RFID | Binds or unbinds physical trigger keys (keycodes 139, 293, 294) to a function module. Set to function=11 (UHF) on session start, restored to function=2 (2D barcode soft-decode) on session stop. |
ENABLE_ENTER_BARCODE_RFID (enter=false) | Suppresses the trailing Enter keystroke the wedge injects after each read. Set once in InitializeAsync to prevent the Enter from activating the focused mode picker in the MAUI UI. |
ENABLE_TAB_BARCODE_RFID (tab=false) | Suppresses the trailing Tab keystroke. Set once in InitializeAsync alongside ENABLE_ENTER_BARCODE_RFID. |
com.rscja.scanner.action.scanner.RFID broadcast and the keyboard wedge (keycode 293 with buffered EPC characters). VendorRfidScanAdapter listens on both and deduplicates via the policy window.
AndroidKeyboardWedge
AndroidKeyboardWedge is a static helper that MainActivity.DispatchKeyEvent calls for every key event. While an RFID session is active (IsSessionActive = true), it buffers the hex characters the wedge emits and fires EpcScanned when keycode 293 arrives, and fires TriggerPressed/TriggerReleased for the physical scan button. All events are logged to logcat tag RFID_WEDGE for ADB diagnostics.
Scan Event Args
TheScanEvents.cs types are shared by both adapters and all consumers of IScanCaptureService.
RfidHandheldContextService
RfidHandheldContextService is a singleton that caches the per-module RFID context returned by GET /api/rfid/handheld/context across navigations. Once a module’s context is fetched it is held in memory until ClearCache() is called explicitly.
RfidHandheldContextService cannot be registered via AddHttpClient<T> because that helper always registers the client class as Transient, which would lose the in-memory module cache on every injection. Instead, MauiProgram registers a named HttpClient ("rfid-handheld-context") and resolves it through IHttpClientFactory to construct the singleton manually:GetContextAsync returns RfidHandheldContextDto.Fallback(module) — a safe context with CanUseRfid = false, CanOperateWithoutRfid = true, and both barcode and manual fallbacks allowed. This ensures the handheld never blocks the operator due to a context fetch failure.
Debug Sandbox
RfidSandboxPage (backed by RfidSandboxViewModel) is a debug-only screen for testing SDK initialization and EPC reads in isolation. It:
- Exposes all four
ScanModevalues for selection. - Calls
InitializeAsync,StartSessionAsync, andStopSessionAsyncthrough the productionIScanCaptureService. - Displays resolved item results (calls
ItemService.ResolveRfidTagAsyncfor each EPC) and a live read count. - Forces
ApplyRfidPolicy(canUseRfid: true, canOperateWithoutRfid: false, "SANDBOX")so RFID errors surface instead of silently falling back. - Exposes
LastErrorandSessionStatusbindings for on-screen diagnostics.