Wielozadaniowość na telewizorze

W Androidzie 14 (API na poziomie 34) wprowadzono ulepszenia interfejsów API obrazu w obrazie (PiP), które umożliwiają wielozadaniowość. Obsługa trybu obraz w obrazie została wprowadzona w Androidzie 8.0 (poziom interfejsu API 26), ale nie była powszechnie obsługiwana na Androidzie TV i nie była w ogóle obsługiwana na Google TV przed Androidem 13. Wielozadaniowość na telewizorze wykorzystuje tryb obrazu w obrazie, aby umożliwić jednoczesne działanie dwóch oddzielnych aplikacji na ekranie: jedna działa na pełnym ekranie, a druga w trybie obrazu w obrazie. Wymagania dotyczące aplikacji działających w tych trybach są różne.

Domyślnie aplikacja w trybie obraz w obrazie nakłada się na aplikację w trybie pełnoekranowym. Działa to podobnie jak standardowa funkcja obraz w obrazie na Androidzie.

Pamiętaj, że podczas integrowania wielozadaniowości aplikacja musi deklarować typy użycia zgodnie ze wskazówkami dotyczącymi jakości aplikacji TV.

Uruchamianie aplikacji w trybie obrazu w obrazie

W przypadku urządzeń TV z Androidem 14 (API na poziomie 34) lub nowszym uruchom aplikację w trybie obrazu w obrazie, wywołując enterPictureInPictureMode(). Telewizory z wcześniejszymi wersjami Androida nie obsługują trybu obrazu w obrazie.

Oto przykład implementacji logiki przycisku, który umożliwia przejście do trybu obrazu w obrazie:

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);
    }
}

Działanie jest dodawane tylko wtedy, gdy urządzenie ma funkcję systemową FEATURE_PICTURE_IN_PICTURE. Gdy działanie zostanie wywołane, format obrazu trybu obrazu w obrazie zostanie dopasowany do formatu obrazu odtwarzanego filmu.

Dodaj tytułpodtytuł, aby poinformować użytkownika, do czego zwykle służy ten PIP.

Współdziałanie z aplikacjami działającymi w trybie obrazu w obrazie

Gdy aplikacja działa w trybie pełnoekranowym, może wymagać dostosowania do innych aplikacji działających w trybie obrazu w obrazie.

Interfejsy API Keep-clear

W niektórych przypadkach aplikacja w trybie obrazu w obrazie może nakładać się na ważne komponenty interfejsu w aplikacji na pełnym ekranie. Aby temu zapobiec, dostępne są interfejsy API, które umożliwiają aplikacjom identyfikowanie krytycznych komponentów interfejsu, na które nie powinna nakładać się aplikacja w trybie obrazu w obrazie. System próbuje uwzględnić te żądania, aby uniknąć zasłaniania tych komponentów przez zmianę położenia okna obrazu w obrazie.

umieszczanie okna PiP w taki sposób, aby nie zasłaniało ważnych komponentów interfejsu;
Rysunek 1. umieszczanie okna PiP w taki sposób, aby nie zasłaniało ważnych komponentów interfejsu;

Aby określić, że widok nie powinien być nakładany, użyj w układzie XML elementu preferKeepClear, jak w tym przykładzie:

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

Możesz to też zrobić programowo za pomocą 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);
}

Czasami nie musisz utrzymywać w czystości całej View, ale tylko jej fragment. Właściwość setPreferKeepClearRects() może służyć do określania regionów View, które nie powinny być nakładane. Interfejsy, które nie korzystają z Views natywnie, np. Flutter, Jetpack Compose i WebView, mogą mieć podsekcje, w których trzeba zachować pusty obszar. W takich przypadkach można użyć tego interfejsu API.

Rodzaje wykorzystania

Aplikacja musi deklarować atrybut wartości metadanychcom.google.android.tv.pip.category, który odpowiada głównemu typowi lub typom użycia trybu obrazu w obrazie. Każdy <activity>, który ma ustawiony atrybut android:supportsPictureInPicture="true", powinien zadeklarować ten atrybut z odpowiednią wartością z poniższej tabeli.

Typy użycia, które nie należą do żadnej z tych kategorii, w szczególności odtwarzanie treści multimedialnych, nie są dozwolone w trybie obrazu w obrazie na telewizorze.

Wartość Opis
communication przykłady zastosowań komunikacyjnych, np. rozmowy wideo lub połączenia głosowe;
smartHome integracje z inteligentnym domem, takie jak połączone dzwonki do drzwi czy elektroniczne nianie;
health przypadki użycia związane ze zdrowiem, takie jak śledzenie aktywności fizycznej lub monitorowanie stanu zdrowia;
ticker Przykłady zastosowań paska informacyjnego, takie jak wyniki sportowe na żywo, wiadomości i notowania giełdowe.

Wiele wartości jest rozdzielonych pionową kreską (|). Przykład:

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