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
.