18 KiB
GUI automation notes (Android wallet)
Companion docs:
- CLI / wallet-cli:
../CLI-AUTOMATION-NOTES.md - Git / tags / suite tree:
../VERSIONS.md
Canonical notes for graphical Android wallet tests against GOA / stage.
Minimal variant (implemented first) — status 2026-07
This is the minimal vanilla path we actually shipped; full dual-platform GUI is planned via flags (below), not required to use these scripts today.
| Piece | Status | Notes |
|---|---|---|
| F-Droid published APK install | done | net.taler.wallet.fdroid 1.6.1 / 854 |
| Source build + same smoke | done | :wallet:assembleFdroidDebug → net.taler.wallet.fdroid.debug |
| Default source branch | done | dev/hernani-inference/fix-bank-withdraw-auto-exchange (minimal GOA exchange auto-add) |
| Deep-link entry (≡ QR) | done | adb VIEW withdraw then pay (taler://withdraw/… → taler://pay…) |
| Explorer API mint (chain) | done | run-goa-gui-chain.sh (GOA + stage) |
| UI taps via uiautomator | done | best-effort Confirm/ToS/Pay; ANR → prefer Wait |
| Screenshots / logcat artifacts | done | under out*, out-gui-chain/ (gitignored) |
| Host CLI e2e settlement | separate | taler-monitoring.sh e2e / ladder (not Android UI) |
| Reliable unattended Confirm on 4 GiB Linux host | limited | System UI ANR; use phone or more RAM |
| iOS GUI | not in this tree | see taler-ios dev/hernani-inference/gui-workflows |
| macOS full dual AVD helpers | upstream | taler-android gui-workflows (Homebrew); ported ideas here for Linux |
Ground rule: bring it to run; app diffs only if needed and minimal; prefer
extending existing dev/hernani-inference/* branches over new trees.
Minimalvariante: was geht / was nicht
Einschränkungen der aktuell implementierten Minimalvariante (deep-link + uiautomator best-effort). Kein voller Dual-Platform-GUI-Stack, kein Ersatz für Host-CLI-Settlement.
Geht (grün)
| Fähigkeit | Wie / Hinweis |
|---|---|
| APK installieren | F-Droid net.taler.wallet.fdroid oder Source assembleFdroidDebug (.debug) |
| GOA-Exchange ohne manuelles Add | Source-Build von fix-bank-withdraw-auto-exchange (Default in run-android-build-and-smoke.sh) |
| Abheben + Bezahlen | Beide Beine: erst Withdraw-URI + Taps, dann Pay-URI + Taps (DO_WITHDRAW/DO_PAY) |
| Light UI-Drive | Confirm / Accept / Pay-Taps über Label-Suche (lib_ui.py, gui-smoke, chain) |
| Multi-Runden-Taps | run-android-gui-smoke.sh / run-goa-gui-chain.sh (best-effort) |
| Explorer-Mint (Kette) | run-goa-gui-chain.sh + EXP_PW_FILE (GOA + stage) |
| Stack-Wahl | STACK=goa / stage (Bank/Merchant-URLs) |
| Artefakte | Screenshots, UI-XML, logcat unter out* / out-gui-chain/ (gitignored) |
| Hybrid-Smoke | Install + Intent + leichte Taps: run-android-pay-smoke.sh |
| Settlement nachweisen | Host-seitig: taler-monitoring.sh e2e / ladder (nicht Android-UI) |
| Flags abschalten | AUTO_ANDROID=0 skip; AUTO_GUI=0 → nur deep-link/pay-smoke |
Geht nicht oder nur eingeschränkt (rot / gelb)
| Beschränkung | Folge / Workaround |
|---|---|
| Unattended Confirm → settled im Emulator (~4 GiB Host) | Häufig System UI ANR; Taps bleiben hängen. Prefer Wait auf ANR-Dialog, echtes Gerät, oder Host mit mehr RAM. Kein zuverlässiges grünes E2E nur über GUI auf dem schwachen Emulator. |
| Vollständige Wallet-Settlement-Assertion in der GUI | Minimalvariante prüft nicht „Balance final / transfer_done“ in der App-Oberfläche. Proof bleibt CLI/e2e. |
| Kamera / physischer QR-Scan | Absichtlich nicht automatisiert; deep-link ist der Shortcut. Landing-QR-Pfade sind HTTP-Thema, nicht Android-GUI. |
| Browser-Shop-Checkout-UI | Kein Chromium/WebView-Drive; Pay-URI kommt per Template-POST + Intent. |
| Volles ToS-Scroll / alle Dialoge | Best-effort Accept-Tap; lange ToS oder unerwartete Sheets können hängen bleiben. |
| Published F-Droid allein auf GOA | Kann Exchange-Add / Spinner-Probleme zeigen → fix-branch-APK bauen; bei Spinner-Hang optional fix-withdraw-spinner-fallback. |
| iOS-GUI | Nicht in diesem Tree; siehe taler-ios gui-workflows. |
| macOS dual AVD / Homebrew-Helpers | Upstream gui-workflows; hier nur Linux-taugliche Port-Ideen. |
AUTO_* in jedem Script erzwungen |
Design + teilweise verdrahtet; Wrapper-Checkliste noch offen. |
run-until-done / CLI-Wallet in GUI-Skripten |
Gehört zu CLI-Automation, nicht GUI; siehe CLI-AUTOMATION-NOTES.md. |
| CI grün = „User hat bezahlt“ | Smoke = Intent + best-effort UI. Wirtschaftlicher Erfolg = Host-e2e / ladder / Explorer. |
Erwartetes Ergebnis pro Schicht
| Schicht | Erfolgskriterium Minimalvariante |
|---|---|
| A Install | APK installed, App startet |
| B Deep-link | Intent delivered, Wallet öffnet Withdraw/Pay-Flow |
| C GUI taps | Dump+Tap ohne Crash; ANR ggf. mit Wait; kein Garant für „Paid“ |
| D Evidence | Artefakte geschrieben |
| Settlement | Außerhalb GUI: Host e2e/ladder |
Wann Minimalvariante reicht
- Smoke nach APK-/Branch-Build (Intent kommt an, App crasht nicht).
- Manuelle Nacharbeit am Gerät nach vorbereiteten URIs.
- GOA/stage Erreichbarkeit von Landing/Template + Wallet-Einstieg.
Wann nicht reicht → nächster Schritt
- Unattended grünes Pay-E2E auf dem Emulator → mehr RAM / physisches Gerät, ggf.
fix-withdraw-spinner-fallback. - Beweis „Münzen da / Merchant paid“ → CLI e2e/ladder, nicht GUI-smoke.
- iOS / Dual-Platform → andere Repos/Flags, nicht diese Skripte.
cd scripts/taler-monitoring/android-test
# Minimal hybrid (install + deep-link + light taps)
STACK=goa ./run-android-pay-smoke.sh
# GUI multi-round taps
STACK=goa ./run-android-gui-smoke.sh
STACK=stage ./run-android-gui-smoke.sh
# Explorer mint + multi withdraw/pay chain (from gui-workflows)
EXP_PW_FILE=$HOME/src/koopa/koopa-admin-secrets/koopa/host-root/taler-bank/bank-explorer-password.txt \
STACK=goa PKG=net.taler.wallet.fdroid.debug \
./run-goa-gui-chain.sh
# Build fix-branch APK then smoke (GUI=1 for gui smoke)
./run-android-build-and-smoke.sh
GUI=1 ./run-android-build-and-smoke.sh
Platform capability flags (planned + defaults)
Automation can run on hosts that support Android only, GUI tooling only (conceptual), or both. Flags keep that explicit for CI and laptops.
Proposed env flags
| Variable | Values | Meaning |
|---|---|---|
AUTO_ANDROID |
0 / 1 |
Run Android wallet automation (adb, APK, emulator/device) |
AUTO_GUI |
0 / 1 |
Drive graphical UI (uiautomator taps, multi-round). If 0, deep-link/CLI-only install smoke. |
AUTO_PLATFORM |
auto / linux / macos / ios |
Host family (optional override) |
EMULATOR_HEADLESS |
1 (default) / 0 |
No host window (-no-window). Server/CI-safe. |
WINDOWED |
0 / 1 |
Shortcut: WINDOWED=1 ⇒ show emulator window (EMULATOR_HEADLESS=0) |
EMULATOR_GPU |
default swiftshader_indirect |
Guest GLES still runs headless (layout/taps/screenshots). Override host only if windowed + real GPU. |
AUTO_START_EMULATOR |
1 (default) / 0 |
If no adb device, start AVD via start-android-emulator.sh --wait |
Headless mode (default)
Default for all GUI / pay smokes: no window on the host. Opening an emulator
GUI on servers (or headless CI) is wrong; these scripts therefore start the AVD
with -no-window and still keep graphics logic in the guest:
| Piece | Headless default |
|---|---|
| Host window | off (-no-window, QT_QPA_PLATFORM=offscreen, no DISPLAY) |
| Guest GLES | on via SwiftShader (-gpu swiftshader_indirect) |
| UI automation | on — uiautomator dump/tap + screencap (no X11 needed) |
| Audio / boot anim | off (-no-audio -no-boot-anim) |
# explicit (same as default)
./start-android-emulator.sh --wait
# or let smoke auto-start headless AVD when no phone is plugged in
STACK=goa ./run-android-gui-smoke.sh
# laptop: show the emulator window
WINDOWED=1 ./start-android-emulator.sh --wait
# or: EMULATOR_HEADLESS=0 EMULATOR_GPU=host ./start-android-emulator.sh --wait
Shared code: lib_android_env.sh + start-android-emulator.sh.
Semantics:
AUTO_ANDROID |
AUTO_GUI |
Behaviour |
|---|---|---|
1 |
0 |
Android install + deep-link smoke only (no multi-round taps) |
1 |
1 |
Android + graphical drive (vanilla GUI / chain) |
0 |
1 |
Reserved (e.g. future desktop/web GUI); currently no-op with a clear message |
0 |
0 |
Skip mobile automation |
Defaults by host (when flags unset)
Host (uname -s) |
Default AUTO_ANDROID |
Default AUTO_GUI |
Rationale |
|---|---|---|---|
| Linux | 1 |
1 if device/emulator present, else scripts exit 3 |
This repo’s day-to-day path; Android only (no iOS here) |
| Darwin (macOS) | 1 |
1 |
Can run Android emulators and (separately) taler-ios GUI helpers; both flags on for Android scripts; iOS is out of tree |
| Other | 0 |
0 |
Fail closed |
Linux default = Android (no second mobile platform in this suite).
macOS may enable both ecosystems in the wider monorepo sense; for these
scripts only Android is implemented — set AUTO_ANDROID=1 (default) and keep
iOS under taler-ios.
Resolution helper (convention for future wrappers)
# Example for a future run-all-mobile.sh
os=$(uname -s)
: "${AUTO_PLATFORM:=auto}"
case "$AUTO_PLATFORM" in
auto) case "$os" in Linux) AUTO_PLATFORM=linux ;; Darwin) AUTO_PLATFORM=macos ;; *) AUTO_PLATFORM=other ;; esac ;;
esac
case "$AUTO_PLATFORM" in
linux)
: "${AUTO_ANDROID:=1}"
: "${AUTO_GUI:=1}"
# no iOS
;;
macos)
: "${AUTO_ANDROID:=1}"
: "${AUTO_GUI:=1}"
# optional later: AUTO_IOS=1 for taler-ios scripts
;;
*)
: "${AUTO_ANDROID:=0}"
: "${AUTO_GUI:=0}"
;;
esac
Scripts today implement Android only; they should honour:
AUTO_ANDROID=0→ exit 0 with “skipped (AUTO_ANDROID=0)”AUTO_GUI=0→ call deep-link smoke without multi-round GUI (or setGUI_ROUNDS=0)
Vanilla layers (detail)
| Layer | What | Tooling |
|---|---|---|
| A — Install | F-Droid or from-source APK | adb install |
| B — Entry (shortcut) | taler://withdraw/… / taler://pay… |
adb am start -a VIEW |
| C — Graphical UI | Confirm / ToS / Pay taps; ANR Wait | uiautomator + lib_ui.py / chain |
| D — Evidence | Screenshots, XML, logcat, URIs | out*/ |
Legitimate shortcuts
| Shortcut | Replaces |
|---|---|
| Deep-link withdraw/pay | Camera QR / opening paywall |
Host POST template → pay URI |
Browser shop checkout UI |
| Label-list taps | Human reading button text |
| Skip full ToS scroll | Tap Accept if shown |
Scripts
| Script | Role |
|---|---|
run-android-pay-smoke.sh |
Hybrid: install + deep-link + light taps |
run-android-gui-smoke.sh |
Multi-round GUI drive |
run-goa-gui-chain.sh |
Multi mint/withdraw/pay (gui-workflows port) |
run-android-build-and-smoke.sh |
Build git ref (branch/tag) + smoke (GUI=1 optional) |
run-android-variant-matrix.sh |
published + stable-self + master (compare builds) |
start-android-emulator.sh |
Start AVD (headless default, SwiftShader) |
lib_android_env.sh |
Flags, PATH, android_ensure_device |
lib_ui.py |
Dump/tap/ANR helpers |
Build variants (anti–“weird local build”)
| Variant | Source | Severity | Purpose |
|---|---|---|---|
| stable-self | only rebuild of current stable tag | WARN | Self-build vs published for one release |
| published | F-Droid current APK | ≤14d → BLOCKER, else WARN | What users install |
| older / milestones | F-Droid APK ~3 / 6 / 9 / 12 mo | always WARN | No self-build of old tags |
| master | origin/master rebuild |
WARN | Tip — never hard-blocks |
| fix (optional) | inference branch | soft | GOA automation fixes |
Self-build: current stable only (plus master/fix if requested) — not older releases.
Blocker window: releases ≤ 14 days.
Milestones: nearest tags to 90/180/270/365d with a still-hosted F-Droid APK.
Stacks under test
| Stack | Withdraw | Pay |
|---|---|---|
| GOA | explorer mint / demo-withdraw.json @ bank.hacktivism.ch |
goa-shop templates / Paivana pay-template |
| stage | explorer / demo-withdraw @ stage.bank… | fermes / jardin public templates |
Lageübersicht GOA + stage (as-is survey · 2026-07-17 ~22:05–22:18)
Device: headless emulator-5554 · host ~3.7 GiB RAM (often <300 MiB free) · timeout per leg ≤420 s.
Legs: Abheben + Bezahlen (DO_WITHDRAW=1 DO_PAY=1). Artefakte: out-survey-20260717-220527/ (gitignored).
Varianten
| Variante | Quelle | Bemerkung |
|---|---|---|
| stable (published) | F-Droid net.taler.wallet.fdroid 1.6.1 / 854 |
as-is |
| master as-is | rebuild origin/master @ f65a976c → .fdroid.debug |
as-is, no patches |
| ältere Releases (3/6/9/12 mon) | F-Droid APKs für 1.5.0/1.3.0/1.1.0/1.0.8 |
nicht auffindbar (HTTP miss) → SKIP (kein Selbstbau älterer Tags) |
| master + inference (extra) | local branch local/master-with-inference @ 3ebe8b09 |
merges fix-bank-withdraw-auto-exchange + fix-withdraw-spinner-fallback · not pushed |
Ergebnis-Matrix
| Variant | Stack | Install / deep-link | Withdraw URI | Pay URI | wallet-core Abheben | wallet-core Pay | ANR | Exit |
|---|---|---|---|---|---|---|---|---|
| stable published | goa (hacktivism) | OK | OK bank.hacktivism.ch | OK paivana template | NO | soft/YES once* | YES | 10 |
| stable published | stage (*.lefrancpaysan) | OK | OK stage.bank… | OK fermes order | NO | NO | YES | 10 |
| master as-is | goa | OK | OK | OK paivana | NO | NO | YES | 10 |
| master as-is | stage | OK | OK | OK fermes | NO | NO | YES | 10 |
| master+inference | goa | OK | OK | OK | NO | NO | YES | 10 |
| master+inference | stage | OK | OK | OK | NO | NO | YES | 10 |
*stable-goa console once reported pay wallet-core YES mid-run; final score still ANR-dominated / not reliable settlement.
Was pro Stack steht (Infra)
| Check | goa / hacktivism | stage / *.lefrancpaysan |
|---|---|---|
Bank …/intro/demo-withdraw.json → taler://withdraw/… |
OK | OK |
| Pay entry | paivana pay-template OK |
fermes panier-legumes POST → taler://pay/… OK |
adb VIEW Intent delivery |
OK | OK |
| Unattended Confirm/Abheben/Pay GUI | FAIL (ANR) | FAIL (ANR) |
| wallet-core prepare/accept withdraw in logcat | not seen | not seen |
Fazit as-is: Beide Stacks liefern die Eingänge (Withdraw- + Pay-URIs). Die GUI/wallet-core-Strecke ist auf diesem Emulator für alle getesteten App-Varianten (stable, master, inference) gleich tot — System UI / Android System ANR, keine brauchbaren Taps. Das ist kein Stack-Unterschied GOA vs stage und kein belastbarer App-Versions-Vergleich.
Inference-Patch-Versuch (lokal, kein Push)
Weil nichts der as-is-Varianten wallet-core-grün war, wurde zusätzlich gebaut:
taler-android branch: local/master-with-inference # NOT pushed
base: origin/master
merged: origin/dev/hernani-inference/fix-bank-withdraw-auto-exchange
origin/dev/hernani-inference/fix-withdraw-spinner-fallback
commit: 3ebe8b091379
APK: apks/wallet-master-inference-3ebe8b091379.apk (local)
| Stack | Inference smoke | Besser als master/stable? |
|---|---|---|
| goa | exit 10, ANR, no withdraw core | Nein |
| stage | exit 10, ANR, no withdraw core | Nein |
Kein grünes Inference-Signal auf diesem Host → wir können nicht belegen, dass die Patches Withdraw/Pay „retten“.
Ebenso können wir nicht belegen, dass master ohne Patches „schuld“ ist: die Umgebung erreicht wallet-core gar nicht.
Wenn später auf Gerät/mehr RAM die Inference-APK plötzlich grün und master/stable rot ist:
das ist der klare Fix-Hinweis — Patches ausdev/hernani-inference/*upstreamen / in master holen.
Heute: noch nicht der Fall; primärer Blocker = Emulator/RAM/ANR.
Nächste sinnvolle Schritte (später)
- Physisches Gerät oder Host ≥6–8 GiB free RAM
- Nur eine Wallet-Package-ID installiert (kein Open-with)
- Survey wiederholen: stable · master ·
local/master-with-inferenceauf goa + stage - Ältere F-Droid-APKs nur wenn wieder gehostet; kein Selbstbau alter Tags
Upstream branches (taler-android dev/hernani-inference/*)
| Branch | Role |
|---|---|
gui-workflows |
macOS emulator helpers + original goa-chain-emu.sh |
fix/bank-withdraw-auto-exchange |
Minimal GOA exchange auto-add (default build branch) |
fix/withdraw-spinner-fallback |
Spinner + OIM; use if spinner still hangs |
experimental-oim* |
Optional cash UI |
Checklist
- Minimal variant documented
- Minimalvariante: was geht / was nicht (Beschränkungen)
- Two stacks (goa / stage)
- Dual-stack run documented (2026-07-17: both FAIL ANR, landings OK)
- Flags design (
AUTO_ANDROID/AUTO_GUI/ platform defaults) - Headless emulator default (
EMULATOR_HEADLESS=1, SwiftShader) - Linux default = Android suite only
- Inference-branch policy
- Wrapper enforces flags in every entry script (incremental)
- Reliable unattended Confirm on low-RAM Linux emulator