Your app should not enter PiP mode in the following situations:
- If the video is stopped or paused.
- If you are on a different page of the app than the video player.
To control when your app enters PiP mode, add a variable that tracks the state
of the video player using a mutableStateOf
.
Toggle state based on if video is playing
To toggle the state based on if the video player is playing, add a listener on the video player. Toggle the state of your state variable based on if the player is playing or not:
player.addListener(object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { shouldEnterPipMode = isPlaying } })
Toggle state based on if player is released
When the player is released, set your state variable to false
:
fun releasePlayer() { shouldEnterPipMode = false }
Use state to define if PiP mode is entered (pre-Android 12)
- Since adding PiP pre-12 uses a
DisposableEffect
, you need to create a new variable byrememberUpdatedState
withnewValue
set as your state variable. This will ensure that the updated version is used within theDisposableEffect
. In the lambda that defines the behavior when the
OnUserLeaveHintListener
is triggered, add anif
statement with the state variable around the call toenterPictureInPictureMode()
:val currentShouldEnterPipMode by rememberUpdatedState(newValue = shouldEnterPipMode) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Build.VERSION.SDK_INT < Build.VERSION_CODES.S ) { val context = LocalContext.current DisposableEffect(context) { val onUserLeaveBehavior: () -> Unit = { if (currentShouldEnterPipMode) { context.findActivity() .enterPictureInPictureMode(PictureInPictureParams.Builder().build()) } } context.findActivity().addOnUserLeaveHintListener( onUserLeaveBehavior ) onDispose { context.findActivity().removeOnUserLeaveHintListener( onUserLeaveBehavior ) } } } else { Log.i("PiP info", "API does not support PiP") }
Use state to define if PiP mode is entered (post-Android 12)
Pass your state variable into setAutoEnterEnabled
so that your app only enters
PiP mode at the right time:
val pipModifier = modifier.onGloballyPositioned { layoutCoordinates -> val builder = PictureInPictureParams.Builder() // Add autoEnterEnabled for versions S and up if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { builder.setAutoEnterEnabled(shouldEnterPipMode) } context.findActivity().setPictureInPictureParams(builder.build()) } VideoPlayer(pipModifier)
Use setSourceRectHint
to implement a smooth animation
The setSourceRectHint
API creates a smoother animation for entering PiP
mode. In Android 12+, it also creates a smoother animation for exiting PiP mode.
Add this API to the PiP builder to indicate the area of the activity that is
visible following the transition into PiP.
- Only add
setSourceRectHint()
to thebuilder
if the state defines that the app should enter PiP mode. This avoids calculatingsourceRect
when the app does not need to enter PiP. - To set the
sourceRect
value, use thelayoutCoordinates
that are given from theonGloballyPositioned
function on the modifier. - Call
setSourceRectHint()
on thebuilder
and pass in thesourceRect
variable.
val context = LocalContext.current val pipModifier = modifier.onGloballyPositioned { layoutCoordinates -> val builder = PictureInPictureParams.Builder() if (shouldEnterPipMode) { val sourceRect = layoutCoordinates.boundsInWindow().toAndroidRectF().toRect() builder.setSourceRectHint(sourceRect) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { builder.setAutoEnterEnabled(shouldEnterPipMode) } context.findActivity().setPictureInPictureParams(builder.build()) } VideoPlayer(pipModifier)