Android 8.0 支持在 Android 手持设备上使用画中画 (PIP) 功能。借助画中画功能,用户可以将有正在进行的活动的应用调整到一个小窗口中。画中画对视频应用来说尤其有用,因为用户可以随时执行其他操作,而不会打断内容播放。用户可以通过 SystemUI 操控该窗口的位置,并通过应用提供的操作(最多三项)与当前处于画中画模式的应用流畅地互动。
有关详情,请参阅 Android 开发者画中画文档。
概览
画中画功能需要在支持它的应用中明确选择启用,并按 Activity 运作(一个应用可以有多个 Activity ,但其中只有一个可处于画中画模式)。Activity 通过调用 enterPictureInPictureMode()
来请求进入画中画模式,并以 onPictureInPictureModeChanged()
的形式接收 Activity 回调。
Android 8.0 中新增了更多方法,包括 setPictureInPictureParams()
,借助这种方法,Activity 可以控制其在画中画模式下的宽高比和自定义操作,这样一来,用户无需展开 Activity 便可以与之互动。在画中画中,Activity 处于暂停但继续呈现的状态,并且不直接接收触摸输入或窗口焦点。在同一时间点,只能有一项任务处于画中画模式。
设备要求
要支持画中画功能,请在 /android/frameworks/base/core/java/android/content/pm/PackageManager.java
中启用 PackageManager#FEATURE_PICTURE_IN_PICTURE
系统功能。支持画中画功能的设备的最小屏幕宽度必须大于 220dp。与分屏多窗口类似,画中画支持多个 Activity 同时在屏幕上运行。因此,设备的 CPU 和 RAM 要足以支持这类使用情形。
实现
大多数 Activity 生命周期管理都是由系统的 ActivityManager
和 WindowManager
组件协作完成的。相应的参考界面实现位于 SystemUI
软件包中。
对系统所做的修改不应影响其内在行为(如兼容性测试套件 (CTS) 测试中所定义)。画中画的系统逻辑主要围绕“置顶”堆栈中的任务和 Activity 管理而展开。以下是对系统逻辑类的简单介绍:
ActivityRecord
:跟踪每个 Activity 的画中画状态。为了防止用户在某些情况下(例如从锁定屏幕或在观看 VR 视频期间)进入画中画,请向checkEnterPictureInPictureState()
添加用例。ActivityManagerService
:Activity 在请求进入画中画模式时所调用的主接口,也是WindowManager
和SystemUI
在更改画中画 Activity 状态时所调用的接口。ActivityStackSupervisor
:从ActivityManagerService
调用,以向置顶堆栈移入任务或从中移出任务,必要时会更新WindowManager
。PinnedStackWindowController
:来自ActivityManager
的WindowManager
接口。PinnedStackController
:将系统中的变化告知SystemUI
,例如 IME 显示/隐藏、宽高比变化、操作变化。BoundsAnimationController
:以在调整大小的过程中不触发配置更改的方式,对画中画 Activity 窗口进行动画处理。PipSnapAlgorithm
:系统和 SystemUI 中使用的共享类,可控制屏幕边缘附近的画中画窗口的贴靠行为。
参考 SystemUI
中提供了画中画功能的完整实现(支持向用户呈现自定义操作并执行展开和关闭等常规操控)。
设备制造商可以在该实现的基础上做进一步的开发,只要所做更改不影响 CDD 所定义的内在行为即可。以下是对相关类的简单介绍:
PipManager
:随SystemUI
启动的SystemUI
组件。PipTouchHandler
:触摸处理程序,用于控制操纵画中画窗口的手势。仅在画中画的输入使用方处于活动状态时使用(请参阅InputConsumerController
)。可在此处理程序中添加新手势。PipMotionHelper
:一个辅助类,用于跟踪画中画的位置和屏幕上允许的区域。通过这个类调用ActivityManagerService
可更新或调整画中画的位置和大小。PipMenuActivityController
:用于启动一个 Activity,以便显示当前画中画中的 Activity 提供的操作。所启动的 Activity 属于任务叠加层 Activity,会移除上层的输入使用方,以使自身进入可互动状态。PipMenuActivity
:菜单 Activity 的实现。PipMediaController
:当媒体会话的变化可能会影响画中画上的默认操作时更新SystemUI
的侦听器。PipNotificationController
:确保在用户使用画中画功能时显示一条有效通知的控制器。PipDismissViewController
:当用户开始与画中画进行互动时向用户显示的叠加层,提示用户可以关闭画中画。
默认显示位置
用于控制画中画的默认显示位置的系统资源有多项:
config_defaultPictureInPictureGravity
:gravity 整数,可控制放置画中画的角落,如BOTTOM|RIGHT
。config_defaultPictureInPictureScreenEdgeInsets
:画中画的放置位置相对于屏幕侧边的偏移量。config_pictureInPictureDefaultSizePercent
和config_pictureInPictureDefaultAspectRatio
:占屏幕宽度的百分比与宽高比的组合,用于控制画中画的大小。计算得出的默认画中画大小不应小于@dimen/default_minimal_size_pip_resizable_task
(如 CTS 和 CDD 中所定义)。config_pictureInPictureSnapMode
:贴靠行为(如PipSnapAlgorithm
中所定义)。
设备实现不应更改 CDD 和 CTS 中定义的宽高比上限和下限。
权限
Android 8.0 在 AppOpsManager
(master/core/java/android/app/AppOpsManager.java)
中新增了基于软件包的“应用操作”(OP_PICTURE_IN_PICTURE
),这样一来,用户便可以通过系统设置在应用级别控制画中画。
当 Activity 请求进入画中画模式时,设备实现需要遵循此检查要求。
测试
要测试画中画实现,请运行主机端 CTS 测试中 /cts/hostsidetests/services/activitymanager
(尤其是 ActivityManagerPinnedStackTests.java
中)下所有与画中画相关的测试。