Multitasking on TV

Android 14 (API level 34) introduces some enhancements to the picture-in-picture (PiP) APIs to allow for multitasking. While PiP support was introduced in Android 8.0 (API level 26), it was not widely supported on Android TV, and not supported at all on Google TV prior to Android 13. Multitasking for TV uses PiP mode to allow two separate apps to coexist on the screen: one running in full screen, with a second running in PiP mode. There are different requirements for apps running in either of these modes.

The default behavior is that the PiP app overlays the full-screen app. This is much the same as standard Android picture-in-picture behavior.

Note that when integrating multitasking, your application must declare its usage types in accordance with the TV app quality guidelines.

Run your app in PiP mode

For TV devices running Android 14 (API level 34) or higher, run your app in PiP mode by calling enterPictureInPictureMode(). TV devices running earlier versions of Android don't support PiP mode.

Here is an example of how to implement the logic of a button to enter PiP mode:

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

The action is only added if the device has the system feature FEATURE_PICTURE_IN_PICTURE. Also, when the action is triggered, the aspect ratio of PiP mode is set to match the aspect ratio of the video being played.

Be sure to add a title and subtitle to give the user information about what this PIP is generally being used for.

Coexist with apps running in PiP mode

When your app is running as a fullscreen app it may need to adapt for other apps running in PiP mode.

Keep-clear APIs

In some cases, the PiP app may overlay important UI components within the fullscreen app. To mitigate this, there are keep-clear APIs that apps can use to identify critical UI components that shouldn't be overlaid. The system attempts to honor the requests to avoid covering these components by repositioning the PiP window.

Keep-Clear

To specify that a view shouldn't be overlaid, use preferKeepClear in your XML layout as in the following example:

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

You can also do this programmatically using 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);
}

There may be times when you don't need to keep an entire View clear, but only a section of it. The setPreferKeepClearRects() can be used to specify regions of the View that shouldn't be overlaid. UIs that don't use Views natively, such as Flutter, Jetpack Compose, and WebView, may have sub-sections that need regions kept clear. This API can be used for those cases.

Usage types

Your app must declare a meta-data value attribute of com.google.android.tv.pip.category that corresponds with the primary type or types of usage for the picture-in-picture mode. Any <activity> that has set android:supportsPictureInPicture="true" should declare this attribute with a relevant value from the table below.

Usage types that don't fall into any of these categories, in particular any playback of media content, are not allowed in picture-in-picture mode on TV.

Value Description
"communication" Communications use cases, such as video or voice calls.
"smartHome" Smart home integrations, such as connected doorbells or baby monitors.
"health" Health use cases, such as fitness tracking or health monitoring.
"ticker" Ticker use cases, such as live sports scores or news and stock tickers.

Multiple values are separated by a vertical bar (|). For example:

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