#!/usr/bin/env bash # Pinch e2e test harness for the Pad emulator (aosp_atd AVD). # # The platform-signed touch.inject app (real MotionEvents through # InputManager — the only multi-touch path that works in the emulator) # drives the renderer's pinch probe; each gesture below is ONE script in # ONE process (the injector's finger map is per-process). # # KNOWN FLAKES (both verified, both handled below): # 1. The injector process is "cached" while its script thread runs and the # 1.5 GB emulator OOM-kills it mid-script occasionally — the script # never reaches "=== done". ti() checks logcat for the done line and # re-runs (a re-run starts a fresh gesture; a stuck pointer from a # half-run is replaced by the next ACTION_DOWN). # 2. The app is on-demand-rendering at ~1 fps: a burst of moves within # one frame's drain does not scroll (single-frame delta pattern). # Scroll tests therefore space the moves >= 40 ms apart — which is # also what a real finger produces over several frames. # # READING RESULTS: AppFontScale in the session file is the reliable pinch # signal. Scroll in the session is NOT (the restore re-derives it from the # pinned line anchor); for scroll tests compare the before/after # screenshots instead. SER=emulator-5554 export ANDROID_SERIAL=$SER ti() { local script="$1" for attempt in 1 2 3; do adb logcat -c 2>/dev/null adb shell 'am broadcast -n "touch.inject/.Injector$ScriptReceiver" --es script "'"$script"'"' >/dev/null 2>&1 sleep 4 if adb shell logcat -d 2>/dev/null | grep -aq "TouchInject: === done"; then return 0 fi echo " (injection incomplete, attempt $attempt — retrying)" done echo " !! injection failed after 3 attempts" return 1 } # ensure Pad is in the foreground (the ATD launcher intermittently holds # focus after a cold start; a backgrounded app receives no touch) fg() { for i in 1 2 3 4 5; do FOC=$(adb shell 'dumpsys window | grep mCurrentFocus') case "$FOC" in *pad.pad*) return 0;; esac adb shell am start -n pad.pad/org.gioui.GioActivity >/dev/null 2>&1 sleep 8 done echo " !! Pad never gained focus: $FOC" return 1 } dbg() { adb shell "echo '$1' > /sdcard/PadPerf/cmd"; sleep 1.5; } shot() { adb exec-out screencap -p > "$1"; } # force-stop (flushes the session), print it, relaunch + reopen the file measure() { adb shell am force-stop pad.pad sleep 4 echo "session: $(adb shell cat /sdcard/Pad/session.json 2>/dev/null)" adb shell am start -n pad.pad/org.gioui.GioActivity >/dev/null 2>&1 sleep 4 } case "$1" in t1) # single-finger scroll must NEVER change the font (device regression) echo "=== T1: single-finger scroll (font must not change) ===" fg || exit 1 shot /tmp/t1_before.png S="down 1 720 1400 wait 80" for y in 1320 1240 1160 1080 1000 920 840 760 680 600 520 440 360 280 200; do S="$S move 1 720 $y wait 40" done S="$S wait 100 up 1" ti "$S" sleep 2 shot /tmp/t1_after.png # compare to before: content moved, same font size measure ;; t2) # two-finger pinch-out: font must scale, center anchored echo "=== T2: two-finger pinch-out (font must grow) ===" fg || exit 1 shot /tmp/t2_before.png S="down 1 570 1200 wait 40 down 2 870 1200 wait 60" for i in 1 2 3 4 5 6 7 8; do x1=$((570 - i*37)); x2=$((870 + i*37)) S="$S move 1 $x1 1200 move 2 $x2 1200 wait 50" done S="$S wait 150 up 1 up 2" ti "$S" sleep 1 shot /tmp/t2_after.png measure ;; t3) # palm-first: the resting finger lands FIRST, the pinch pair is the # two that move — the palm must never enter the distance echo "=== T3: palm-first three fingers (pinch pair = the two movers) ===" fg || exit 1 shot /tmp/t3_before.png S="down 1 720 400 wait 100 down 2 570 1200 wait 60 down 3 870 1200 wait 150" for i in 1 2 3 4 5 6 7 8; do x2=$((570 - i*37)); x3=$((870 + i*37)) S="$S move 2 $x2 1200 move 3 $x3 1200 wait 50" done S="$S wait 150 up 2 up 3 wait 50 up 1" ti "$S" sleep 1 shot /tmp/t3_after.png measure ;; t4) # lift one finger mid-pinch: survivor must SCROLL, not zoom echo "=== T4: lift finger mid-pinch (survivor scrolls, no more zoom) ===" fg || exit 1 shot /tmp/t4_before.png S="down 1 570 1200 wait 40 down 2 870 1200 wait 60 move 1 533 1200 move 2 907 1200 wait 80 up 2 wait 80" for y in 1280 1360 1440 1520 1600 1680 1760 1840 1920 2000; do S="$S move 1 533 $y wait 40" # survivor (finger 1) keeps its own x done S="$S wait 100 up 1" ti "$S" sleep 1 shot /tmp/t4_after.png # compare to before: content scrolled, font frozen measure ;; reset) # back to a known state (one command per file — no pipes) dbg "fontsize 1"; dbg "top" ;; *) echo "usage: $0 t1|t2|t3|t4|reset" ;; esac