Re-render shared QR/barcodes on the Unihertz Titan 2 subscreen.
Share to Verso from any app:
- image (JPEG/PNG/screenshot) — scanned with ML Kit
- PDF — every page scanned (cap 20 pages)
.pkpass—pass.json→barcodes[]- text/URL — encoded as QR. Google Wallet save URLs get the JWT decoded; if it has an inline barcode it's used, otherwise the URL itself is encoded.
Formats: QR, Aztec, PDF417, Data Matrix, Code 128/39/93, Codabar, EAN-13/8, ITF, UPC-A/E.
Settings → Subscreen Settings → preferred apps → add Verso. Then back screen → MORE APPS → tap Verso once. The app shows these steps on first run with a button into Subscreen Settings.
Share → toast "N codes ready" → tap Verso on the back.
Gestures on the back:
- tap / swipe left: next (older)
- swipe right: previous (newer)
- long-press: remove this / remove all
- subscreen's own swipe leaves the app
Ring buffer keeps the 25 most recent.
keytool -genkeypair -keystore release.jks -storepass password -keypass password \
-keyalg RSA -keysize 2048 -validity 36500 -alias verso -dname "CN=Verso"
./gradlew :app:assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk
AGP 8.9.1, JDK 17, minSdk 24, targetSdk 36. Deps: appcompat, material, ml-kit barcode-scanning, zxing core.
- Wallet share URLs for already-saved passes carry only a
classId/idreference; resolving requires Wallet API auth. Screenshot the pass instead. .pkpasssignature isn't checked. Whatever's in the file is what gets shown.- A malicious payload in shared QR is re-rendered faithfully. Verso doesn't filter content.
ShareReceiverActivity (share target, never directly visible) → CodeCache (disk ring buffer) → DisplayActivity (LAUNCHER, gestures, display). CodeRenderer wraps zxing for re-encoding. WalletExtractor and PkPassExtractor handle the structured-input formats. Onboarding is the first-run dialog.
Apache 2.0. See LICENSE.