#!/usr/bin/env bash # GUI-oriented Android smoke (vanilla level): deep-link entry + UI taps. # # Entry shortcut (legitimate — same as scanning a QR on the landing): # adb VIEW taler://withdraw/… and taler://pay… # Then drives the **graphical UI** via uiautomator dump + taps (Confirm / ToS / Pay). # # Systems: STACK=goa | stage | auto # APK: published F-Droid or APK_PATH=… (from-source) # # See AUTOMATED-GUI-NOTES.md # set -euo pipefail ROOT=$(cd "$(dirname "$0")" && pwd) # shellcheck source=run-android-pay-smoke.sh # We re-use install/URI resolution by calling common pieces inline. export OUT_DIR="${OUT_DIR:-$ROOT/out-gui}" export GUI_ROUNDS="${GUI_ROUNDS:-10}" export GUI_SLEEP="${GUI_SLEEP:-3}" # Install + deliver intents via existing smoke, but skip its weak single-tap # by setting GUI_MODE=1 which we implement here more fully. # Simpler: do install/URI here by sourcing patterns from pay-smoke via env + python. # Delegate install + URI start to pay-smoke with GUI_AFTER=1 if we patch it; # instead run a self-contained flow calling pay-smoke pieces. APK_DIR="${APK_DIR:-$ROOT/apks}" APK_URL="${APK_URL:-https://f-droid.org/repo/net.taler.wallet.fdroid_854.apk}" APK_NAME="${APK_NAME:-net.taler.wallet.fdroid_854.apk}" APK_PATH="${APK_PATH:-}" PKG="${PKG:-net.taler.wallet.fdroid}" STACK="${STACK:-auto}" SERIAL="${SERIAL:-}" mkdir -p "$OUT_DIR" if ! command -v adb >/dev/null 2>&1; then [ -x "$HOME/Android/Sdk/platform-tools/adb" ] && export PATH="$HOME/Android/Sdk/platform-tools:$PATH" fi command -v adb >/dev/null || { echo "adb missing" >&2; exit 2; } if [ -z "$SERIAL" ]; then SERIAL=$(adb devices | awk '/\tdevice$/{print $1; exit}') fi [ -n "$SERIAL" ] || { echo "no adb device" >&2; exit 3; } ADB=(adb -s "$SERIAL") echo "device: $SERIAL mode: GUI (uiautomator)" case "$STACK" in auto) if curl -sfS -m 5 -o /dev/null https://bank.hacktivism.ch/config; then STACK=goa; else STACK=stage; fi ;; esac case "$STACK" in goa) BANK=https://bank.hacktivism.ch MERCHANT=https://taler.hacktivism.ch WITHDRAW_JSON="$BANK/intro/demo-withdraw.json" ;; stage) BANK=https://stage.bank.lefrancpaysan.ch MERCHANT=https://stage.monnaie.lefrancpaysan.ch WITHDRAW_JSON="$BANK/intro/demo-withdraw.json" ;; *) echo "unknown STACK" >&2; exit 2 ;; esac echo "stack: $STACK" if [ -n "$APK_PATH" ] && [ -f "$APK_PATH" ]; then : elif [ -f "$APK_DIR/$APK_NAME" ]; then APK_PATH="$APK_DIR/$APK_NAME" else APK_PATH="$APK_DIR/$APK_NAME" mkdir -p "$APK_DIR" curl -fL --retry 3 -o "$APK_PATH" "$APK_URL" fi echo "apk: $APK_PATH pkg: $PKG" "${ADB[@]}" wait-for-device "${ADB[@]}" install -r "$APK_PATH" "${ADB[@]}" shell settings put global window_animation_scale 0 || true "${ADB[@]}" shell settings put global transition_animation_scale 0 || true "${ADB[@]}" shell settings put global animator_duration_scale 0 || true WURI=$(curl -sfS -m 25 "$WITHDRAW_JSON" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d.get("taler_withdraw_uri") or d.get("qr_payload") or "")') [ -n "$WURI" ] || { echo "no withdraw uri" >&2; exit 4; } echo "withdraw: $WURI" echo "$WURI" >"$OUT_DIR/last-withdraw.uri" "${ADB[@]}" shell am force-stop "$PKG" 2>/dev/null || true "${ADB[@]}" logcat -c 2>/dev/null || true # --- Shortcut A: deep-link withdraw (≡ QR scan on landing) --- "${ADB[@]}" shell am start -a android.intent.action.VIEW -d "$WURI" | tee "$OUT_DIR/start-withdraw.txt" sleep 5 # --- Graphical: drive UI --- python3 - "$ROOT/lib_ui.py" "$SERIAL" "$OUT_DIR" "$GUI_ROUNDS" "$GUI_SLEEP" <<'PY' import json, sys, importlib.util from pathlib import Path lib_path, serial, out, rounds, sleep_s = ( Path(sys.argv[1]), sys.argv[2], Path(sys.argv[3]), int(sys.argv[4]), float(sys.argv[5]) ) spec = importlib.util.spec_from_file_location("lib_ui", lib_path) lib = importlib.util.module_from_spec(spec) spec.loader.exec_module(lib) st = lib.gui_drive(serial, out / "gui-withdraw", rounds=rounds, sleep_s=sleep_s, phase="wd") (out / "gui-withdraw-status.json").write_text(json.dumps(st, indent=2)) print("gui-withdraw taps:", st.get("taps")) print("gui-withdraw anr:", st.get("anr_dismissals")) PY # Pay URI PAY_URI="" if [ "$STACK" = "stage" ]; then if RESP=$(curl -sfS -m 20 -X POST -H 'Content-Type: application/json' -d '{}' \ "$MERCHANT/instances/fermes-des-collines/templates/panier-legumes" 2>/dev/null); then PAY_URI=$(printf '%s' "$RESP" | python3 -c 'import json,sys;d=json.load(sys.stdin);oid=d.get("order_id")or"";tok=d.get("token")or""; print("taler://pay/stage.monnaie.lefrancpaysan.ch/instances/fermes-des-collines/%s/?c=%s"%(oid,tok) if oid and tok else "")') fi else PAY_URI="taler://pay-template/taler.hacktivism.ch/instances/goa-shop/paivana" fi if [ -n "$PAY_URI" ]; then echo "pay: $PAY_URI" echo "$PAY_URI" >"$OUT_DIR/last-pay.uri" # Shortcut B: deep-link pay (≡ scan pay QR / open paywall link) "${ADB[@]}" shell am start -a android.intent.action.VIEW -d "$PAY_URI" | tee "$OUT_DIR/start-pay.txt" sleep 5 python3 - "$ROOT/lib_ui.py" "$SERIAL" "$OUT_DIR" "$GUI_ROUNDS" "$GUI_SLEEP" <<'PY' import json, sys, importlib.util from pathlib import Path lib_path, serial, out, rounds, sleep_s = ( Path(sys.argv[1]), sys.argv[2], Path(sys.argv[3]), int(sys.argv[4]), float(sys.argv[5]) ) spec = importlib.util.spec_from_file_location("lib_ui", lib_path) lib = importlib.util.module_from_spec(spec) spec.loader.exec_module(lib) st = lib.gui_drive(serial, out / "gui-pay", rounds=rounds, sleep_s=sleep_s, phase="pay") (out / "gui-pay-status.json").write_text(json.dumps(st, indent=2)) print("gui-pay taps:", st.get("taps")) print("gui-pay anr:", st.get("anr_dismissals")) PY fi "${ADB[@]}" logcat -d -t 400 >"$OUT_DIR/logcat.txt" || true grep -iE 'taler-wallet|prepareBank|preparePay|confirm|Error|success' "$OUT_DIR/logcat.txt" \ | tail -100 >"$OUT_DIR/logcat-taler.txt" || true echo echo "=== GUI smoke summary ($STACK) ===" echo "package: $PKG" echo "shortcut withdraw URI: delivered" echo "GUI withdraw: see $OUT_DIR/gui-withdraw-status.json + screenshots" [ -n "$PAY_URI" ] && echo "shortcut pay URI: delivered" [ -n "$PAY_URI" ] && echo "GUI pay: see $OUT_DIR/gui-pay-status.json + screenshots" if grep -q prepareBankIntegratedWithdrawal "$OUT_DIR/logcat.txt" 2>/dev/null; then echo "wallet-core: prepareBankIntegratedWithdrawal YES" else echo "wallet-core: prepareBankIntegratedWithdrawal no (ANR/slow UI?)" fi if grep -qiE 'preparePay|confirmPay|pay-template|preparePurchase' "$OUT_DIR/logcat.txt" 2>/dev/null; then echo "wallet-core: pay path YES" else echo "wallet-core: pay path not confirmed in logcat" fi echo "artifacts: $OUT_DIR/" ls -la "$OUT_DIR" | sed 's/^/ /' echo "Documented shortcuts → AUTOMATED-GUI-NOTES.md"