O Android 14 (nível 34 da API) apresenta algumas melhorias nas APIs picture-in-picture (PiP) para possibilitar a realização de várias tarefas. Embora o suporte a picture-in-picture tenha sido introduzido no Android 8.0 (nível 26 da API), ele não tinha suporte no Android TV nem no Google TV antes do Android 13. O multitarefa para TV usa o modo picture-in-picture para permitir que dois apps separados coexistam na tela: um em tela cheia e o outro em execução no modo picture-in-picture. Há requisitos diferentes para apps executados em qualquer um desses modos.
O comportamento padrão é que o app picture-in-picture se sobreponha ao app em tela cheia. É muito parecido com o comportamento padrão do picture-in-picture do Android.
Ao integrar multitarefas, seu aplicativo precisa declarar os tipos de uso de acordo com as diretrizes de qualidade de apps para TV.
Executar o app no modo picture-in-picture
Em dispositivos de TV com o Android 14 (nível 34 da API) ou versões mais recentes, execute o app no modo picture-in-picture
chamando enterPictureInPictureMode()
. Dispositivos de TV com versões anteriores
do Android não oferecem suporte ao modo picture-in-picture.
Confira 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ó vai 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
em reprodução.
Adicione um título e um subtítulo para dar ao usuário informações sobre para que o PIP geralmente é usado.
Coexistir com apps executados no modo picture-in-picture
Quando o app é executado em tela cheia, pode ser necessário se adaptar a outros apps em execução no modo picture-in-picture.
APIs Keep-clear
Em alguns casos, o app picture-in-picture pode sobrepor componentes de interface importantes no app de tela cheia. Para mitigar isso, existem APIs claras que os apps podem usar para identificar componentes críticos da interface que não podem ser sobrepostos. O sistema tenta respeitar as solicitações para evitar a cobertura desses componentes reposicionando a janela picture-in-picture.
Para especificar que uma visualização não pode ser sobreposta, use preferKeepClear
no
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 maneira 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 um View
inteiro livre, mas
apenas uma parte dele. O setPreferKeepClearRects()
pode ser usado para
especificar regiões do View
que não podem ser sobrepostas. As interfaces que não usam
View
s de forma nativa, como Flutter, Jetpack Compose e WebView, podem ter
subseções que precisam de regiõ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 corresponda ao tipo principal ou aos
tipos 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 abaixo.
Os tipos de uso que não se enquadram em nenhuma dessas categorias, especialmente a 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 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" />