主要内容来自Source Android的主题内容显示篇https://source.android.com/docs/core/display?hl=zh-cn
关键字:AOSP、Source、核心主题、显示、Android屏幕、主副屏、折叠屏
00. 总览
Launcher3:
- 从Launcher3开始就支持带有遮罩的自适应图标
Android7:
- Android 7.0 及更高版本中,设备可以使用多窗口模式同时显示多个应用
- Android 7.1.1 及更高版本支持使用圆形启动器图标。默认情况下,系统不会启用圆形启动器图标。
Android8:
- 开始支持画中画模式,画中画通常用户视频预览等业务
- Android 8.0 通过优化分屏功能并为其添加更多功能来改进分屏模式。 在默认实现中,如果用户在进入分屏模式后点按主屏幕,则系统会压缩顶部窗格,并调整启动器的大小。/platform/packages/apps/Launcher3/ 中的 Launcher3 代码中有这项新功能的参考实现。
- Android 8.1 对演示模式支持进行了修订,以通过 DevicePolicyManager createAndManageUser API 创建演示用户。这样一来,系统便可以针对演示设备上的用户管理和设备政策管理,对标准演示模式进行更灵活的 OEM 自定义
Android9:
- Android 9 新增了对在设备上实现不同类型刘海屏的支持。通过刘海屏,您可以打造沉浸式全面屏体验,同时继续在设备前端为重要传感器留出空间。
- 当用户打开、关闭应用或在应用之间切换时,SystemUI 或启动器(主屏幕)进程会发送逐帧控制动画的请求,同时保证在视图动画和窗口动画之间进行同步。
Android10:
- Android 10 推出了 COLOR_DISPLAY_SERVICE 系统服务,具备系统 API surface,使系统、“设置”和系统界面能够更好地控制所有颜色转换(包括护眼模式)
- 在 Android 10 之前,Activity 也可以在 PAUSED 状态下接收输入
- 以 Android 10 为目标平台的应用可支持同时恢复多个 Activity(处于 RESUMED 状态)
- 除了现有的 CameraManager#AvailabilityCallback#onCameraAvailable() 回调之外,Android 10 还添加了 CameraManager#AvailabilityCallback#onCameraAccessPrioritiesChanged(),它涵盖了焦点(以及相机优先使用权)在处于 RESUMED 状态的多个 Activity 之间切换的情况。应用开发者应同时使用这两个回调来确定尝试访问相机的适当时机。
- 在 Android 10 中,锁定屏幕扩展到所有公共辅助显示屏。锁定屏幕仍然很简单,但不支持从辅助屏幕解锁。
Android11:
- Android 11 引入了新的系统基元,即 Conversation,通过 Sharesheet(已在 Android 10 中推出)在系统中的应用之间分享对话数据,用于驱动对话泡,参与通知栏顶部的新对话空间,用于创建对话微件(在 Android 12 中实现)
- 在 Android 11 中,启动期间报告的第一个屏幕是主屏幕。这与连接类型是内部还是外部并不相关。不过,主屏幕是不能断开连接的,由此可见,实际操作中的主屏幕必须是内部屏幕。请注意,一些可折叠手机有多个内部屏幕。
- Android 11 引入了 ExtServices 模块中文本分类器服务的可更新默认实现。
Android12:
- Android 12 中,公共 API 可用于实现窗口模糊处理效果(例如背景模糊处理和模糊处理后方屏幕),即高斯模糊。
- Material You 动态配色,Material3的UI组件可自动实现动态配色
- Android 12 中,原始设备制造商 (OEM) 和合作伙伴无需执行任何操作,即可实现局部屏幕放大功能。此功能默认处于启用状态
- Android 12 中引入的局部屏幕放大功能为弱视用户提供了经过改进的视图选项。
- Android12引入 SplashScreen API,实现应用冷启动动画
Android13:
- Android 13 开始,系统支持六种不同的主题样式,并且动态配色算法存在各种变体,以满足开发者需求和现实所需的对比度
- Android 13 中的通知采用“选择启用”模式,这与旧版 Android 不同,旧版 Android 采用的是“选择停用”模式
- 从 Android 13 开始,系统界面中的媒体控件包含对操作按钮和远程播放的更新
- 从 Android 13 开始,Android 能够根据设备状态(例如折叠、展开或半折叠 [桌面模式])自定义自动旋转设置。
Android14:
- 在 Android 14 中,采用双屏模式时,在可折叠设备的内屏上运行的应用能够在面向其他用户的外屏上显示额外的内容;例如,外屏可以向拍摄或录制对象显示相机预览。
Android15:
- 支持桌面窗口化
Android16:
- 从 Android 16-QPR1 版本开始,系统提供了一种基于设备状态的自动旋转重构实现。本指南引用了此重构后的代码,因为早期版本存在一个已知问题,即设置值可能会在没有用户互动的情况下发生变化。
01. 多屏幕
11. 推荐做法
限制屏幕访问
可以使用 Display#FLAG_PRIVATE 标志将屏幕标记为“不公开”,这样做会限制除所有者之外的所有人向此类屏幕添加内容。针对虚拟屏幕增加了更多限制,因为任何应用都可以创建虚拟屏幕,而不让用户看见。如果虚拟屏幕不归系统所有,则只有具备 [allowEmbedded](https://developer.android.com/guide/topics/manifest/activity-element?hl=zh-cn#embedded) 属性的 Activity 才能访问该屏幕,并且其调用者应具有 ACTIVITY_EMBEDDING 权限。
要有条件地控制 activity 启动,请使用 LaunchParamsController,它会拦截所有 activity 启动,并允许系统组件修改在启动时使用的参数。此功能可在 system_server 中找到。
配置屏幕窗口设置和系统装饰
可在 DisplayWindowSettings 中配置每个屏幕的系统装饰。设备实现可以在 /data/system/display_settings.xml 中提供默认配置。
此值决定是否要在屏幕上显示系统装饰(启动器、壁纸、导航栏和其他装饰窗口)和 IME。 如需了解详情,请参阅 DisplayWindowSettings#shouldShowSystemDecorsLocked() 和 DisplayWindowSettings#shouldShowImeLocked()。
要识别屏幕,请使用唯一 ID(这默认使用 DisplayInfo#uniqueId)或硬件屏幕的物理端口 ID(请参阅 DisplayInfo#address)。
12. activity 启动政策
- 应用使用 ActivityOption#setLaunchDisplayId(int) 可将特定屏幕指定为 activity 启动的目标
- Android 10 包含 ActivityManager#isActivityStartAllowedOnDisplay(Context context, int displayId, Intent intent) 方法,用于先检查应用的安全限制,然后再尝试在屏幕上启动。
13. 显示屏支持
调整 activity 和屏幕的尺寸
在 Android 7(及更高版本)中,您可以将应用设置为 resizeableActivity=false,使其始终在全屏模式下运行。
Android 10 支持新的宽高比,既包括高宽高比的长屏幕和薄屏幕,也包括 1:1 的屏幕。应用可以定义自身能够处理的屏幕的 [ApplicationInfo#maxAspectRatio](https://developer.android.com/guide/topics/manifest/activity-element?hl=zh-cn#maxaspectratio) 和 ApplicationInfo#minAspectRatio。

多屏幕支持
Android 10 更改了 DisplayInfo#uniqueId,以添加稳定的标识符并区分本地、网络和虚拟屏幕。
Android 10 还提供了一种获取端口信息的便捷方法 (Physical#getPort())。您可以在框架中使用此方法来静态标识屏幕。例如,该方法在 DisplayWindowSettings 中使用。DisplayAddress.Network 包含 MAC 地址,可以使用 DisplayAddress#fromMacAddress() 进行创建。
$ dumpsys SurfaceFlinger --display-id
# Example output.
Display 21691504607621632 (HWC display 0): port=0 pnpId=SHP displayName="LQ123P1JX32"
Display 9834494747159041 (HWC display 2): port=1 pnpId=HWP displayName="HP Z24i"
Display 1886279400700944 (HWC display 1): port=2 pnpId=AUS displayName="ASUS MB16AP"
注意:不支持按屏幕进行 VSYNC。所有屏幕均由主内部屏幕的 VSYNC 信号驱动。
每屏幕焦点
使用 com.android.internal.R.bool.config_perDisplayFocusEnabled 设置每屏幕焦点。
为了同时支持多个以单个屏幕为目标的输入源,可以将 Android 10 配置为支持多个聚焦窗口,每个屏幕最多支持一个。当多个用户同时与同一设备交互并使用不同的输入方法或设备(例如 Android Automotive)时,此功能仅适用于特殊类型的设备。
强烈建议不要为常规设备启用此功能,包括跨屏设备或用于类似桌面设备体验的设备。这主要是出于安全方面的考虑,因为这样做可能会导致用户不确定哪个窗口具有输入焦点。
14. 系统装饰支持
系统装饰 Decor
Android 10 增加了对于配置辅助屏幕的支持,以显示特定的系统装饰(例如壁纸、导航栏和启动器)。默认情况下,主屏幕会显示所有系统装饰项,而辅助屏幕会显示选择性启用的装饰项。对输入法 (IME) 的支持可以与其他系统装饰项分开设置。
使用 DisplayWindowSettings#setShouldShowSystemDecorsLocked() 在特定屏幕上添加对系统装饰的支持,或在 /data/system/display_settings.xml 中提供默认值。如需查看相关示例,请参阅屏幕窗口设置。
启动器 Launcher
在 Android 10 中,每个配置为支持系统装饰的屏幕,默认情况下都有一个专用于启动器 activity 的主屏幕堆栈,该堆栈的类型为 WindowConfiguration#ACTIVITY_TYPE_HOME。每个屏幕使用一个单独的启动器 activity 实例。
大多数现有的启动器都不支持多个实例,也没有针对大屏幕尺寸进行过优化。此外,在辅助/外部屏幕上通常需要不同类型的体验。为了提供针对辅助屏幕的专用 activity,Android 10 在 intent 过滤器中引入了 SECONDARY_HOME 类别。此 activity 的实例将在支持系统装饰的所有屏幕上使用,每个屏幕对应一个实例。
壁纸
开发者可以通过在 WallpaperInfo XML 定义中提供 android:supportsMultipleDisplays="true" 来声明对壁纸功能的支持。壁纸开发者还可以使用 WallpaperService.Engine#getDisplayContext() 中的显示上下文来加载素材资源。
框架会为每个屏幕创建一个 WallpaperService.Engine 实例,因此每个引擎都有自己的 surface 和显示上下文。开发者需要确保每个引擎都能够根据 VSYNC 以不同的帧频独立绘制。
在 Android 10 中,IWallpaperConnection#attachEngine() 和 IWallpaperService#attach() 接口接受 displayId 参数来创建与每个屏幕之间的连接。 WallpaperManagerService.DisplayConnector 封装了每个屏幕的壁纸引擎和连接。在 WindowManager 中,会在构建时为每个 DisplayContent 对象创建壁纸控制器,而不是为所有屏幕创建一个 WallpaperController。
15. 输入法
为了实现在屏幕之间切换 IME 窗口,Android 10 实现了以下功能:
现在,可以在 DisplayContent#mInputMethodWindow 和 DisplayContent#mInputMethodTarget 中跟踪每个屏幕的 IME 和输入目标窗口,以便 WindowManager (WM) 可以单独管理每个屏幕的 IME 焦点状态。
在 IMMS 端,当通过 ViewRootImpl#handleWindowFocusChanged -> InputMethodManager#onPostWindowFocus -> IMMS#startInputOrWindowGainedFocus 收到来自外部屏幕的应用客户端焦点请求时,它会先取消绑定当前的输入法服务,然后再重新绑定该服务,以在 onServiceConnected() 中重新附加针对该外部屏幕的新 IME 窗口令牌。
在 IMS 端,收到 IMS#attachToken 后,将触发以下流程:
调用 ContextImpl#updateDisplay,以在 InputMethodService#attachToken() 中更新服务上下文的屏幕。这会调用 ViewGroup#addView() 来调整键盘布局并适应检查当前上下文的目标屏幕。
调用 DisplayContent#setInputMethodWindowLocked() 之后,该实现使用 WindowProcessController 将进程级屏幕配置更改发送给 IME 进程,以替换资源和屏幕指标。
调用 onConfigurationChanged() 和 ViewGroup#addView() 之后,InputMethodService 客户端将获得合适的配置(其中包含正确的屏幕指标)来重新初始化输入视图。
16. 输入路由
Android 10 增加了一种机制来指定哪些输入设备属于哪些屏幕。这种关联由端口号完成,其中端口是指与屏幕连接的物理端口。
例如,如果 Android 设备有两个标记为 hdmi1 和 hdmi2 的 HDMI 端口,则屏幕端口值可以为 1 和 2。即使将不同的屏幕(例如不同的屏幕型号或制造商)连接到同一物理 HDMI 端口,端口值也保持不变。这样一来,设备制造商就能够提供组装和升级屏幕的说明。
这种关联在 /vendor/etc/input-port-associations.xml 中配置。例如:
<ports>
<port display="0" input="usb-xhci-hcd.0.auto-1.1/input0" />
<port display="1" input="usb-xhci-hcd.0.auto-1.2/input0" />
</ports>
在上面的示例中,display="0" 指定与屏幕连接的端口。input="usb-xhci-hcd.0.auto-1.1/input0" 指定与输入设备连接的端口。如需确定与特定设备关联的端口,请使用以下终端命令,然后在 Event Hub 状态中查看这些设备的 location 属性。
adb shell dumpsys input
如果连接了很多设备,请点按特定设备,以在 Input Dispatcher 状态中检查 RecentQueue 数组。然后,您可以确定生成最新事件的设备。之后,您可以在 Event Hub 状态中找到相应的设备。
如需确定分配给连接的屏幕的屏幕端口,请使用 adb shell dumpsys display,然后在“Display Devices”下针对每个屏幕查找 DisplayDeviceInfo 的 address 属性。或者,使用 adb shell dumpsys SurfaceFlinger --display-id 转储所有已连接屏幕的标识信息。另请参阅静态屏幕标识符。
如果为特定输入设备指定关联,并且系统中不存在相应的屏幕,则该输入设备会被禁用,直到出现相应的屏幕为止。这种关联仅对触摸屏设备执行。
17. 通知历史记录
以下是这些通知历史记录界面组件的可用参考实现:
设置: packages/apps/Settings/src/com/android/settings/notification/history
系统服务器: com.android.server.notification.NotificationHistory.*.java
您可以使用 NotificationHistoryDatabase 类中的 HISTORY_RETENTION_DAYS 常量设置通知在通知历史记录界面中显示的天数。此外,您还可以修改通知历史记录界面中显示的内容区以及数据的呈现方式。
默认的通知历史记录保留期限为 24 小时。
针对代码的每个组件提供以下单元测试:
系统服务器单元测试:FrameworksUiServicesTests
设置单元测试:make -j64 RunSettingsRoboTests ROBOTEST_FILTER="com.android.settings.notification"
02. 演示模式
零售演示模式如何实现数据自动清理的呢?Android11上要启用该如何操作
概览
- 零售演示模式的“数据自动清理”核心思路是把顾客所处的环境放在一个专用“演示用户”下,并在空闲或定期触发时直接删除该演示用户并重新创建一个全新的演示用户。从而彻底清除该用户下所有应用数据、设置、下载与媒体文件,再把预置的演示内容重新投放进去。
- 在 Android 11 上,这一能力仍受支持,但启用与清理策略属于系统/OEM 定制范畴。普通商用固件不会暴露开关,只有系统签名组件与系统服务能创建/删除演示用户并实施策略。
数据自动清理是如何实现的
- 专用“演示用户”隔离:
- 演示模式下,设备切换到一个被标记为 Demo 的用户(系统内部为 demo flag),普通用户操作都在该用户空间内进行。
- 通过用户限制(UserManager 的各类 DISALLOW_*)禁用添加账号、安装 App、修改关键设置、USB 传输、开发者选项等,减少可变性与隐私风险。
- 重置策略(自愈):
- 触发条件通常为“长时间空闲”“夜间维护时段”“设备重启后”“店员手动触发”等,具体由 OEM 配置。
- 重置动作的可靠做法是“删除并重建演示用户”:
- 切回系统/管理员用户 → 删除当前演示用户 → 重新创建新的演示用户(可选设为临时/ephemeral) → 投放演示内容 → 切换进入新演示用户。
- 这种做法覆盖所有应用私有目录和媒体存储,避免遗漏比“逐个清理 App 数据”更稳妥。
- 有的实现会在短间隔内执行“增量清理”(清理非白名单应用数据、清除最近任务),但最终的每日或重启清理仍以“重建用户”为主。
- 内容恢复与白名单:
- 演示素材放在只读分区或系统拥有目录(例如 product/vendor/system 的只读资源,或系统持有的数据目录),重置后由系统/特权 App复制到新用户空间。
- 少数核心演示组件(如演示控制 App、播放器)属于白名单,不被清理或在重置后立即重新部署。
在 Android 11 上启用的大致做法(面向 OEM/系统集成)
- 前提与权限
- 需要平台签名组件与系统服务改动;普通第三方 App或用户无法启用。
- 多用户必须可用;Setup Wizard/OOBE 流程需支持进入演示路径。
- 典型集成步骤(方向性指南,具体以你所用分支/OEM规范为准)
- 准备演示资源与控制组件
- 预置演示内容(图片/视频/脚本)到只读分区或系统持有目录。
- 提供平台签名的“演示控制”组件,完成投放、守护与与系统服务交互(监测空闲、触发重置、白名单管理)。
- 在首次开机流程(Setup Wizard)分支到“零售演示”
- 检测门店机标记(构建变量、系统属性、渠道配置或隐藏入口),创建演示用户并切换进入。
- 对演示用户设置必要的用户限制(示例:DISALLOW_ADD_USER、DISALLOW_FACTORY_RESET、DISALLOW_INSTALL_APPS、DISALLOW_MODIFY_ACCOUNTS、DISALLOW_USB_FILE_TRANSFER、DISALLOW_DEBUGGING_FEATURES、必要时 DISALLOW_CONFIG_WIFI/BT 等)。
- 实现自动清理与重置逻辑
- 系统服务或特权 App 维护空闲计时/夜间 Alarm,满足条件后执行重置:
- 切回系统/管理员用户
- 移除演示用户(UserManager.removeUser)
- 重新创建演示用户(可选加“临时/ephemeral”属性,方便在登出/重启时自动移除)
- 重新投放演示内容并应用限制
- 切换进入新演示用户
- 根据需要增加“增量清理”(清理非白名单包数据、清理最近任务)以缩短间隔中的恢复时间。
- 系统服务或特权 App 维护空闲计时/夜间 Alarm,满足条件后执行重置:
- UI/维护入口
- 为店员提供隐秘/受控的维护入口(密码、NFC 工具或特定手势)以触发立即重置或退出演示模式(若你的产品允许)。
- 合规与验证
- 验证个人数据不会跨重置保留;测试账户添加/支付/下载路径均被禁止。
- 评估功耗与屏幕常亮策略;避免影响热与寿命。
- 准备演示资源与控制组件
系统侧实现要点(伪代码示例,系统权限)
- 创建演示用户并切换
- UserInfo demo = mUserManager.createUser("Demo", flags_for_demo | flags_for_ephemeral);
- applyUserRestrictions(demo.id, demo_restrictions);
- seedDemoContent(demo.id);
- mActivityManager.switchUser(demo.id);
- 自动重置
- mActivityManager.switchUser(UserHandle.SYSTEM);
- mUserManager.removeUser(demo.id);
- UserInfo newDemo = mUserManager.createUser("Demo", flags_for_demo | flags_for_ephemeral);
- seedDemoContent(newDemo.id);
- applyUserRestrictions(newDemo.id);
- mActivityManager.switchUser(newDemo.id);
如何在你的代码树中落地与排查
- 在 AOSP 里查找零售演示相关服务与配置点:
- 在 frameworks/base 下搜索 “retaildemo”“Demo user”“isDemoUser” 等关键字,了解系统服务与资源开关。
- UserManager 提供 isDemoUser() 供 App 检测;系统服务内部持有 Demo 用户的标记与管理逻辑。
- 演示模式是否启用通常由 OEM 的 overlay/属性与 SUW 流控制;不同分支命名与开关不完全一致,建议在你的版本用 grep 全树定位后按分支规范集成。
- 验证方法:
- 在工程/测试构建(userdebug/eng)下,通过日志与 dumpsys user 查看当前用户是否带 demo 标记;观察空闲后是否触发重置流程。
- 普通 user 构建与量产机通常不会暴露任何开关或命令。
若无法使用零售演示模式
- 可采用企业设备管理替代(Device Owner + Lock Task/Kiosk)。它不能自动“重建用户”但能限制操作、定期清理应用数据、保持展示状态;适合你不做系统改动或没有平台签名权限的场景。
注意
- 激活 RDM 的入口、白名单、重置时机等常由 OEM/GMS 渠道文档规定,很多细节不公开;如无权或无文档,不建议尝试在普通设备启用。
- 演示模式的退出路径要在设计时确定(隐藏口令、工厂工具或刷机),避免门店误锁死设备。
03. 文本分类器
Android 11 引入了 ExtServices 模块中文本分类器服务的可更新默认实现。在搭载 Android 11 或更高版本的设备上,getTextClassifier() 方法会返回 ExtServices 模块中的此默认实现。建议设备制造商使用此 TextClassifierService 实现,因为它可以通过 Mainline OTA 更新进行更新。
Android 11 还移除了之前在 Android 8.1 中引入的本地文本分类器默认实现。因此,getLocalTextClassifier() 会返回 NO_OP 文本分类器。您应该使用 getDefaultTextClassifierImplementation() 方法,而不是本地实现。
如果设备制造商希望使用自己的文本分类算法,他们可以通过在 config.xml 文件中指定 config_defaultTextClassifierPackage 来实现自定义文本分类器服务。如果未指定此配置,则会使用默认的系统实现。自定义实现可以通过调用 TextClassifierService.getDefaultTextClassifierImplementation(Context) 来获取默认实现的实例。如需了解详情,请参阅实现自定义文本分类器服务。
测试
如需验证文本分类器服务的实现,请使用 platform/cts/tests/tests/textclassifier/ 中的兼容性测试套件 (CTS) 测试。
04. HRD和SDR
混合 SDR 和 HDR 内容组合功能可根据内置屏幕设备特性进行配置,以便在电池续航时间、烧屏和内容保真度之间权衡取舍。
调暗 SDR 图片可能会导致 black crush,或原始图片的较暗区域出现信息丢失。这是因为较深颜色值收合在一组较小的深色代码上。
如果调暗会导致不可接受的 black crush,相应的实现过程必须实现抖动算法,这种算法会将噪声注入最终图片中,以便减少条带效果。
如果 HWC 实现无法在颜色流水线中的适当位置抖动图片,则必须请求 SurfaceFlinger 在 GPU 上应用调暗和抖动。
实现还可以调整 sdrHdrRatioMap 的值以限制 SDR 元素的调暗程度。调暗到极低的亮度需要使用 GPU,这样可以提高图片质量,但可能会缩短电池续航时间
通过adb shell dumpsys SurfaceFlinger或adb shell dumpsys display可以了解设备当前的HDR/SDR配置情况。
05. 系统界面中的媒体控件
为了确保用户可以使用众多媒体控件来操控媒体播放应用,Android 13 媒体控件上的操作按钮衍生自 PlaybackState 操作状态。 此次更改后,函数 MediaDataManager#createActionsFromState 会根据 PlaybackState 操作状态来生成操作按钮信息。相比之下,在 Android 12 中,媒体控件上的操作按钮由添加到 MediaStyle 通知的通知操作决定。MediaStyle 是专为“媒体播放”定制的通知样式。它的核心作用不是仅仅“放几个按钮”,而是把这条通知与应用的 MediaSession 绑定,让系统把它识别为媒体通知,并在各处(锁屏、通知栏、快捷设置媒体卡片、音量面板等)以统一的媒体控件展示与控制。
远程播放 API
为了在各种平台上提供一致的媒体体验,从 Android 13 开始,添加了新的系统 API Notification#setRemotePlaybackInfo,用于在媒体控件系统界面中标记媒体通知以进行远程播放。
Notification#setRemotePlaybackInfo 是 Android 13(API 33)新增的系统接口(@SystemApi),用于给“媒体类通知”附带“远端播放信息”。它让系统 UI/媒体控制条知道这条通知所控制的播放发生在远端设备(如 Cast 设备、外接音箱、电视),从而显示“正在某设备上播放”、提供合适的设备切换/音量控制等体验。该接口仅面向系统应用,普通三方应用不应直接使用
06. WindowManager 扩展
借助 Jetpack WindowManager 库,应用开发者可为新的设备规格和多窗口环境提供支持。
WindowManager 扩展(简称“扩展”)是一个可选择启用的 Android 平台模块,支持各种 Jetpack WindowManager 功能。该模块在 AOSP 中的 frameworks/base/libs/WindowManager/Jetpack 中实现,并搭载在支持 WindowManager 功能的设备上。

Jetpack WindowManager(androidx.window)主要是给应用提供跨版本一致的“窗口与折叠设备适配”能力,帮助 app 在大屏、可折叠、可自由调整窗口大小的设备上自适应布局与行为。它不是系统的 WindowManager 服务,而是面向应用的兼容层与工具集。