画中画

适用于 Android 手持设备的画中画 (PIP) 功能可让用户将正在进行活动的应用调整到一个小窗口中。PIP 对于视频应用尤其有用,因为内容会在用户自由执行其他操作时继续播放。用户可以通过 SystemUI 操作此窗口的位置,并通过(最多三个)应用提供的操作与当前处于画中画模式的应用互动。

PIP 需要支持它的应用明确选择启用,并且在每个 Activity 的基础上工作。(单个应用可以有多个 Activity,但只有一个 Activity 处于 PIP 模式。)Activity 通过调用 enterPictureInPictureMode() 请求进入画中画模式,并以 onPictureInPictureModeChanged() 的形式接收 Activity 回调。

setPictureInPictureParams() 方法允许 Activity 在画中画 (PIP) 模式下控制其纵横比和自定义操作,从而让用户无需展开 Activity 即可与之互动。在 PIP 模式下,Activity 处于暂停但仍在渲染的状态,并且不会直接接收触摸输入或窗口焦点。一次只能有一个任务处于 PIP 模式。

如需了解详情,请参阅 Android 开发者画中画文档。

设备要求

要支持 PIP,请在 /android/frameworks/base/core/java/android/content/pm/PackageManager.java 中启用 PackageManager#FEATURE_PICTURE_IN_PICTURE 系统功能。支持 PIP 的设备必须具有最小宽度大于 220dp 的屏幕。与分屏多窗口类似,PIP 允许多个 Activity 同时在屏幕上运行。因此,设备应具有足够的 CPU 和 RAM 来支持此用例。

实现

大多数 Activity 生命周期管理都在 ActivityManagerWindowManager 之间的系统中完成。参考 UI 实现在 SystemUI 软件包中。

对系统的修改不应影响其由兼容性测试套件 (CTS) 测试定义的内在行为。PIP 的系统逻辑主要围绕“固定”堆栈中任务和 Activity 的管理。以下是类概览

  • ActivityRecord跟踪每个 Activity 的画中画状态。要防止用户在某些情况下(例如从锁屏界面或在 VR 期间)进入 PIP,请将用例添加到 checkEnterPictureInPictureState()
  • ActivityManagerService从 Activity 请求进入 PIP 的主要接口,以及从 WindowManagerSystemUI 调用以更改 PIP Activity 状态的接口。
  • ActivityStackSupervisorActivityManagerService 调用,以将任务移入或移出固定堆栈,并在必要时更新 WindowManager
  • PinnedStackWindowController来自 ActivityManagerWindowManager 接口。
  • PinnedStackControllerSystemUI 报告系统中的更改,例如 IME 显示/隐藏、纵横比更改或操作更改。
  • BoundsAnimationController以不会在调整大小时触发配置更改的方式为 PIP Activity 窗口设置动画效果。
  • PipSnapAlgorithm系统和 SystemUI 中使用的共享类,用于控制 PIP 窗口在屏幕边缘附近的吸附行为。

参考 SystemUI 提供了 PIP 的完整实现,该实现支持向用户呈现自定义操作和常规操作(例如展开和关闭)。设备制造商可以在这些更改的基础上进行构建,前提是它们不影响 CDD 定义的内在行为。以下是类概览

  • PipManagerSystemUI 启动的 SystemUI 组件。
  • PipTouchHandler触摸处理程序,用于控制操作 PIP 的手势。这仅在 PIP 的输入使用者处于活动状态时使用(请参阅 InputConsumerController)。可以在此处添加新手势。
  • PipMotionHelper一个便捷类,用于跟踪 PIP 位置和屏幕上允许的区域。通过 ActivityManagerService 调用以更新 PIP 的位置和大小或为其设置动画效果。
  • PipMenuActivityController启动一个 Activity,该 Activity 显示当前处于 PIP 模式的 Activity 提供的操作。此 Activity 是任务叠加 Activity,并移除叠加的输入使用者以使其可互动。
  • PipMenuActivity菜单 Activity 的实现。
  • PipMediaController监听器,当媒体会话发生可能影响 PIP 上的默认操作的更改时,它会更新 SystemUI
  • PipNotificationController控制器,用于确保在用户使用 PIP 功能时通知处于活动状态。
  • PipDismissViewController当用户开始与 PIP 互动以指示可以关闭 PIP 时,向用户显示的叠加层。

默认放置

有多种系统资源可以控制 PIP 的默认放置

  • config_defaultPictureInPictureGravitygravity 整数,用于控制放置 PIP 的角,例如 BOTTOM|RIGHT
  • config_defaultPictureInPictureScreenEdgeInsets从屏幕侧边放置 PIP 的偏移量。
  • config_pictureInPictureDefaultSizePercentconfig_pictureInPictureDefaultAspectRatio屏幕宽度百分比和纵横比的组合控制 PIP 的大小。计算出的默认 PIP 大小不应小于 CTS 和 CDD 定义的 @dimen/default_minimal_size_pip_resizable_task
  • config_pictureInPictureSnapModePipSnapAlgorithm 中定义的吸附行为。

设备实现不应更改 CDD 和 CTS 中定义的最小和最大纵横比。

权限

AppOpsManager (main/core/java/android/app/AppOpsManager.java) 中的每个软件包“应用操作” (OP_PICTURE_IN_PICTURE) 允许用户通过系统设置在每个应用级别控制 PIP。当 Activity 请求进入画中画模式时,设备实现需要遵守此检查。

测试

要测试 PIP 实现,请运行主机端 CTS 测试中 /cts/hostsidetests/services/activitymanager 下的所有画中画相关测试,尤其是在 ActivityManagerPinnedStackTests.java 中。