Ingresa PiP en los momentos correctos

Tu app no debe ingresar al modo de PIP en las siguientes situaciones:

  • Indica si el video está detenido o pausado.
  • Si te encuentras en una página de la app diferente a la del reproductor de video

Para controlar cuándo tu app ingresa en modo de PIP, agrega una variable que haga un seguimiento del estado del reproductor de video con un mutableStateOf.

Estado de activación o desactivación según si se está reproduciendo el video

Para alternar el estado según si el reproductor de video está en reproducción, agrega un objeto de escucha en el reproductor de video. Alterna el estado de tu variable de estado según si el jugador está jugando o no:

player.addListener(object : Player.Listener {
    override fun onIsPlayingChanged(isPlaying: Boolean) {
        shouldEnterPipMode = isPlaying
    }
})

Alternar el estado según si se soltó el reproductor

Cuando se suelte el reproductor, establece la variable de estado en false:

fun releasePlayer() {
    shouldEnterPipMode = false
}

Usa el estado para definir si se ingresa al modo de PiP (anterior a Android 12)

  1. Dado que agregar PIP en versiones anteriores a Android 12 usa un DisposableEffect, debes crear una variable nueva con rememberUpdatedState y establecer newValue como tu variable de estado. Esto garantizará que se use la versión actualizada en DisposableEffect.
  2. En la expresión lambda que define el comportamiento cuando se activa OnUserLeaveHintListener, agrega una sentencia if con la variable de estado alrededor de la llamada a enterPictureInPictureMode():

    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 = Runnable {
                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")
    }

Usa el estado para definir si se ingresa al modo de PiP (posterior a Android 12)

Pasa tu variable de estado a setAutoEnterEnabled para que tu app solo entre en el modo PIP en el momento adecuado:

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)

Usa setSourceRectHint para una animación fluida

La API de setSourceRectHint crea una animación más fluida para ingresar al modo de PiP. En Android 12 y versiones posteriores, también se crea una animación más fluida para salir del modo de PiP. Agrega esta API al compilador de PIP para indicar el área de la actividad que es visible después de la transición a PIP.

  1. Solo agrega setSourceRectHint() al builder si el estado define que la app debe ingresar al modo PIP. Esto evita calcular sourceRect cuando la app no necesita ingresar al modo PiP.
  2. Para establecer el valor de sourceRect, usa los layoutCoordinates que se proporcionan desde la función onGloballyPositioned en el modificador.
  3. Llama a setSourceRectHint() en el builder y pasa la variable sourceRect.

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)