From 1514de53c7214e5fb6c8923c701a5b9fcb15d1d8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 28 Mar 2026 22:40:03 +0000 Subject: [PATCH] fix: keep screen on during PiP playback and survive screen lock PiP video now keeps the screen on while playing (matching YouTube behavior) and no longer kills the activity when the screen locks, allowing audio to continue through the PlaybackService. https://claude.ai/code/session_01QJzmFaabSA9YQ3oCQwEHTJ --- .../service/playback/pip/PipVideoActivity.kt | 20 +++++++++---- .../service/playback/pip/PipVideoView.kt | 29 +++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoActivity.kt index f69ce32c4..0252d4835 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoActivity.kt @@ -60,14 +60,22 @@ class PipVideoActivity : ComponentActivity() { } } - override fun onStop() { - super.onStop() - finishAndRemoveTask() + override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) { + super.onPictureInPictureModeChanged(isInPictureInPictureMode) + if (!isInPictureInPictureMode) { + // User dismissed PiP (swiped away or expanded). + finishAndRemoveTask() + } } - override fun finish() { - finishAndRemoveTask() - super.finish() + override fun onStop() { + super.onStop() + if (!isInPictureInPictureMode) { + // Only finish if we're not in PiP mode. + // When the screen locks while in PiP, we stay alive + // so the PlaybackService can continue audio playback. + finishAndRemoveTask() + } } companion object { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt index 4a01cb6ec..59a425981 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt @@ -32,7 +32,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView import androidx.core.content.ContextCompat +import androidx.media3.common.Player import androidx.media3.common.util.UnstableApi import androidx.media3.ui.compose.ContentFrame import androidx.media3.ui.compose.state.rememberMuteButtonState @@ -51,6 +53,8 @@ fun RenderPipVideo( controller: MediaControllerState, waveformData: WaveformData?, ) { + KeepScreenOnWhilePlaying(controller) + val modifier = remember { val ratio = @@ -78,6 +82,31 @@ fun RenderPipVideo( } } +@Composable +fun KeepScreenOnWhilePlaying(controller: MediaControllerState) { + val view = LocalView.current + + DisposableEffect(controller.controller, view) { + val listener = + object : Player.Listener { + override fun onIsPlayingChanged(isPlaying: Boolean) { + if (view.keepScreenOn != isPlaying) { + view.keepScreenOn = isPlaying + } + } + } + + // Set initial state + view.keepScreenOn = controller.controller.isPlaying + + controller.controller.addListener(listener) + onDispose { + controller.controller.removeListener(listener) + view.keepScreenOn = false + } + } +} + @Composable fun RegisterControllerReceiver(controllerState: MediaControllerState) { val context = LocalContext.current