Android 8.0 includes support for picture-in-picture (PIP) for Android handheld devices. PIP allows users to resize an app with an ongoing activity 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.
More information is available in the Android Developer Picture-in-picture documentation.
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()
.
Android 8.0 added additional methods, including
setPictureInPictureParams()
, which 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.
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.
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.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.
Android 8.0 added a per-package "application operation"
(OP_PICTURE_IN_PICTURE
) to AppOpsManager
(master/core/java/android/app/AppOpsManager.java)
, which allows
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.
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
.