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. 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. Existem requisitos diferentes para aplicativos executados em qualquer um desses modos.
O comportamento padrão é que o app PiP sobrepõe o app em tela cheia. Isso é semelhante ao comportamento padrão do picture-in-picture do Android.
Ao integrar a multitarefa, o aplicativo precisa declarar os tipos de uso em conformidade com as diretrizes de qualidade de apps para 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
PiP 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ó 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 informar ao usuário para que esse PIP é usado.
Coexistir com apps executados no modo picture-in-picture
Quando o app está em execução como um app em tela cheia, ele pode precisar se adaptar a outros apps 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 atender às solicitações para evitar cobrir esses componentes recolocando a janela do PiP.
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 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, você não precisa manter um View
inteiro limpo, mas
apenas uma seção dele. O setPreferKeepClearRects()
pode ser usado para
especificar regiões do View
que não devem ser sobrepostas. que não usam
View
s de forma nativa, como Flutter, Jetpack Compose e WebView, podem ter
subseções que precisam de informações claras. 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 principal ou
aos 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 chamadas de vídeo ou 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 tickers, como placares esportivos ao vivo ou notícias e tickers 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" />