Multitarefas na TV

O Android 14 (nível 34 da API) apresenta algumas melhorias na APIs picture-in-picture (PiP) para fazer várias tarefas ao mesmo tempo. Enquanto picture-in-picture foi introduzido no Android 8.0 (API de nível 26), ele não era amplamente compatíveis com o Android TV e não são compatíveis com o Google TV em versões anteriores ao Android. 13. A multitarefa para TV usa o modo picture-in-picture para permitir que dois aplicativos diferentes coexistam na tela: um em execução integralmente e outra no modo picture-in-picture. Existem requisitos diferentes para aplicativos executados em qualquer um desses modos.

O comportamento padrão é que o app picture-in-picture se sobreponha ao app em tela cheia. Isso é é muito parecido com o comportamento padrão do picture-in-picture do Android.

Observe que, ao integrar multitarefas, seu aplicativo deve declarar seu tipos de uso no de acordo com as diretrizes de qualidade de apps para TV.

Executar o app no modo picture-in-picture

Para dispositivos de TV com o Android 14 (nível 34 da API) ou versões mais recentes, executar o app no picture-in-picture chamando enterPictureInPictureMode(). Dispositivos de TV executados mais cedo não são compatíveis com o modo picture-in-picture.

Este é um exemplo de como implementar a lógica de um botão para entrar Modo picture-in-picture:

Kotlin

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    pictureInPictureButton.visibility =
        if (requireActivity().packageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
            pictureInPictureButton.setOnClickListener {
                val aspectRatio = Rational(view.width, view.height)
                val params = PictureInPictureParams.Builder()
                    .setAspectRatio(aspectRatio)
                    .build()
                val result = requireActivity().enterPictureInPictureMode(params)
            }
            View.VISIBLE
        } else {
            View.GONE
        }
}

Java

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if (requireActivity().getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
        pictureInPictureButton.setVisibility(View.VISIBLE);
        pictureInPictureButton.setOnClickListener(v -> {
            Rational aspectRatio = new Rational(view.getWidth(), view.getHeight());
            PictureInPictureParams params = new PictureInPictureParams.Builder()
                    .setAspectRatio(aspectRatio)
                    .setTitle("My Streaming App")
                    .setSubtitle("My On-Demand Content")
                    .build();
            Boolean result = requireActivity().enterPictureInPictureMode(params);
        });
    } else {
        pictureInPictureButton.setVisibility(View.GONE);
    }
}

A ação só vai ser adicionada se o dispositivo tiver o recurso do sistema FEATURE_PICTURE_IN_PICTURE Além disso, quando a ação é acionada, proporção do modo picture-in-picture está definida para corresponder à proporção do vídeo tocado.

Adicione um título e um subtítulo para dar as informações do usuário para que o PIP geralmente é usado.

Coexistir com apps executados no modo picture-in-picture

Quando seu aplicativo é executado como um aplicativo de tela cheia, ele pode precisar se adaptar a outros em execução no modo picture-in-picture.

APIs Keep-clear

Em alguns casos, o aplicativo picture-in-picture pode sobrepor componentes de IU importantes no aplicativo de tela cheia. Para atenuar isso, existem APIs claras que os apps podem usar para identificar componentes críticos da IU que não devem ser sobrepostos. O sistema tenta respeitar as solicitações para evitar a cobertura desses componentes, reposicionando a janela picture-in-picture.

Manter claro

Para especificar que uma visualização não deve ser sobreposta, use preferKeepClear na sua Layout XML, como no exemplo a seguir:

<TextView
    android:id="@+id/important_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:preferKeepClear="true"
    android:text="@string/app_name"/>

Também é possível fazer isso de forma programática usando setPreferKeepClear():

Kotlin

private lateinit var binding: MyLayoutBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    binding = MyLayoutBinding.inflate(layoutInflater)
    setContentView(binding.root)
    binding.importantText.isPreferKeepClear = true
}

Java

private MyLayoutBinding binding;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    binding = MyLayoutBinding.inflate(getLayoutInflater());
    setContentView(binding.getRoot());
    binding.importantText.setPreferKeepClear(true);
}

Às vezes, não é necessário manter uma View inteira clara, mas somente uma parte dele. O setPreferKeepClearRects() pode ser usado para especificar regiões do View que não devem ser sobrepostas. que não usam Views de forma nativa, como Flutter, Jetpack Compose e WebView, podem ter subseções que precisam de informações claras. É possível usar essa API nesses casos.

Tipos de uso

Seu app precisa declarar um atributo de valor de metadados de com.google.android.tv.pip.category, que corresponde ao tipo principal ou e tipos de uso do modo picture-in-picture. Qualquer <activity> que tenha definido android:supportsPictureInPicture="true" precisa declarar esse atributo com uma relevante da tabela abaixo.

Os tipos de uso que não se enquadram em nenhuma dessas categorias, em particular a reprodução de conteúdo de mídia não são permitidas no modo picture-in-picture na TV.

Valor Descrição
"communication" Casos de uso de comunicação, como videochamadas ou chamadas de voz.
"smartHome" Integrações de casa inteligente, como campainhas ou babás eletrônicas conectadas.
"health" Casos de uso relacionados à saúde, como monitoramento de condicionamento físico ou saúde.
"ticker" Casos de uso de indicadores, como placares esportivos ao vivo ou notícias e códigos de ações.

Vários valores são separados por uma barra vertical (|). Por exemplo:

<meta-data android:name="com.google.android.tv.pip.category" android:value="smartHome|health" />