Configurar seu app para picture-in-picture

Na tag de atividade do arquivo AndroidManifest.xml, faça o seguinte:

  1. Adicione supportsPictureInPicture e defina como true para declarar que você vai usar o PiP no app.
  2. Adicione configChanges e defina como orientation|screenLayout|screenSize|smallestScreenSize para especificar que a atividade processa as mudanças de configuração de layout. Dessa forma, sua atividade não será reiniciada quando mudanças de layout ocorrerem durante as transições do modo picture-in-picture.

      <activity
        android:name=".SnippetsActivity"
        android:exported="true"
        android:supportsPictureInPicture="true"
        android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
        android:theme="@style/Theme.Snippets">

No código do Compose, faça o seguinte:

  1. Adicione esta extensão em Context. Você vai usar essa extensão várias vezes ao longo do guia para acessar a atividade.
    internal fun Context.findActivity(): ComponentActivity {
        var context = this
        while (context is ContextWrapper) {
            if (context is ComponentActivity) return context
            context = context.baseContext
        }
        throw IllegalStateException("Picture in picture should be called in the context of an Activity")
    }

Adicionar PiP ao sair do app para Androids anteriores ao Android 12

Para adicionar o PiP em versões anteriores ao Android 12, use addOnUserLeaveHintProvider. Siga estas etapas para adicionar o PiP para versões anteriores ao Android 12:

  1. Adicione uma restrição de versão para que esse código seja acessado apenas nas versões O até R.
  2. Use um DisposableEffect com Context como chave.
  3. Dentro do DisposableEffect, defina o comportamento para quando o onUserLeaveHintProvider for acionado usando uma lambda. Na lambda, chame enterPictureInPictureMode() em findActivity() e transmita PictureInPictureParams.Builder().build().
  4. Adicione addOnUserLeaveHintListener usando findActivity() e transmita a lambda.
  5. No onDispose, adicione removeOnUserLeaveHintListener usando findActivity() e transmita a lambda.

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

Adicionar PiP ao sair do app para o Android 12 ou mais recente

Após o Android 12, o PictureInPictureParams.Builder é adicionado por um modificador transmitido ao player de vídeo do app.

  1. Crie um modifier e chame onGloballyPositioned nele. As coordenadas do layout serão usadas em uma etapa posterior.
  2. Crie uma variável para o PictureInPictureParams.Builder().
  3. Adicione uma instrução if para verificar se o SDK é S ou mais recente. Nesse caso, adicione setAutoEnterEnabled ao builder e defina como true para entrar no modo PiP ao deslizar. Isso proporciona uma animação mais suave do que passar por enterPictureInPictureMode.
  4. Use findActivity() para chamar setPictureInPictureParams(). Chame build() no builder e transmita.

val pipModifier = modifier.onGloballyPositioned { layoutCoordinates ->
    val builder = PictureInPictureParams.Builder()

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        builder.setAutoEnterEnabled(true)
    }
    context.findActivity().setPictureInPictureParams(builder.build())
}
VideoPlayer(pipModifier)

Use setAspectRatio para definir a proporção da janela PiP.

Para definir a proporção da janela PiP, escolha uma proporção específica ou use a largura e a altura do tamanho do vídeo do player. Se você estiver usando um player media3, verifique se ele não é nulo e se o tamanho do vídeo dele não é igual a [VideoSize.UNKNOWN][6] antes de definir a proporção.

val context = LocalContext.current

val pipModifier = modifier.onGloballyPositioned { layoutCoordinates ->
    val builder = PictureInPictureParams.Builder()
    if (shouldEnterPipMode && player != null && player.videoSize != VideoSize.UNKNOWN) {
        val sourceRect = layoutCoordinates.boundsInWindow().toAndroidRectF().toRect()
        builder.setSourceRectHint(sourceRect)
        builder.setAspectRatio(
            Rational(player.videoSize.width, player.videoSize.height)
        )
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        builder.setAutoEnterEnabled(shouldEnterPipMode)
    }
    context.findActivity().setPictureInPictureParams(builder.build())
}

VideoPlayer(pipModifier)

Se você estiver usando um player personalizado, defina a proporção na altura e na largura do player usando a sintaxe específica dele. Se o player for redimensionado durante a inicialização, se ele estiver fora dos limites válidos de qual pode ser a proporção, o app vai falhar. Talvez seja necessário adicionar verificações quando a proporção puder ser calculada, semelhante ao que é feito para um player de mídia.