From 12859087337b19ec5dbb5573ef7bef9c1c63c866 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sun, 16 Aug 2026 21:51:14 +0200 Subject: [PATCH] fix(android): paint the letterbox bars, so stale pixels stop surviving in them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Native video left debris in the padding around the video: the "previous frame" flash on rotation, a ghost copy of the control bar stranded in the top bar, each new clock digit drawn over the one before it (35:42 with the 1 still showing through the 2), and the sleep/quality menus leaving their imprint after closing. One cause under all of it — nothing painted those bars. The window surface is opaque; the theme is not translucent and dumpsys window shows no translucency flag. For an opaque surface HWUI deliberately does NOT clear the damaged region before replaying a frame: it assumes the view hierarchy covers every pixel it owns. Here that hierarchy is window background → video TextureView → transparent WebView, and fitSurfaceToScreen sizes the TextureView to the letterboxed video rect. So the bars were the window background's alone to paint, and setTransparent(true) cleared it to TRANSPARENT — leaving them painted by nobody, with whatever was last in the framebuffer surviving there. The window background now stays opaque black while compositing. It cannot hide the video: the TextureView is drawn on top of it, and the WebView's own background is what lets the picture through. Three previous attempts missed because they aimed at the window's rotation animation and at TextureView frame-retention — two postOnAnimation hops, an onSurfaceTextureUpdated reveal, then ROTATION_ANIMATION_JUMPCUT with FLAG_FULLSCREEN to make it stick. The pixels were never the animation's, which is also why the artefact reproduces standing still, with no rotation involved. Those are removed. The alpha-hiding among them actively made things worse: it blanked the one view that reliably paints its own rect. FLAG_FULLSCREEN goes too — it fought edge-to-edge insets for no gain. Verified on device (HONOR ROD2-W09, Android 16): reproduced with native video on — ghost control bar in the top bar, doubled clock digit — then absent after the fix across playback, the control bar and a rotation round-trip. DR-194 is rewritten to record the real mechanism and marked Done. --- docs/requirements.md | 2 +- docs/traceability.md | 8898 ++++++++--------- .../com/dtourolle/jellytau/MainActivity.kt | 108 +- .../jellytau/player/JellyTauPlayer.kt | 102 +- 4 files changed, 4508 insertions(+), 4602 deletions(-) diff --git a/docs/requirements.md b/docs/requirements.md index 4aaa88c2..02d9662d 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -349,7 +349,7 @@ Internal architecture, components, and application logic. | DR-188 | Native Android video is **ready to be the default except for the background-audio handoff**, and the flip therefore waits. The picture defects behind DR-172 are all found, fixed and device-verified — DR-185 (the app shell painted over the surface through a CSS rule targeting an attribute nothing set), DR-182 (nothing could lift the poster card on a path with no `