summaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-10-22 21:06:44 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-10-22 21:06:44 +0000
commit9bf135585885b043a05f3e74197314bdb4633c67 (patch)
tree02b76001144b26d8711a6c3f47c4a01bfbcc97cb /app/src/main/java
parent4fa99073761bbedcdc2bce45a666399bf4b425aa (diff)
Hardware-accelerate the video dialog's own window
Peter, on the referrer build: the player "plays and shows controls, with a white screen instead of video. The scrubber thumbnails pop up, but the main playback is blank white." His screenshot shows YouTube's title, gear, play button, timecode and progress bar all drawn correctly over a blank area. That narrows it a long way. Everything the page renders -- chrome, gradients, the storyboard images behind the scrubber -- composites fine, so the renderer is healthy and the embed is right. The one thing missing is the only thing that does not come from the page: video is composited from a separate surface, and that needs the window it sits in to be hardware accelerated. The player is a Dialog, which is its own Window. The activity declares android:hardwareAccelerated, but that does not carry to a Window a dialog creates for itself, so the flag is now set on it explicitly. No new logic, so nothing new to unit-test: the URL and referrer this loads are unchanged and still covered by YouTubeLinksTest. It is a property of the window the existing WebView lives in. Unverified here, and this emulator cannot settle it: it has no working video path at all in a WebView. It hard-crashed the AVD twice on a plain <video>, and with software decoding forced it survives but renders a broken-media placeholder rather than a picture. Everything up to display is confirmed on-device; display is not. If the picture is still missing, this rules the window out and the remaining suspect is the surface itself, which means taking the player out of a floating window entirely. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/org/terst/feedreader/ui/ReaderWebView.kt20
1 files changed, 20 insertions, 0 deletions
diff --git a/app/src/main/java/org/terst/feedreader/ui/ReaderWebView.kt b/app/src/main/java/org/terst/feedreader/ui/ReaderWebView.kt
index 1bc1315..3af460a 100644
--- a/app/src/main/java/org/terst/feedreader/ui/ReaderWebView.kt
+++ b/app/src/main/java/org/terst/feedreader/ui/ReaderWebView.kt
@@ -7,6 +7,7 @@ import android.view.ScaleGestureDetector
import android.view.View
import android.webkit.WebChromeClient
import android.webkit.WebResourceRequest
+import android.view.WindowManager
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.foundation.layout.Column
@@ -21,8 +22,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
+import androidx.compose.ui.window.DialogWindowProvider
import org.terst.feedreader.data.DEFAULT_READER_FONT_SIZE_PX
import org.terst.feedreader.data.UNZOOMED_TEXT_ZOOM_PERCENT
import org.terst.feedreader.data.pinchZoomFontSizePx
@@ -343,6 +347,22 @@ fun YouTubePlayerDialog(videoId: String, onDismiss: () -> Unit) {
// narrow, sitting off-center). Opt out so fillMaxWidth below means the real
// screen width, with our own padding controlling the margin instead.
Dialog(onDismissRequest = onDismiss, properties = DialogProperties(usePlatformDefaultWidth = false)) {
+ // A dialog is its own Window, and video is the one kind of web content that needs the
+ // window it sits in to be hardware accelerated: it is composited from a separate surface
+ // rather than drawn into the page like everything else. Without the flag, the page
+ // renders perfectly and only the video is missing -- reported live as the player's
+ // controls, title and scrubber thumbnails all appearing over a blank area where the
+ // picture should be, with the audio playing.
+ //
+ // The activity has android:hardwareAccelerated, but that does not carry to a Window the
+ // dialog creates for itself, so it is set here explicitly.
+ val dialogWindow = (LocalView.current.parent as? DialogWindowProvider)?.window
+ LaunchedEffect(dialogWindow) {
+ dialogWindow?.setFlags(
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+ )
+ }
AndroidView(
modifier = Modifier.fillMaxWidth().padding(16.dp).aspectRatio(16f / 9f),
factory = { ctx ->