diff --git a/AGENTS.md b/AGENTS.md index dd86e61f..19d5af0b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -106,16 +106,90 @@ Three product flavours — **github**, **fdroid**, **play** — differ only in t update-check API; **github** is the normal local dev flavour. Debug builds install side-by-side (`applicationIdSuffix ".test"`). -**Connected-device testing:** Always build and install the **github debug** -variant. Update the existing installation in place with `adb install -r` so its -app data, preferences, VPN consent, and test state are preserved. Do not uninstall -the app or run `pm clear` unless the user explicitly requests a clean install. +**Connected-device testing:** build and install the **fdroid debug** variant, +which installs as `net.kollnig.missioncontrol.fdroid.test`. ```bash -./gradlew assembleGithubDebug -adb install -r app/build/outputs/apk/github/debug/TrackerControl-githubDebug-latest.apk +./gradlew assembleFdroidDebug +adb install -r app/build/outputs/apk/fdroid/debug/TrackerControl-fdroidDebug-latest.apk +``` + +Not github debug: that installs as `net.kollnig.missioncontrol.test`, which is +also what a maintainer's own day-to-day dev build installs as. Testing against it +overwrites their real preferences, and enabling its VPN takes the consent slot +from whatever they were running. The flavours differ only in the update-check +API, so nothing is lost by using fdroid for device work. (Working on the +update-check itself is the exception — that needs github, and needs asking +first.) + +**Never destroy state without asking.** `adb uninstall`, `pm clear`, overwriting +a preferences file, revoking a permission — every one of these is irreversible +and the device usually belongs to someone who has real configuration on it. Ask +first, naming the package and what will be lost, and wait for a yes. This applies +even when the target looks like a throwaway you installed yourself: it is one +mistaken package name away from wiping the real install. Update in place with +`adb install -r`, which preserves app data, preferences, VPN consent, and test +state, and for cleanup reset only the specific state your test touched. + +One more side effect worth announcing before you trigger it: enabling the VPN +calls `VpnService.prepare()`, which **revokes whatever VPN app currently holds +consent** — the maintainer's own build, or their real VPN. It will need +re-enabling afterwards. + +### Driving the app without permission popups + +Onboarding, the VPN consent dialog and the runtime permission prompts can all be +pre-satisfied from adb, so an agent never has to tap through them. + +```bash +PKG=net.kollnig.missioncontrol.fdroid.test + +# 1. Runtime permissions. -g grants everything the manifest declares, so revoke +# whichever one you are actually testing (checkSelfPermission would lie). +adb install -r -g app/build/outputs/apk/fdroid/debug/TrackerControl-fdroidDebug-latest.apk +adb shell pm revoke $PKG android.permission.ACCESS_LOCAL_NETWORK + +# 2. VPN consent. Makes VpnService.prepare() return null, which skips BOTH the +# system ConfirmDialog and TrackerControl's own explainer before it. +adb shell appops set $PKG ACTIVATE_VPN allow + +# 3. Onboarding. ActivityMain checks onboarding_version against +# ActivityOnboarding.ONBOARDING_VERSION; seeding it lands you on the main +# screen. This works before the first launch — run-as can create the file. +cat > /tmp/seed.xml <<'XML' + + + + +XML +adb push /tmp/seed.xml /data/local/tmp/seed.xml +adb shell "run-as $PKG sh -c 'mkdir -p shared_prefs && cat /data/local/tmp/seed.xml > shared_prefs/${PKG}_preferences.xml'" + +adb shell monkey -p $PKG -c android.intent.category.LAUNCHER 1 ``` +(Push through `/data/local/tmp` rather than piping a heredoc into `adb shell` — +quoting survives the round trip intact.) + +The VPN switch is at roughly `input tap 108 216` on a 1080×2400 screen; from +there the tunnel comes up with no dialogs at all. Verify with +`adb shell dumpsys connectivity | grep -o "VPN:net.kollnig[a-z.]*"`. + +Preferences, once seeded: + +- **Force-stop before editing.** A running process holds prefs in memory and + will overwrite your file on exit: `adb shell am force-stop $PKG` first. +- **Merge, never replace.** Rewriting the whole file drops `onboarding_version` + and drops you back into onboarding. Append inside `` with `sed`, or read + the file, edit, and write it back whole. +- **`adb uninstall` and `pm clear` wipe all of the above** — the seeded prefs, + the appop, and the granted permissions — which is a second reason not to reach + for them, on top of needing to ask first. + +To check a notification, read it with +`adb shell dumpsys notification --noredact | grep -A6 ''` rather than +screenshotting the shade, which captures the user's private notifications. + ```bash # From the repo root. Use ./gradlew (the wrapper).