Implementation rule
Treat ScanManager as a hardware resource with an explicit owner. Open it, select the intended output mode, register the decode receiver, validate every payload, then unregister and close deterministically. Confirm method behavior on the production-intent sample.
Prepare a reproducible SDK baseline
Package the approved SDK artifact through the controlled developer-download process. Record its version and SHA-256 alongside the application build and device record.
Keep vendor APIs behind a scanner adapter so business logic can be unit tested without hardware and another capture implementation can be substituted.
- Approved SDK source only
- Artifact hash recorded
- Adapter boundary defined
- Device matrix created
Own the scanner lifecycle once
The API reference documents openScanner, closeScanner, startDecode, stopDecode and output-mode functions. Decide whether the activity, a foreground service or another application-scoped component owns those calls.
Avoid multiple screens opening the scanner independently. Make stop and close safe to repeat and surface failed return values in diagnostic state without logging barcode payloads.
- Single resource owner
- Idempotent cleanup
- Return values observed
- No payloads in ordinary logs
Validate the broadcast payload
A successful decode broadcast can include raw data, a decoded string, length and barcode type. Check action, nullability and length before delivering a domain event.
Choose one authoritative representation. If encoding matters, preserve raw bytes and decode under an explicit charset instead of assuming every barcode is simple ASCII.
- Action exactly matches
- Length consistent with payload
- Encoding policy documented
- Duplicate event guard
Move from demo to production evidence
Compile success proves only source compatibility. Run the application on each intended model, OS and firmware with representative labels and lifecycle scenarios.
Record scanner settings and the output mode after configuration. Regression-test after firmware, SDK, application or MDM policy changes.
- Representative scan corpus
- Sleep and resume cycles
- Rapid and long-code cases
- Versioned test record
ScanManager lifecycle state map
Keep resource calls aligned with observable application state.
| State | Required action | Failure response |
|---|---|---|
| Starting | Create ScanManager and open scanner | Block capture and show diagnostic state |
| Ready | Set output mode and register receiver | Read back or report configuration failure |
| Capturing | Start decode or accept trigger events | Timeout, stop and allow controlled retry |
| Paused | Stop decode and unregister as designed | Prevent delivery to inactive workflow |
| Destroyed | Close scanner once | Record cleanup result without sensitive data |
Minimal lifecycle-aware Kotlin example
Verify output-mode constants, Android receiver flags and lifecycle ownership against the exact SDK, target API and application architecture.
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.device.ScanManager
import androidx.appcompat.app.AppCompatActivity
class UrovoScannerActivity : AppCompatActivity() {
private val scanner = ScanManager()
private var receiverRegistered = false
private val decodeReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != ScanManager.ACTION_DECODE) return
val raw = intent.getByteArrayExtra(ScanManager.DECODE_DATA_TAG) ?: return
val declaredLength = intent.getIntExtra(ScanManager.BARCODE_LENGTH_TAG, raw.size)
val type = intent.getByteExtra(ScanManager.BARCODE_TYPE_TAG, 0)
val value = intent.getStringExtra(ScanManager.BARCODE_STRING_TAG)
?: raw.copyOf(declaredLength.coerceIn(0, raw.size)).toString(Charsets.UTF_8)
onValidatedScan(value, type)
}
}
override fun onStart() {
super.onStart()
check(scanner.openScanner()) { "Scanner could not be opened" }
// Confirm the broadcast-output constant in the SDK version you ship.
check(scanner.switchOutputMode(0)) { "Output mode could not be set" }
registerReceiver(decodeReceiver, IntentFilter(ScanManager.ACTION_DECODE))
receiverRegistered = true
}
override fun onStop() {
scanner.stopDecode()
if (receiverRegistered) unregisterReceiver(decodeReceiver)
receiverRegistered = false
scanner.closeScanner()
super.onStop()
}
private fun onValidatedScan(value: String, type: Byte) {
// Route a sanitized domain event; do not log sensitive barcode values.
}
}ScanManager validation checklist
Attach this record to the approved application and device baseline.
- 01
SDK version and SHA-256 recorded
- 02
Device SKU, OS and firmware recorded
- 03
Scanner opens and closes repeatedly
- 04
Output mode read or confirmed
- 05
Receiver lifecycle matches active UI
- 06
Raw, string, length and type extras checked
- 07
All required symbologies tested
- 08
Long, damaged and rapid scans tested
- 09
Sleep, reboot and MDM kiosk mode tested
- 10
No sensitive barcode data logged
Frequently asked questions
What does switchOutputMode(0) mean?
The API reference documents output-mode switching, but constants and behavior must be checked in the exact SDK release and device firmware. Do not copy the sample constant into production without verification.
Should the scanner close in onPause or onStop?
Choose lifecycle ownership based on the application architecture and whether scanning may continue when partially obscured. The important requirement is one owner, deterministic cleanup and tested behavior.
Can this sample be used on every UROVO device?
No. It is a validation blueprint based on ScanManager v4.1.0326. Compile and run it on each intended model, OS and firmware before release.
Evidence and limitations
SDK-reference-backed sample / not validated on every target configuration
The code is illustrative and deliberately calls out version-specific constants and Android receiver policy for verification.
Reviewed: 2026-08-10
- UROVO Android SDK v4.1.0326 ScanManager API reference
- UROVO ScanManager sample project in approved SDK export
- Android application and broadcast receiver lifecycle documentation

