Picture-in-picture

The picture-in-picture (PIP) feature for Android handheld devices lets users resize an app with an ongoing activitiy into a small window. PIP is especially useful for video apps because content continues to play while the user is free to perform other actions. Users can manipulate this window's position through the SystemUI and interact with the application currently in picture-in-picture with (up to three) app-provided actions.

PIP requires explicit opt-in from applications that support it and works on a per-activity basis. (A single application can have multiple activities, only one of which is in PIP.) Activities request to enter picture-in-picture by calling enterPictureInPictureMode(), and receive activity callbacks in the form of onPictureInPictureModeChanged().

The setPictureInPictureParams() method lets activities control their aspect ratio while in PIP and custom actions, which allow users to interact with the activity without having to expand it. In PIP, the activity is in a paused, but rendering, state and does not directly receive touch input or window focus. Only a single task can be in PIP at a time.

More information is available in the Android Developer Picture-in-picture documentation.

Device requirements

To support PIP, enable the PackageManager#FEATURE_PICTURE_IN_PICTURE system feature in /android/frameworks/base/core/java/android/content/pm/PackageManager.java. Devices that support PIP must have a screen that is larger than 220dp at its smallest width. Similar to split screen multi-window, PIP allows multiple activities to run on-screen at the same time. Therefore, devices should have sufficient CPU and RAM to support this use case.

Implementation

Most of the activity lifecycle management is done in system between ActivityManager and WindowManager. The reference UI implementation is in the SystemUI package.

Modifications to the system should not affect its intrinsic behavior as defined by the Compatibility Test Suite (CTS) tests. The system logic for PIP mainly revolves around the management of tasks and activities within the "pinned" stack. Here is a quick class overview:

  • ActivityRecord: tracks each activity's picture-in-picture state. To prevent users from entering PIP in certain circumstances, such as from the lock screen or during VR, add cases to checkEnterPictureInPictureState().
  • ActivityManagerService: the primary interface from the activity to request entering PIP and the interface to calls from WindowManager and SystemUI to change the PIP activity state.
  • ActivityStackSupervisor: called from the ActivityManagerService to move tasks in or out of the pinned stack, updating the WindowManager as necessary.
  • PinnedStackWindowController: the WindowManager interface from ActivityManager.
  • PinnedStackController: reports changes in the system to SystemUI, such as IME shown/hidden, aspect ratio changed, or actions changed.
  • BoundsAnimationController: animates the PIP activity windows in a way that does not trigger a configuration change while resizing.
  • PipSnapAlgorithm: a shared class used in both the system and SystemUI that controls the snapping behaviour of the PIP window near the edges of the screen.

The reference SystemUI provides a complete implementation of PIP that supports presenting custom actions to users and general manipulation, such as expansion and dismissal. Device manufacturers can build upon these changes, as long as they do not affect the intrinsic behaviours as defined by the CDD. Here is a quick class overview:

  • PipManager: the SystemUI component that is started with SystemUI.
  • PipTouchHandler: the touch handler, which controls the gestures that manipulate the PIP. This is only used while the input consumer for the PIP is active (see InputConsumerController). New gestures can be added here.
  • PipMotionHelper: a convenience class that tracks the PIP position, and allowable region on-screen. Calls through to ActivityManagerService to update or animate the position and size of the PIP.
  • PipMenuActivityController: starts an activity that shows the actions provided by the activity currently in PIP. This activity is a task-overlay activity, and removes the overlaying input consumer to allow it to be interactive.
  • PipMenuActivity: the implementation for the menu activity.
  • PipMediaController: the listener that updates SystemUI when the media session changes in a way that might affect the default actions on the PIP.
  • PipNotificationController: the controller that ensures that a notification is active while a user is using the PIP feature.
  • PipDismissViewController: the overlay shown to users when they start interacting with the PIP to indicate that it can be dismissed.

Default placement

There are various system resources that control the default placement of the PIP:

  • config_defaultPictureInPictureGravity: the gravity integer, which controls the corner to place the PIP, such as BOTTOM|RIGHT.
  • config_defaultPictureInPictureScreenEdgeInsets: the offsets from the sides of the screen to place the PIP.
  • config_pictureInPictureDefaultSizePercent and config_pictureInPictureDefaultAspectRatio: the combination of percentage of the screen width and the aspect ratio controls the size of the PIP. The computed default PIP size should not be smaller than @dimen/default_minimal_size_pip_resizable_task, as defined by CTS and the CDD.
  • config_pictureInPictureSnapMode: the snapping behaviour as defined in PipSnapAlgorithm.

Device implementations should not change the minimum and maximum aspect ratios that are defined in the CDD and CTS.

Permissions

The per-package "application operation" (OP_PICTURE_IN_PICTURE) in AppOpsManager (main/core/java/android/app/AppOpsManager.java), lets users to control PIP on a per-application level through the system settings. Device implementations need to respect this check when an activity requests to enter picture-in-picture mode.

Testing

To test PIP implementations, run all picture-in-picture related tests found in the host-side CTS tests under /cts/hostsidetests/services/activitymanager, particularly in ActivityManagerPinnedStackTests.java.