Wielozadaniowość na telewizorze

Android 14 (poziom 34 interfejsu API) wprowadza kilka ulepszeń interfejsów API obrazu w obrazie (PiP), które umożliwiają korzystanie z trybu wielozadaniowego. Obsługa PIP została wprowadzona w Androidzie 8.0 (poziom 26 interfejsu API), ale nie była powszechnie obsługiwana na Androidzie TV, a przed Androidem 13 nie była obsługiwana w Google TV. Tryb wielozadaniowy na telewizorze korzysta z trybu PIP, aby umożliwić współistnienie na ekranie 2 oddzielnych aplikacji: jednej działającej na pełnym ekranie i drugiej działającej w trybie PIP. Aplikacje działające w tych trybach mają różne wymagania.

Domyślnie aplikacja PiP nakłada się na aplikację działającą na pełnym ekranie. Jest to podobne do standardowego zachowania obrazu w obrazie w Androidzie.

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

Uruchamianie aplikacji w trybie PiP

Na urządzeniach z Androidem TV w wersji 14 (poziom 34 interfejsu API) lub nowszej uruchom aplikację w trybie PiP mode, wywołując metodę enterPictureInPictureMode(). Urządzenia z Androidem TV w starszych wersjach Androida nie obsługują trybu PiP.

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

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, współczynnik proporcji trybu PiP zostanie ustawiony tak, aby pasował do współczynnika proporcji odtwarzanego filmu.

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

Współistnienie z aplikacjami działającymi w trybie PiP

Gdy aplikacja działa na pełnym ekranie, może być konieczne dostosowanie jej do innych aplikacji działających w trybie PiP.

Interfejsy API keep-clear

W niektórych przypadkach aplikacja PiP może nakładać się na ważne komponenty interfejsu w aplikacji działającej na pełnym ekranie. Aby temu zapobiec, dostępne są interfejsy API keep-clear, których aplikacje mogą używać do identyfikowania krytycznych komponentów interfejsu, które nie powinny być nakładane. System próbuje uwzględnić prośby o unikanie zasłaniania tych komponentów, zmieniając położenie okna PiP.

Keep-Clear

Aby określić, że widok nie powinien być nakładany, użyj preferKeepClear w układzie XML, 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ą metody 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 trzeba utrzymywać całego View w czystości, ale tylko jego części. Metody setPreferKeepClearRects() można użyć do określenia obszarów View, które nie powinny być nakładane. Interfejsy, które nie używają natywnie Views, takie jak Flutter, Jetpack Compose i WebView, mogą mieć podsekcje, które wymagają utrzymywania obszarów w czystości. W takich przypadkach można użyć tego interfejsu API.

Rodzaje wykorzystania

Aplikacja musi zadeklarować atrybut wartości metadanych odpowiadający głównemu typowi lub typom użycia trybu obrazu w obrazie.com.google.android.tv.pip.category Każda <activity> która ma ustawiony android:supportsPictureInPicture="true" powinna zadeklarować ten atrybut z odpowiednią wartością z tabeli poniżej.

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

Wartość Opis
communication Przypadki użycia związane z komunikacją, np. rozmowy wideo lub głosowe.
smartHome Integracje z inteligentnym domem, np. połączone dzwonki do drzwi lub nianie elektroniczne.
health Przypadki użycia związane ze zdrowiem, np. śledzenie aktywności fizycznej lub monitorowanie stanu zdrowia.
ticker Przypadki użycia związane z paskiem informacyjnym, np. wyniki sportowe na żywo lub 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" />