The Phone Was Not My Test Rig. It Was Already in Use

I was already using my phone for development when an automated session prepared another iOS performance run against it. A screenshot exposed the collision before the second run took control.
That should have ended the attempt.
The automation also sent a mouse click intended for the app. It landed on a different window because desktop focus had moved.
Two failures, one assumption: the automated session had treated shared hardware as if it belonged exclusively to the test process.
It did not. The phone was being used. So was the desktop (a surprisingly common condition for a personal computer).
A device run is a write to a shared session
Mobile test automation often gets described as if a device were a passive destination. Build, install, launch, inspect.
Each verb changes state.
A second Flutter process can attach to the same phone while another development session is active. A launch can replace the running app. An installer can overwrite or remove a build. A driver can compete for the Dart VM service.
The dangerous part is that the conflict may not fail immediately. Both sessions can make partial progress and then produce logs or screenshots that belong to different runs.
That is worse than a clean refusal because the evidence still looks plausible.
Synthetic input has no ownership lock
The desktop collision was simpler.
A script decided where to click. Before the operating system delivered the event, focus moved to the operator's window. The click went to the focused application, not to the application the script had in mind.
There is no useful “click more carefully” fix for this race. The human owns focus and can change it at any time. A coordinate does not carry an application identity.
Screen reading and input injection also have different risk. A bounded screenshot can be read-only. A synthetic click can save, delete, submit, dismiss, or launch something depending on the window beneath it.
Once I separated those two capabilities, the safe boundary became obvious: observe without stealing focus, and ask the person to perform interactions instead of injecting desktop input.
The smallest useful device protocol
I do not need a distributed lock service for one phone (that would be impressively over-engineered). I need a short preflight.
Before a device run:
- Identify the exact device and the command that will write to it.
- Check for an existing
flutter runor another process using the device. - Announce the install, launch, termination, or driver action before it happens.
- Stop if the device is busy.
For desktop interaction:
- Prefer a window or region capture that does not move focus.
- Do not synthesize keyboard or mouse input on a shared desktop.
- Ask for a manual interaction when a click is required.
This protocol adds a short preflight. It can prevent two sessions from corrupting each other's evidence and forcing a complete rerun.
A conflict is a valid test result
Automation tends to treat “could not run” as failure and “produced output” as success. Shared-device work needs a third result:
SKIPPED_BUSY: the target device has an active operator session
That outcome preserves both sessions. It also tells the next person exactly what must change before retrying.
Taking the device anyway produces a prettier dashboard and a less trustworthy result.
Prefer lower-cost evidence first
Not every mobile question needs the phone.
Static inspection can confirm configuration. Unit tests can confirm pure logic. Widget tests can confirm layout constraints. A simulator can cover many runtime paths without touching a daily device.
Physical hardware should be used for the properties that require it: platform integration, actual sensors, notifications, audio routing, performance, or behavior under lock and process termination.
The order matters. Use cheap, isolated evidence first. Reach for shared hardware when it can answer a question the earlier layers cannot.
The broader lesson
Coding agents are often evaluated by how independently they can act. Independence is useful only when the resource is actually theirs to control.
A repository may have parallel writers. A browser may have a human-controlled focus. A phone may be both a development target and someone's daily device.
The correct assumption is not exclusivity. It is concurrency.
Before your next automated device run, add one boring check for an existing session. If the phone is busy, report it and stop.
The most professional test result you produce that day might be the one you deliberately did not run.
Get the next post.
If you made it to the end, meet the next post in your inbox or RSS reader.