blob: b86306da4d53a3e744a4ca1645fe6d4954dee48e [file] [log] [blame]
<html devsite>
<head>
<title>Picture-in-picture</title>
<meta name="project_path" value="/_project.yaml" />
<meta name="book_path" value="/_book.yaml" />
</head>
<body>
<!--
Copyright 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<p>
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.
</p>
<p>
More information is available in the Android Developer
<a href="https://developer.android.com/training/tv/playback/picture-in-picture.html">Picture-in-picture</a>
documentation.
</p>
<h2 id="overview">Overview</h2>
<p>
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
<code>enterPictureInPictureMode()</code>, and receive activity callbacks in the
form of <code>onPictureInPictureModeChanged()</code>.
</p>
<p>
Android 8.0 added additional methods, including
<code>setPictureInPictureParams()</code>, 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.
</p>
<h2 id="device-requirements">Device requirements</h2>
<p>
To support PIP, enable the
<code>PackageManager#FEATURE_PICTURE_IN_PICTURE</code> system feature in
<code><a href="https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/content/pm/PackageManager.java">/android/frameworks/base/core/java/android/content/pm/PackageManager.java</a></code>.
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.
</p>
<h2 id="implementation">Implementation</h2>
<p>
Most of the activity lifecycle management is done in system between
<code><a href="https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/am/">ActivityManager</a></code>
and <code><a
href="https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/">WindowManager</a></code>.
The reference UI implementation is in the <code><a
href="https://android.googlesource.com/platform/frameworks/base/+/master/packages/SystemUI/">SystemUI</a></code>
package.
</p>
<p>
Modifications to the system should not affect its intrinsic behavior as defined
by the <a href="#cts-tests">Compatibility Test Suite (CTS) tests</a>.
The system logic for PIP mainly revolves around the management of tasks and
activities within the "pinned" stack. Here is a quick class overview:
</p>
<ul>
<li><strong><code>ActivityRecord</code></strong>: 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
<code>checkEnterPictureInPictureState()</code>.</li>
<li><strong><code>ActivityManagerService</code></strong>: the primary interface
from the activity to request entering PIP and the interface to calls from
<code>WindowManager</code> and <code>SystemUI</code> to change the PIP activity
state.</li>
<li><strong><code>ActivityStackSupervisor</code></strong>: called from the
<code>ActivityManagerService</code> to move tasks in or out of the pinned stack,
updating the <code>WindowManager</code> as necessary.</li>
<li><strong><code>PinnedStackWindowController</code></strong>: the
<code>WindowManager</code> interface from <code>ActivityManager</code>.</li>
<li><strong><code>PinnedStackController</code></strong>: reports changes in the
system to <code>SystemUI</code>, such as IME shown/hidden, aspect ratio changed,
or actions changed.</li>
<li><strong><code>BoundsAnimationController</code></strong>: animates the PIP
activity windows in a way that does not trigger a configuration change while
resizing.</li>
<li><strong><code>PipSnapAlgorithm</code></strong>: 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.</li>
</ul>
<p>
The reference <code><a
href="https://android.googlesource.com/platform/frameworks/base/+/master/packages/SystemUI/">SystemUI</a></code>
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:</p>
<ul>
<li><strong><code>PipManager</code></strong>: the <code>SystemUI</code>
component that is started with <code>SystemUI</code>.</li>
<li><strong><code>PipTouchHandler</code></strong>: 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 <code>InputConsumerController</code>). New
gestures can be added here.</li>
<li><strong><code>PipMotionHelper</code></strong>: a convenience class that
tracks the PIP position, and allowable region on-screen. Calls through to
<code>ActivityManagerService</code> to update or animate the position and size
of the PIP.</li>
<li><strong><code>PipMenuActivityController</code></strong>: 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.</li>
<li><strong><code>PipMenuActivity</code></strong>: the implementation for the
menu activity.</li>
<li><strong><code>PipMediaController</code></strong>: the listener that updates
<code>SystemUI</code> when the media session changes in a way that might affect
the default actions on the PIP.</li>
<li><strong><code>PipNotificationController</code></strong>: the controller that
ensures that a notification is active while a user is using the PIP feature.</li>
<li><strong><code>PipDismissViewController</code></strong>: the overlay shown to
users when they start interacting with the PIP to indicate that it can be
dismissed.</li>
</ul>
<h2 id="default-placement">Default placement</h2>
<p>
There are various system resources that control the default placement of the
PIP:
</p>
<ul>
<li><strong><code>config_defaultPictureInPictureGravity</code></strong>: the <a
href="https://developer.android.com/reference/android/view/Gravity.html">gravity</a>
integer, which controls the corner to place the PIP, such as
<code>BOTTOM|RIGHT</code>.</li>
<li><strong><code>config_defaultPictureInPictureScreenEdgeInsets</code></strong>:
the offsets from the sides of the screen to place the PIP.</li>
<li><strong><code>config_pictureInPictureDefaultSizePercent</code></strong> and
<strong><code>config_pictureInPictureDefaultAspectRatio</code></strong>: 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
<code>@dimen/default_minimal_size_pip_resizable_task</code>, as defined by CTS
and the CDD.</li>
<li><strong><code>config_pictureInPictureSnapMode</code></strong>: the snapping
behaviour as defined in <code>PipSnapAlgorithm</code>.</li>
</ul>
<p>
Device implementations should not change the minimum and maximum aspect ratios
that are defined in the CDD and CTS.
</p>
<h2 id="permissions">Permissions</h2>
<p>
Android 8.0 added a per-package "application operation"
(<code>OP_PICTURE_IN_PICTURE</code>) to <code>AppOpsManager</code>
(<code>master/core/java/android/app/AppOpsManager.java)</code>, 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.
</p>
<h2 id="cts-tests">Testing</h2>
<p>
To test PIP implementations, run all picture-in-picture related tests found in
the host-side CTS tests under <code><a
href="https://android.googlesource.com/platform/cts/+/master/hostsidetests/services/activitymanager/src/android/server/cts">/cts/hostsidetests/services/activitymanager</a></code>,
particularly in <code>ActivityManagerPinnedStackTests.java</code>.
</p>
</body>
</html>