WindowManager 扩展

借助 Jetpack WindowManager 库,应用开发者可为新的设备外形规格和多窗口环境提供支持。

WindowManager 扩展(简称“扩展”)是一个可选择启用的 Android 平台模块,支持各种 Jetpack WindowManager 功能。该模块在 AOSP 中的 frameworks/base/libs/WindowManager/Jetpack 中实现,并搭载在支持 WindowManager 功能的设备上。

扩展模块分发

WindowManager 扩展会被编译到 .jar 库中,如果在设备的 makefile 中被启用,会放置在设备的 system_ext 分区中。

要在设备上启用 WindowManager 扩展,请将以下代码添加到正式版设备 makefile 中:

$(call inherit-product, $(SRC_TARGET_DIR)/product/window_extensions.mk)

此操作会在设备上启用 androidx.window.extensionsandroidx.window.sidecar 软件包,并设置 persist.wm.extensions.enabled 属性。 如果将这些软件包包含在 makefile 中,也会在 etc/permissions/ 中放置声明,使它们可供应用进程使用。通常情况下,当 Jetpack WindowManager 库使用这些模块时,它们会在运行时作为应用进程的一部分加载和执行,这使得其操作类似于客户端框架代码,如下图所示:

图 1. 加载到应用进程中的 WindowManager 扩展,类似于平台代码。

androidx.window.extensions 模块是我们正在积极开发的 WindowManager 扩展模块。androidx.window.sidecar 模块是为了兼容最低版本的 Jetpack WindowManager 而随附的旧版模块,但辅助信息文件不再处于活跃维护状态。

下图显示了用于确定使用 androidx.window.extensions 还是 androidx.window.sidecar 的逻辑。

图 2. 用于确定访问 androidx.window.extensions 还是 androidx.window.sidecar 的决策树。

扩展模块

WindowManager 扩展目前为大屏可折叠设备和支持在外接显示屏上进行窗口化的设备提供窗口化功能。功能区域包括:

如果设备硬件不支持相应功能,除非该功能在兼容性定义文档 (CDD) 7.1.1.1 中明确要求,否则 OEM 的扩展实现可以提供 null 组件或使用 WindowExtensions 接口中方法的默认/桩实现的组件。

扩展和 Jetpack API

除了公开平台 API 之外,WindowManager 扩展模块还提供了自己的 API 接口。扩展模块在一个面向非开发者的 androidx.window.extensions Jetpack 库中公开开发,因此 Jetpack WindowManager (androidx.window) 可以在编译时链接到该模块。Extensions API 接口通常提供较低级别的 API。

扩展提供的 API 仅供 Jetpack WindowManager 库使用。应用开发者不应直接调用 Extensions API。为确保功能正常运行,不得将扩展库作为应用的依赖项添加到 Gradle build 文件中。避免直接将 Extensions 库预编译到应用中;而是依靠运行时加载,来避免合并加载预编译的扩展类和运行时提供的扩展类。

Jetpack WindowManager (androidx.window) 应被添加为应用依赖项。它提供了面向开发者的公开 API,包括适用于 WindowManager 扩展功能的 API。WindowManager 库会自动将扩展加载到应用进程中,并将较低级别的 Extensions API 封装到更高级别的抽象化功能和更有针对性的接口中。WindowManager Jetpack API 遵循现代 Android 应用开发的标准,旨在通过与使用其他 AndroidX 库的代码库完美集成,提供便捷的互操作性。

扩展版本和更新

扩展模块可以随 Android 平台年度或季度更新而更新。借助季度更新,Extensions API 级别可在 Android 平台 API 更新之间不断提升,从而加快迭代,并使 OEM 有机会在临近硬件发布时向新功能添加正式 API 访问权限。

下表列出了各种 Android 版本的 androidx.window.extensions API 版本。

Android 平台版本 WindowManager 扩展 API 级别 androidx.window.extensions API 版本
14 3 1.2.0
13 QPR3 2 1.1.0
13 1 1.0.0
12L 1 1.0.0

表 1. AOSP 中 Android 平台版本和 WindowManager 扩展版本之间的对应关系。

Extensions API 级别(第 2 列)随着现有稳定 API 接口(第 3 列)的每一次递增而增加。

由 OEM 提供的任何基础平台软件版本必须至少与上表中定义的扩展版本相同。您可以随旧版平台一起提供新版扩展,但通常情况下,实现还需要对 WindowManager 核心中进行大量修改才能支持该功能。实现不会针对相应旧平台版本,通过 CTS 测试自动进行验证。

向后兼容性和向前兼容性

Jetpack WindowManager 可处理复杂的任务,包括处理频繁的 API 级别更新、快速的 API 演变和向后兼容性。在应用进程中执行库代码时,库会检查声明的 Extensions API 级别,并根据声明的级别提供对功能的访问权限。

为防止应用在运行时崩溃,WindowManager 还会根据声明的 Extensions API 级别,对可用的 Extensions API 执行运行时 Java 反射检查。如果存在不一致,WindowManager 可能会停用扩展的部分或全部功能,并将相关功能报告为不适用于应用。

WindowManager 扩展以 system_ext 模块的形式实现,该模块使用私有平台 API 调用 WindowManager 核心 DeviceStateManager 以及其他系统服务,以此实现扩展功能。

在对应的季度或年度 Android 平台最终版本发布之前,可能无法与扩展的预发布版本保持兼容性。Extensions API 的完整历史记录可以在发布分支 window:extensions:extensions API 文本文件中找到。

较高版本的扩展必须能继续与编译到应用中的旧版 WindowManager 搭配使用,以保持向前兼容性。为此,任何新版 Extensions API 都只会添加新 API,而不会移除旧版 API。因此,包含较低版本 WindowManager 的应用可以继续使用针对应用进行编译时所用的旧版 Extensions API。

CTS 验证可确保对于设备上声明的任何扩展 API 版本,所有的 API 和先前版本都存在且可正常运行。

性能

从 Android 14(API 级别 34)开始,Extensions 模块默认会缓存在非 bootclasspath 系统类加载器中,这样一来,由于在应用启动时会将该模块加载到内存中,因此性能不会受到任何影响。在客户端和服务器之间执行额外的 IPC 调用时,使用各个模块功能可能会略微影响应用的性能特征。

模块

activity 嵌入

activity 嵌入组件提供了一系列功能,使应用能够在父级应用的边界内组织 activity 窗口呈现。这包括在多窗格布局中同时并排显示两个 activity,以便旧应用针对大屏设备进行优化。

activity 嵌入组件必须能在内置大小等于或大于 sw600 dp 的显示屏的所有设备上可用。 此外,在支持外接显示屏的设备上,还必须启用 activity 嵌入,因为如果在运行时连接了外部显示屏,应用可能会以较大的尺寸显示。

设备配置

扩展模块分发部分所述,除了启用扩展模块之外,无需特定的设备配置。最好在支持多窗口模式的所有设备上启用扩展。未来的 Android 版本可能需要在常见手持式设备和大屏设备配置中使用扩展。

窗口布局信息

当合页跨越某个应用窗口时,窗口布局信息组件会识别合页在可折叠设备上的位置和状态。借助窗口布局信息,应用可以在可折叠设备的桌面模式下响应和显示经过优化的布局。如需了解使用情况详情,请参阅让应用具备折叠感知能力

如果可折叠 Android 设备包含用于连接单独或连续显示面板区域的合页,则必须通过 WindowLayoutComponent 向应用提供合页的相关信息。

必须相对于由传递到 API 的 Context 所标识的应用窗口,报告合页位置和边界。如果应用窗口边界未与合页边界相交,则不必报告合页 DisplayFeature。如果无法可靠地报告位置(例如,当用户在多窗口模式或兼容信箱模式下自由移动应用窗口时),不报告显示功能也可以接受。

对于折叠功能,当合页位置在稳定状态之间切换时,必须报告状态更新。默认情况下,当显示屏处于平展状态时,API 必须报告 FoldingFeature.State.FLAT。如果设备硬件状态稳定,可处于半折叠模式,则 API 必须报告 FoldingFeature.State.HALF_OPENED。API 中没有闭合状态,因为在这种情况下,应用窗口不可见,也不会跨越合页边界。

设备配置

为支持折叠功能实现,OEM 必须执行以下操作:

  • device_state_configuration.xml 中配置设备状态,以供 DeviceStateManagerService 使用。如需查看参考信息,请参阅 DeviceStateProviderImpl.java

    如果 DeviceStateProviderDeviceStatePolicy 的默认实现不适用于设备,请改用自定义实现。

  • 扩展模块分发部分所述,启用扩展模块。

  • com.android.internal.R.string.config_display_features 字符串资源(通常在设备叠加层的 frameworks/base/core/res/res/values/config.xml 中)中指定显示功能的位置。

    字符串的预期格式为:

    <type>-[<left>,<top>,<right>,<bottom>]

    type 可为 foldhingelefttoprightbottom 的值是屏幕坐标空间中自然屏幕方向下的整数像素坐标。配置字符串可以包含多个显示功能,各功能之间用英文分号分隔。

    例如:

    <!-- Jetpack WindowManager display features -->
    <string name="config_display_features" translatable="false">fold-[1000,0,1000,2000]</string>
    
  • 定义 DeviceStateManager 中使用的内部设备状态标识符与 com.android.internal.R.array.config_device_state_postures 中发送给开发者的公开状态常量之间的映射。

    每个条目的预期格式为:

    <device_specific_state_identifier>:<Jetpack WindowManager state identifier>

    支持的状态标识符包括:

    • COMMON_STATE_NO_FOLDING_FEATURES = 1:没有折叠功能,无法报告状态。例如,它可能是典型的向内折叠设备的闭合状态,其中主屏位于内侧。
    • COMMON_STATE_HALF_OPENED = 2:折叠功能是半开的。
    • COMMON_STATE_FLAT = 3:折叠功能是平展的。例如,它可能是典型的向内折叠设备的展开状态,其中主屏位于内侧。
    • COMMON_STATE_USE_BASE_STATE = 1000:在 Android 14 中,如果合页状态是根据基本状态派生而来的,该值可用于表示模拟状态,正如 CommonFoldingFeature.java 中所定义

    如需了解详情,请参阅 DeviceStateManager.DeviceStateCallback#onBaseStateChanged(int)

    例如:

    <!-- Map of System DeviceState supplied by DeviceStateManager to WindowManager posture.-->
    <string-array name="config_device_state_postures" translatable="false">
        <item>0:1</item>    <!-- CLOSED       : COMMON_STATE_NO_FOLDING_FEATURES -->
        <item>1:2</item>    <!-- HALF_OPENED  : COMMON_STATE_HALF_OPENED -->
        <item>2:3</item>    <!-- OPENED       : COMMON_STATE_FLAT -->
        <item>3:1</item>    <!-- REAR_DISPLAY : COMMON_STATE_NO_FOLDING_FEATURES -->
        <item>4:1000</item> <!-- CONCURRENT   : COMMON_STATE_USE_BASE_STATE -->
    </string-array>
    

窗口区域

窗口区域组件提供了一系列功能,让应用可在某些可折叠设备和多显示屏设备上访问额外的显示屏和显示区域。

后置显示模式可让应用在可折叠设备的外屏上显示相机预览界面,从而支持您使用主设备相机自拍和拍摄视频。如果设备具有与 Android 兼容(由 Android CDD 根据尺寸、密度和可用导航可供性等属性定义)的外屏(可与后置设备的摄像头对齐),则必须提供对后置屏幕模式的访问权限。

在 Android 14 中,采用双屏模式时,在可折叠设备的内屏上运行的应用能够在面向其他用户的外屏上显示额外的内容;例如,外屏可以向拍摄或录制对象显示相机预览。

设备配置

为支持折叠功能实现,OEM 必须执行以下操作:

  • device_state_configuration.xml 中配置设备状态,以供 DeviceStateManagerService 使用。如需了解详情,请访问 DeviceStateProviderImpl.java

    如果 DeviceStateProviderDeviceStatePolicy 的默认实现不适用于设备,请改用自定义实现。

  • 对于支持展开或平展模式的可折叠设备,请在 com.android.internal.R.array.config_openDeviceStates 中指定相应的状态标识符。

  • 对于支持折叠状态的向内折叠设备,请在 com.android.internal.R.array.config_foldedDeviceStates 中列出相应的状态标识符。

  • 对于支持半折叠状态的向内折叠设备(合页像笔记本电脑一样处于半开状态),请在 com.android.internal.R.array.config_halfFoldedDeviceStates 中列出相应的状态。

  • 对于支持后置显示模式的设备,请执行以下操作:

    • DeviceStateManagercom.android.internal.R.array.config_rearDisplayDeviceStates 中列出相应的状态。
    • com.android.internal.R.string.config_rearDisplayPhysicalAddress 中指定后置显示屏的实际显示地址。
    • com.android.internal.R.integer.config_deviceStateRearDisplay 中指定状态标识符,以供扩展使用。
    • com.android.internal.R.array.config_deviceStatesAvailableForAppRequests 中添加状态标识符,使其可用于应用。
  • 在 Android 14 中,对于支持双屏(并发)显示模式的设备:

    • com.android.internal.R.bool.config_supportsConcurrentInternalDisplays 设为 true
    • com.android.internal.R.config_deviceStateConcurrentRearDisplay 中指定后置显示屏的实际显示地址。
    • 指定 com.android.internal.R.integer.config_deviceStateConcurrentRearDisplay 中供扩展程序使用的状态标识符(如果标识符适用于应用)。
    • com.android.internal.R.array.config_deviceStatesAvailableForAppRequests 中添加状态标识符,使其可用于应用。

验证

原始设备制造商 (OEM) 必须验证其实现情况,以确保在常见场景中可以实现预期行为。CTS 测试以及使用 Jetpack WindowManager 的测试可供 OEM 用于测试实现。

CTS 测试

如需运行 CTS 测试,请参阅运行 CTS 测试。与 Jetpack WindowManager 相关的 CTS 测试位于 cts/tests/framework/base/windowmanager/jetpack/ 下。 测试模块的名称为 CtsWindowManagerJetpackTestCases

WindowManager 测试

如需下载 Jetpack WindowManager 测试,请按照 Android Jetpack 说明操作。 这些测试位于 window:window 模块下的窗口库中:window/window/src/androidTest/

如需从命令行运行 window:window 模块的设备测试,请执行以下操作:

  1. 插接启用了开发者选项和 USB 调试的设备。
  2. 允许计算机调试设备。
  3. 在 Androidx 库的根目录中打开 shell。
  4. 切换到 framework/support 目录。
  5. 运行以下命令:./gradlew window:window:connectedAndroidTest
  6. 分析结果。

如需从 Android Studio 运行测试,请执行以下操作:

  1. 打开 Android Studio。
  2. 插接启用了开发者选项和 USB 调试的设备。
  3. 允许计算机调试设备。
  4. 转到窗口模块的窗口库中的测试。
  5. 打开测试类,然后使用编辑器右侧的绿色箭头运行它。

或者,您也可以在 Android Studio 中创建配置,以运行测试方法、测试类或模块中的所有测试。

您可以通过查看 shell 的输出,来手动分析结果。如果设备不符合某些假设,会跳过部分测试。结果会保存在某个标准位置,分析人员可以编写脚本来自动分析结果。