From 92c832864df4d0c35cfc8e8fd4ad041db07c9154 Mon Sep 17 00:00:00 2001 From: Krzysztof Moch Date: Thu, 6 Nov 2025 09:02:40 +0100 Subject: [PATCH] fix(android): disable controls when in PiP --- .../core/fragments/FullscreenVideoFragment.kt | 7 ++++++- .../fragments/PictureInPictureHelperFragment.kt | 3 +++ .../main/java/com/twg/video/view/VideoView.kt | 17 ++++++++++++++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/react-native-video/android/src/main/java/com/twg/video/core/fragments/FullscreenVideoFragment.kt b/packages/react-native-video/android/src/main/java/com/twg/video/core/fragments/FullscreenVideoFragment.kt index 868e2540..34935885 100644 --- a/packages/react-native-video/android/src/main/java/com/twg/video/core/fragments/FullscreenVideoFragment.kt +++ b/packages/react-native-video/android/src/main/java/com/twg/video/core/fragments/FullscreenVideoFragment.kt @@ -91,6 +91,7 @@ class FullscreenVideoFragment(private val videoView: VideoView) : Fragment() { requireActivity().isInPictureInPictureMode if (isInPictureInPictureMode) { + // Disable controls in PiP mode - media session creates its own controls for PiP videoView.playerView.useController = false } else { videoView.playerView.useController = videoView.useController @@ -197,7 +198,11 @@ class FullscreenVideoFragment(private val videoView: VideoView) : Fragment() { restoreSystemUI() - if (videoView.useController == false) { + // Keep controls disabled if in PiP mode - media session creates its own controls for PiP + val isInPictureInPictureMode = requireActivity().isInPictureInPictureMode + if (isInPictureInPictureMode) { + videoView.playerView.useController = false + } else if (videoView.useController == false) { videoView.playerView.useController = false } diff --git a/packages/react-native-video/android/src/main/java/com/twg/video/core/fragments/PictureInPictureHelperFragment.kt b/packages/react-native-video/android/src/main/java/com/twg/video/core/fragments/PictureInPictureHelperFragment.kt index b3a21c23..f4eedb20 100644 --- a/packages/react-native-video/android/src/main/java/com/twg/video/core/fragments/PictureInPictureHelperFragment.kt +++ b/packages/react-native-video/android/src/main/java/com/twg/video/core/fragments/PictureInPictureHelperFragment.kt @@ -50,6 +50,9 @@ class PictureInPictureHelperFragment(private val videoView: VideoView) : Fragmen } if (currentPipVideo == videoView) { + // Disable controls immediately when entering PiP - media session creates its own controls for PiP + videoView.playerView.useController = false + // If we're currently in fullscreen, exit it first to prevent parent conflicts if (videoView.isInFullscreen) { try { diff --git a/packages/react-native-video/android/src/main/java/com/twg/video/view/VideoView.kt b/packages/react-native-video/android/src/main/java/com/twg/video/view/VideoView.kt index ad2c256a..200f9ba2 100644 --- a/packages/react-native-video/android/src/main/java/com/twg/video/view/VideoView.kt +++ b/packages/react-native-video/android/src/main/java/com/twg/video/view/VideoView.kt @@ -320,10 +320,9 @@ class VideoView @JvmOverloads constructor( Log.d("ReactNativeVideo", "Hiding root content views for PiP video nitroId: $nitroId") - // Remove playerView from parent - // In PiP mode, we don't want to show the controller - // Controls are handled by System if we have MediaSession + // In PiP mode, disable controls immediately - media session creates its own controls for PiP playerView.useController = false + playerView.setBackgroundColor(Color.BLACK) playerView.setShutterBackgroundColor(Color.BLACK) @@ -412,6 +411,11 @@ class VideoView @JvmOverloads constructor( return try { events.willEnterPictureInPicture?.let { it() } + // Disable controls before entering PiP - media session creates its own controls for PiP + runOnMainThread { + playerView.useController = false + } + val success = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val params = createPictureInPictureParams(this) safeEnterPictureInPictureMode(params) @@ -447,6 +451,9 @@ class VideoView @JvmOverloads constructor( events.willExitPictureInPicture?.let { it() } + // Restore controls when exiting PiP - they were disabled because media session handles PiP controls + playerView.useController = useController + if (movedToRootForPiP) { restoreRootContentViews() } else { @@ -471,6 +478,10 @@ class VideoView @JvmOverloads constructor( } events.willExitPictureInPicture?.let { it() } + + // Restore controls when exiting PiP - they were disabled because media session handles PiP controls + playerView.useController = useController + if (movedToRootForPiP) { restoreRootContentViews() } else {