O Android 14 (nível 34 da API) apresenta algumas melhorias nas APIs de picture-in-picture (PiP) para permitir a multitarefa. Embora o suporte ao PiP tenha sido introduzido no Android 8.0 (nível 26 da API), ele não era amplamente compatível com o Android TV e não era compatível com o Google TV antes do Android 13. A multitarefa para TV usa o modo PIP para permitir que dois apps separados coexistam na tela: um em tela cheia e outro no modo PIP. Há requisitos diferentes para apps em execução em qualquer um desses modos.
O comportamento padrão é que o app PiP se sobreponha ao app em tela cheia. Isso é muito parecido com o comportamento padrão do picture-in-picture do Android.
Ao integrar a multitarefa, seu aplicativo precisa declarar os tipos de uso de acordo com as diretrizes de qualidade de apps de TV.
Executar o app no modo PIP
Para dispositivos de TV com o Android 14 (nível 34 da API) ou mais recente, execute o app no modo picture-in-picture
chamando enterPictureInPictureMode(). Os dispositivos de TV com versões anteriores
do Android não são compatíveis com o modo PIP.
Veja um exemplo de como implementar a lógica de um botão para entrar no 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ó será adicionada se o dispositivo tiver o recurso do sistema
FEATURE_PICTURE_IN_PICTURE. Além disso, quando a ação é acionada, a
proporção do modo picture-in-picture é definida para corresponder à proporção do vídeo que está sendo
reproduzido.
Adicione um título e um subtítulo para informar ao usuário para que esse PIP geralmente é usado.
Coexistir com apps em execução no modo PIP
Quando o app está em tela cheia, talvez seja necessário se adaptar a outros apps em execução no modo PiP.
APIs de área livre
Em alguns casos, o app PiP pode se sobrepor a componentes importantes da IU no app em tela cheia. Para evitar isso, há APIs de limpeza que os apps podem usar para identificar componentes críticos da IU que não podem ser sobrepostos. O sistema tenta atender às solicitações para evitar que esses componentes sejam cobertos, reposicionando a janela PIP.
Para especificar que uma visualização não pode ser sobreposta, use preferKeepClear no seu
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 todo o View limpo, mas
apenas uma seção dele. O setPreferKeepClearRects() pode ser usado para
especificar regiões do View que não devem ser sobrepostas. As interfaces que não usam
Views de forma nativa, como Flutter, Jetpack Compose e WebView, podem ter
subseções que precisam de regiões sem obstruções. Essa API pode ser usada nesses casos.
Tipos de uso
O app precisa declarar um atributo de valor de metadados de
com.google.android.tv.pip.category que corresponda ao tipo ou
aos tipos principais de uso do modo picture-in-picture. Qualquer <activity> que tenha definido
android:supportsPictureInPicture="true" precisa declarar esse atributo com um
valor relevante da tabela a seguir.
Os tipos de uso que não se enquadram em nenhuma dessas categorias, em particular qualquer reprodução de conteúdo de mídia, não são permitidos no modo picture-in-picture na TV.
| Valor | Descrição |
|---|---|
"communication" |
Casos de uso de comunicação, como videochamadas ou ligações. |
"smartHome" |
Integrações de casa inteligente, como campainhas conectadas ou babás eletrônicas. |
"health" |
Casos de uso de saúde, como monitoramento de condicionamento físico ou de saúde. |
"ticker" |
Casos de uso de letreiros, como placares de esportes ao vivo ou letreiros de notícias e 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" />