Matt Van HornandMatt Van Horn f3424b716d fix: Import cloud-backed PKPASS files off the main thread (#3282)
* fix: Import cloud-backed PKPASS files off the main thread

Fixes #2464

* Address review: move all import parsing off the main thread, restore failure toasts

- Route image/PDF/pkpass/espass imports through one background importFile
- Restore errorReadingFile / errorReadingImage / noBarcodeFound toasts via a
  main-looper-marshalling showToast helper
- Replace fixed-timeout awaits in the activity tests with a waitFor predicate

* Start the import coroutine on the main dispatcher, hop to IO for the read

launch(Dispatchers.IO) starts the coroutine on a background thread immediately,
so a paused Robolectric main looper never drives it and the activity tests time
out. Launch on the lifecycle scope's default (main) dispatcher and wrap only the
blocking read in withContext(Dispatchers.IO).

* Fix the two failing import tests

Two separate bugs, both in the tests I added:

- new Intent(ACTION_VIEW, uri).setType(...) clears the data URI (setType and
  setData clear each other), so the activity received a null Uri and the read
  never started. Use setDataAndType.
- The intermediate-state assertions (no started activity / RESULT_CANCELED)
  are not observable: waiting on the main looper drains it, and Robolectric
  drains it again during .visible(), so the import has already run to
  completion by the time the test regains control. Assert the off-main-thread
  read directly instead, which is the property these tests exist to prove.

* fix: make showToast reusable with a caller-supplied duration

Take the toast length as a parameter instead of hardcoding LENGTH_LONG, so
the helper can serve short toasts too, and document why it exists: it shows
the toast directly when already on the main looper and otherwise posts it
there, which is what the off-main-thread import path needs.

Reorders the modifiers to the file's `static private` convention.

All existing call sites pass LENGTH_LONG, so behavior is unchanged.

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-09-05 12:31:04 +02:00
2026-08-28 17:09:28 +02:00
2026-08-28 17:09:28 +02:00
2026-08-11 22:06:01 +02:00

Catima

Copylefted libre software (GPLv3+) card management app for Android 6.0 and up.

GitHub Version GitHub Wear OS Version IzzyOnDroid Version F-Droid Version Google Play Store Version

Reproducibility status

Android CI Translation status

Matrix

Get it on IzzyOnDroid Get it on F-Droid Get it on Obtainium Get it on Google Play

Feature graphic

Stores your store loyalty and membership cards on your device, instead of having to carry them around.

Supported barcodes:

  • AZTEC
  • CODABAR
  • CODE_39
  • CODE_93
  • CODE_128
  • DATA_MATRIX
  • EAN_8
  • EAN_13
  • ITF
  • PDF_417
  • QR_CODE
  • UPC_A
  • UPC_E

Works fully offline, supports pkpass ("Add to Apple Wallet") files and select smartwatches through Gadgetbridge and Wear OS companion app.

Screenshots

Core app

Wear OS companion app

Moving data from other apps

Within the app you can import cards and codes from files, Catima, FidMe, Loyalty Card Keychain and Voucher Vault. For FidMe you need to select the barcode type for each entry afterwards.

Building

Building can either be done through Android Studio (not reproducible!) or the build.sh script in this repository (reproducible with OpenJDK 21). This script can also sign the build.

Build without signing:

./build.sh

Build with signing:

KEYSTORE=/path/to/keystore KEYSTORE_ALIAS=catima ./build.sh

Translating

Translation status

Help translate the app to your language from our Hosted Weblate page.

Special thanks

This app is based on the great (but no longer developed) Loyalty Card Keychain by Branden Archer.

Logo and feature graphic contributed by il-Luca and Aeven-Dev, based on the original logo by Rose (TangentFoxy) and original feature graphic by Ziad OUALHADJ.

S
Description
No description provided
Readme GPL-3.0
54 MiB
0 Stars 1 Watchers 0 Forks
Languages
Java 67.6%
Kotlin 30.8%
Shell 0.9%
Python 0.6%