Files
filip131311 b1abdec13a feat(tools): add a shake tool for iOS simulators and Android emulators (#786)
Shaking a device was the one hardware gesture argent couldn't perform, putting
iOS's "Undo Typing" prompt, React Native's dev menu, and app-side
shake-to-report handlers out of reach.

iOS needs no simulator-server work: Simulator.app drives Device > Shake by
posting a plain Darwin notification, `com.apple.UIKit.SimulatorShake`, which
UIKit turns into the same motion event a physical device raises. So the whole
path is one `simctl spawn <udid> notifyutil -p <name>` — and the same argv runs
on a remote simulator through `sim-remote spawn`, whose exit code must be read
explicitly because it exits 0 even when the child fails.

Android has no OS-level shake event at all; every shake feature is an app-side
accelerometer detector, so the sensor is driven over the emulator console with a
burst of hard direction changes. That override outlives the call, so the resting
vector is captured up front and always restored.

Simulators and emulators only. Physical phones have real accelerometers with no
host-side hook, and TV targets have no shake gesture — but Apple TV and Android
TV are not separate platforms, so the capability matrix cannot exclude them and
each handler probes the runtime and rejects, pointing at `tv-remote`.

Live testing on a packaged build found three Android defects, each now fixed and
covered by a test that fails without the fix:

- The resting-vector regex could not read scientific notation, which is exactly
  how a rotated emulator reports its near-zero axes. The read failed, a portrait
  fallback was adopted, and the restore then rotated a landscape device back to
  portrait while still reporting success.
- Overlapping shakes raced: the second captured a mid-burst sample as its
  resting vector and, finishing last, left the accelerometer pinned at ±30 m/s²
  — a self-perpetuating state every later shake re-restored. Capture, burst and
  restore are now one critical section per device, and an implausible resting
  magnitude is rejected so a foreign tilt heals instead of being adopted.
- `adb emu` exits 0 whether or not the console accepted the command, reporting
  a refusal only as a `KO:` line, so a rejected sensor write read as a
  successful shake. The reply is now read, taking the last non-empty line as the
  verdict.

Verified live: iOS raises the undo alert (local and remote), the Android burst
reaches the framework per `dumpsys sensorservice` with the resting pose restored,
landscape survives a shake, four concurrent shakes serialize cleanly, and a
refusing console fails loudly.
2026-08-13 23:20:24 +02:00
..