screentinker/android
ScreenTinker d913397559 Hand the frame back cleanly when a wipe ends
Reported as one or two frames of the OUTGOING photo after every transition, before
the incoming one appears. Three things conspired, all at the moment the wipe ends.

The overlay is a translucent SurfaceView with setZOrderOnTop(true) and a clear colour
of (0,0,0,0). onDrawFrame() cleared unconditionally, before testing whether there was
anything to draw. finish() left RENDERMODE_CONTINUOUSLY on and only POSTED the content
swap and the hide to the main thread, so the GL thread got at least one more frame in
first: it cleared to fully transparent while the overlay was still visible, showing
straight through to the ImageView — which still held the previous photo, because the
swap had not run yet. Not a black flash; a see-through one. The same clear ran on the
failed/hard-cut path.

So: clear only when a frame is actually going to be drawn over it, and stop the render
loop in finish() on the GL thread rather than waiting for the main thread to park the
overlay. What stays on screen is then the wipe's final frame, which is the destination
image, and it is correct to leave it there.

That still left the hand-off itself racing. Hiding a Z-ordered SurfaceView is a
SurfaceFlinger transaction that is not synchronised with the app drawing the newly
mounted bitmap, so the hide can land a vsync before the paint and uncover the old photo
anyway. The overlay now lingers briefly before parking. It costs nothing to look at —
both layers are showing the same picture — and it removes the race rather than
narrowing it.

Measured on the panel with 64x36 frame classification over screen recordings: the old
photo reappeared after 1 of 4 wipes before, 0 of 14 after the first two changes. That
sampling runs through a virtual display and cannot see every composited frame, so it
bounds the problem rather than proving absence — hence closing the last gap by
construction instead of by measurement.

The web player never had this: it calls mount() and then hides the canvas synchronously
in one task, so both land in the same paint.
2026-07-28 22:23:23 -05:00
..
app Hand the frame back cleanly when a wipe ends 2026-07-28 22:23:23 -05:00
gradle/wrapper Initial open source release 2026-04-08 12:14:53 -05:00
build.gradle.kts Initial open source release 2026-04-08 12:14:53 -05:00
gradle.properties Initial open source release 2026-04-08 12:14:53 -05:00
gradlew Initial open source release 2026-04-08 12:14:53 -05:00
gradlew.bat Initial open source release 2026-04-08 12:14:53 -05:00
settings.gradle.kts Initial open source release 2026-04-08 12:14:53 -05:00