Pad/tools/touchinject/build.sh
Greg Pomerantz 180fa966c8 Pinch-to-font-size (continuous, content-point pinned) + IME-open scroll fix
Two feature bodies accumulated in the working tree:

1. Pinch to change the app font size, continuously (no snapping):
   - internal/ui/pinch_tracker.go: logic-free touch state machine.
     Two-mover formation (the resting palm can land first or last;
     movement is the only signal valid for both), pair = the mover
     pair whose distance changed most, baseline = press distance
     (formDist), lazy pending releases, survivor-scroll forwarding
     after a pair break. Robust to ~1 fps frames: a whole pinch can
     land in one drain (formDist/brokeFactor/lazy releases).
   - render.go: pinch probe (raw pointer events) + grab lifecycle so
     the pair is exclusive (scroll sees nothing of the pair) and the
     survivor's finger keeps working as a scroll after the pinch.
   - state.go/logic.go/session.go/frame.go: app-local float font
     scale, content-point pin (buffer byte + offset from baseline,
     not a layout point, so rewrap keeps the same character under
     the center), restore/font pins, session persistence.
   - pinch_test.go, pinch_font_test.go, tag_identity_test.go,
     real_draw_probe_test.go: unit + real-Renderer/real-Router tests.

2. Soft keyboard must not shift content:
   - Root cause: gioui.org/app calls Router.RevealFocus on any frame
     the viewport shrinks (IME open under adjustResize) and
     synthesizes a pointer.Scroll nudge aimed at the focused field's
     stale pre-resize bounds; gesture.Scroll consumed it -> a 32 dp
     content jump.
   - Fix: main.go flags the shrink frame; render.go drains that one
     synthetic scroll for the gesture's tag before Update (scroll-
     range clamping cannot work: the router UNIONs ranges across
     frames). Finger scroll (pointer.Drag) and the flinger are
     untouched. reveal_focus_drain_test.go reproduces RevealFocus at
     the router level and verifies the drain + zero delta.

Also: tools/touchinject (platform-signed emulator multi-touch
injection harness + e2e script, adb has no two-finger input),
docs (spec 2.2 + development_plan 18-20), .gitignore, gofmt.
2026-08-23 09:00:51 -04:00

49 lines
2.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Builds touchinject.apk (a privileged multi-touch gesture injector) from
# Injector.java using the local Android SDK. The APK must be installed under
# /system/priv-app for the INJECT_EVENTS (signature|privileged) permission to
# be granted — see the bottom of this file.
set -euo pipefail
cd "$(dirname "$0")"
SDK=/home/gmp/android-sdk
BT="$SDK/build-tools/35.0.0"
PLAT="$SDK/platforms/android-35/android.jar"
rm -rf build
mkdir -p build/classes
javac -nowarn -source 1.8 -target 1.8 -classpath "$PLAT" -d build/classes Injector.java
"$BT/d8" --release --min-api 24 --lib "$PLAT" --output build build/classes/touch/inject/*.class
# aapt2 resolves the android: namespace against the framework resource
# table, which is shipped inside android.jar (resources.arsc).
"$BT/aapt2" link --manifest AndroidManifest.xml -I "$PLAT" \
--min-sdk-version 24 --target-sdk-version 35 -o build/base.apk
cp build/base.apk build/touchinject-unsigned.apk
jar uf build/touchinject-unsigned.apk -C build classes.dex
if [ ! -f build/ts.jks ]; then
keytool -genkeypair -keystore build/ts.jks -storepass android -keypass android \
-alias ts -dname "CN=TouchInject, OU=Dev" -keyalg RSA -keysize 2048 -validity 10000
fi
"$BT/apksigner" sign --ks build/ts.jks --ks-pass pass:android --key-pass pass:android \
--out touchinject.apk build/touchinject-unsigned.apk
"$BT/apksigner" verify --print-certs touchinject.apk | head -1
echo "=== DONE: $(pwd)/touchinject.apk"
# --- Install as a privileged system app (emulator, rooted) ---------------
# SER=emulator-5554
# adb -s $SER root && adb -s $SER remount
# adb -s $SER shell mkdir -p /system/priv-app/TouchInject
# adb -s $SER push touchinject.apk /system/priv-app/TouchInject/TouchInject.apk
# adb -s $SER shell chmod 644 /system/priv-app/TouchInject/TouchInject.apk
# adb -s $SER reboot # permission grant is evaluated at install/boot
# adb -s $SER wait-for-device && adb -s $SER shell 'while [ -z $(getprop sys.boot_completed) ]; do sleep 1; done'
# adb -s $SER shell dumpsys package touch.inject | grep -A2 INJECT_EVENTS # granted=true
#
# --- Inject a gesture ------------------------------------------------------
# adb -s $SER shell am startservice -n touch.inject/.Injector \
# -e script "down 1 400 1000 wait 100 down 2 700 1200 wait 100 \
# move 1 380 980 move 2 720 1220 wait 50 \
# move 1 340 940 move 2 760 1260 wait 50 up 1 up 2"
# adb -s $SER logcat -d -s TouchInject