android: the handoff — the pending rounds, the pipeline, and what is unverified
Everything written this session that has not been through the device: rounds 43 to 48 (each patch adversarially verified, 43's transient-notice expectation fixed), a partial round 49, the pipeline scripts, the Android Auto design and the icon comparison mock. Also the two harness changes that were never A/B'd — adaptive waits, which may only shorten a declared wait and never lengthen it, and a ship that runs the mock walk and the deploy at the same time. The A/B and its 255-step baseline are in handoff/tools; main stays at what the phone has actually walked.
This commit is contained in:
1 parent
867fd42972
commit
9f0601027c
400 files changed
+26401
-3
No files matched your search
@@ -0,0 +1,108 @@
|
||||
/* ── the phone, turned over: the two settings that do it ───────────────
|
||||
* `settings get system accelerometer_rotation` and `user_rotation` are the
|
||||
* only two things on the device this walk ever writes, and both are READ
|
||||
* before either is written. The saved pair is latched at module scope on
|
||||
* purpose: the step loop's `still()` and its PROBE call are wrapped in
|
||||
* nothing at all, so a WebView that stops answering rejects after cdp.mjs's
|
||||
* timeout and throws clean out of the walk into main's `finally`. That is
|
||||
* the exact path that would otherwise leave Kyle's phone locked sideways,
|
||||
* which is why the restore is a latch reachable from four places — the
|
||||
* rotation block's own finally, main's finally, process 'exit' and a
|
||||
* signal — rather than a step in a list. */
|
||||
let rotationSaved = null;
|
||||
|
||||
/** Both rotation settings as the device has them now, or null when either
|
||||
* will not read as something we recognise. null is the SKIP signal: the
|
||||
* block never writes what it could not read first. `user_rotation` comes
|
||||
* back as the literal "null" on a phone where it has never been set. */
|
||||
function rotationSettings() {
|
||||
try {
|
||||
const accel = adb("shell", "settings", "get", "system", "accelerometer_rotation").toString().trim();
|
||||
const user = adb("shell", "settings", "get", "system", "user_rotation").toString().trim();
|
||||
if (!/^\d+$/.test(accel)) return null;
|
||||
if (!/^\d+$/.test(user) && user !== "null") return null;
|
||||
return { accel, user };
|
||||
} catch { return null; }
|
||||
}
|
||||
|
||||
/** Read once and latch. Returns the pair, or null when the device would not
|
||||
* say — in which case nothing has been written and there is nothing to put
|
||||
* back. */
|
||||
function rotationArm() {
|
||||
const was = rotationSettings();
|
||||
if (was) rotationSaved = was;
|
||||
return was;
|
||||
}
|
||||
|
||||
/** Drop the latch WITHOUT writing anything. For the skip paths: the pair has
|
||||
* been read but nothing has been put, and restoring there would write two
|
||||
* settings onto Kyle's phone that this walk never changed. */
|
||||
function rotationDisarm() { rotationSaved = null; }
|
||||
|
||||
/** Hold the phone at one rotation. Auto-rotate goes off FIRST: with the
|
||||
* sensor still in charge it takes `user_rotation` straight back and the
|
||||
* turn never happens. Returns null, or the message it failed with. */
|
||||
function rotationPut(n) {
|
||||
try {
|
||||
adb("shell", "settings", "put", "system", "accelerometer_rotation", "0");
|
||||
adb("shell", "settings", "put", "system", "user_rotation", String(n));
|
||||
return null;
|
||||
} catch (e) { return e.message; }
|
||||
}
|
||||
|
||||
/** Put both back, once. The latch is cleared BEFORE anything is written, so
|
||||
* the first caller is the only one that acts and the three behind it are
|
||||
* no-ops; a restore that fails puts the latch back so the next caller can
|
||||
* try again. The rotation goes first and auto-rotate last — a phone whose
|
||||
* auto-rotate was on must hand control back to the sensor only once the
|
||||
* angle underneath it is the one it started at. Synchronous, because
|
||||
* `adb()` is spawnSync and nothing asynchronous survives an 'exit'
|
||||
* handler. Returns true, null when there was nothing to restore, or the
|
||||
* message it failed with. */
|
||||
function rotationRestore() {
|
||||
const was = rotationSaved;
|
||||
rotationSaved = null;
|
||||
if (!was) return null;
|
||||
try {
|
||||
if (was.user === "null") {
|
||||
/* never set on this phone: delete it rather than inventing a 0 */
|
||||
try { adb("shell", "settings", "delete", "system", "user_rotation"); }
|
||||
catch { adb("shell", "settings", "put", "system", "user_rotation", "0"); }
|
||||
} else {
|
||||
adb("shell", "settings", "put", "system", "user_rotation", was.user);
|
||||
}
|
||||
adb("shell", "settings", "put", "system", "accelerometer_rotation", was.accel);
|
||||
return true;
|
||||
} catch (e) { rotationSaved = was; return e.message; }
|
||||
}
|
||||
|
||||
/** The system's own view of the turn, for the report only. The two settings
|
||||
* read back, plus the display's current size and rotation out of `dumpsys
|
||||
* window displays` — whose spelling moves between Android versions, so a
|
||||
* parse failure comes back empty and is printed, never asserted. */
|
||||
function rotationSystem() {
|
||||
const out = { setAccel: "", setUser: "", dispCur: "", dispRot: "" };
|
||||
try {
|
||||
out.setAccel = adb("shell", "settings", "get", "system", "accelerometer_rotation").toString().trim();
|
||||
out.setUser = adb("shell", "settings", "get", "system", "user_rotation").toString().trim();
|
||||
} catch { /* empty is the reading */ }
|
||||
try {
|
||||
const d = adb("shell", "dumpsys", "window", "displays").toString();
|
||||
out.dispCur = (d.match(/\bcur=(\d+x\d+)/) || [])[1] || "";
|
||||
out.dispRot = (d.match(/mCurrentRotation=(?:ROTATION_)?(\w+)/) || d.match(/\brotation=(\d+)/) || [])[1] || "";
|
||||
} catch { /* empty is the reading */ }
|
||||
return out;
|
||||
}
|
||||
|
||||
/* 'exit' does not run on a signal and a signal does not run 'exit', so
|
||||
both. Ctrl-C in the middle of the turn is precisely the case that would
|
||||
otherwise leave the phone sideways until Kyle found the Quick Settings
|
||||
tile. Registered only for the phone walk — the mock never writes a
|
||||
setting, and a SIGINT handler on the mock run would change how Ctrl-C
|
||||
behaves there for nothing. */
|
||||
if (PHONE) {
|
||||
process.on("exit", () => { rotationRestore(); });
|
||||
for (const sig of ["SIGINT", "SIGTERM", "SIGBREAK"]) {
|
||||
process.on(sig, () => { rotationRestore(); process.exit(130); });
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user