AOSP 13 分屏源码分析
AOSP 13 分屏源码分析本文档基于 AOSP 13 源码梳理系统级分屏Split Screen的架构、核心类、进入/退出流程及调试方法。1. 概述AOSP 13 的分屏实现已从传统 SystemUI View 迁移到WM ShellWindowManager Shell。SystemUI托管 Shell 进程、桥接 Launcher不包含分屏核心 UI 逻辑WM ShellStage 管理、分割线、窗口 bounds、过渡动画Launcher3 Quickstep分屏选择 UI、动画、跨进程调用 Shellsystem_serverTask 树、WINDOWING_MODE_MULTI_WINDOW、应用WindowContainerTransaction注意SystemUI 中的SplitShade*、SplitClockView是通知栏分屏布局与多窗口分屏无关。WindowManager/Jetpack/下的SplitPairRule属于Activity Embedding应用内分屏与系统分屏是两套机制。2. 整体架构system_serverWM ShellSystemUILauncher3 Quickstep用户触发ISplitScreen AIDLWindowContainerTransaction最近任务、长按图标Taskbar 拖拽键盘快捷键RecentsViewSplitSelectStateControllerSystemUiProxySystemUIServiceWMShellOverviewProxyServiceSplitScreenControllerStageCoordinatorMainStage SideStageSplitLayout DividerViewTaskOrganizerControllerWindowOrganizerController层级职责Launcher3分屏选择 UI、动画、调用ISplitScreen.startTasks()SystemUI启动 WM Shell把ISplitScreenBinder 传给 LauncherWM ShellStage 管理、分割线、窗口 bounds、过渡动画system_serverTask 树、WINDOWING_MODE_MULTI_WINDOW、应用 WCT3. 核心目录路径内容frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/分屏核心逻辑frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/分割线、布局计算frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/拖拽进入分屏packages/apps/Launcher3/quickstep/最近任务分屏 UI 与状态机frameworks/base/services/core/java/com/android/server/wm/Task/Window 策略frameworks/base/packages/SystemUI/src/com/android/systemui/wmshell/Shell 生命周期托管4. Task 层级模型StageCoordinator定义了分屏的核心规则SideStage 有子任务→ 分屏才算激活MainStage 有子任务→ 仅在 Coordinator 激活时MainStage 与 SideStage 都可见→ 分割线才显示两个 Stage 放在同一个single-top root task下实际窗口树结构Display └── Split Root Task (single-top, mRootTaskInfo) ├── MainStage root (WINDOWING_MODE_MULTI_WINDOW) ← 默认启动目标 │ └── App Task ├── SideStage root (WINDOWING_MODE_MULTI_WINDOW) ← 用户显式选中的任务 │ └── App Task └── Divider (TYPE_DOCK_DIVIDER, DividerView)启动时通过ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN指定任务进入哪个 Stage。5. 关键类职责5.1 WM Shell 层类文件职责SplitScreenControllersplitscreen/SplitScreenController.java顶层入口实现ISplitScreenAIDLStageCoordinatorsplitscreen/StageCoordinator.java核心编排器WCT 构建、进入/退出、Stage 协调MainStagesplitscreen/MainStage.java主 Stage默认 launch 目标SideStagesplitscreen/SideStage.java副 Stage用户显式 pin 的任务StageTaskListenersplitscreen/StageTaskListener.java通过ShellTaskOrganizer创建MULTI_WINDOWroot taskSplitLayoutcommon/split/SplitLayout.java计算 bounds、分割线位置、拖拽 dismissDividerViewcommon/split/DividerView.java分割线触摸拖动/双击SplitWindowManagercommon/split/SplitWindowManager.java托管TYPE_DOCK_DIVIDER窗口SplitScreenTransitionssplitscreen/SplitScreenTransitions.java分屏过渡动画DragAndDropControllerdraganddrop/DragAndDropController.java拖拽进入分屏5.2 Launcher 层类文件职责SplitSelectStateControllerutil/SplitSelectStateController.java分屏选择状态机记录第一个/第二个 AppRecentsViewviews/RecentsView.javainitiateSplitSelect()/confirmSplitSelect()SystemUiProxySystemUiProxy.java封装ISplitScreen跨进程调用SplitScreenSelectStateuioverrides/states/SplitScreenSelectState.javaOverview 中选第二个 App 时的 UI 状态SplitShortcut.ktsplitscreen/SplitShortcut.kt桌面/All Apps 长按分屏GroupedTaskViewviews/GroupedTaskView.java重新启动已有分屏对TopTaskTrackerTopTaskTracker.java实现ISplitScreenListener跟踪 Stage 任务5.3 SystemUI 层类文件职责SystemUIServiceSystemUIService.javaSystemUI 进程启动间接启动 WMShellWMShellwmshell/WMShell.javaShell 生命周期桥接唤醒、全屏退出SystemUIInitializerSystemUIInitializer.java构建WMComponent注入 SplitScreen5.4 system_server 层类文件职责TaskOrganizerControllerserver/wm/TaskOrganizerController.javaShell task organizer IPCWindowOrganizerControllerserver/wm/WindowOrganizerController.java应用 WCTreparent、bounds、launchTaskDisplayAreaserver/wm/TaskDisplayArea.java创建 multi-window root taskRecentTasksserver/wm/RecentTasks.java分屏对分组显示在最近任务6. 跨进程 APIISplitScreen.aidlLauncher 与 Shell 通过 AIDL 通信Binder key 为KEY_EXTRA_SHELL_SPLIT_SCREEN。核心方法// 同时启动两个 task 进入分屏onewayvoidstartTasks(inttaskId1,inBundleoptions1,inttaskId2,inBundleoptions2,intsplitPosition,floatsplitRatio,inRemoteTransitionremoteTransition,inInstanceIdinstanceId);// 启动 Intent TaskonewayvoidstartIntentAndTask(inPendingIntentpendingIntent,inBundleoptions1,inttaskId,inBundleoptions2,intsidePosition,floatsplitRatio,inRemoteTransitionremoteTransition,inInstanceIdinstanceId);// 退出分屏onewayvoidexitSplitScreen(inttoTopTaskId);// 注册监听onewayvoidregisterSplitScreenListener(inISplitScreenListenerlistener);文件路径frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl7. 进入分屏流程7.1 触发方式方式入口最近任务菜单TaskShortcutFactory→TaskView.initiateSplitSelect()Overview 卡片 Split 按钮RecentsView.initiateSplitSelect(TaskView)桌面/All Apps 长按SplitShortcut.kt→SplitScreenSelectStateTaskbar 拖拽DragAndDropController→DragAndDropPolicy键盘快捷键SplitWithKeyboardShortcutController重新启动已有分屏对GroupedTaskView.launchTasks()通知拖拽DragAndDropController同一套流程ADB 调试SplitScreenShellCommandHandlercmd splitscreen7.2 两 App 选择流程最常见Step 1 — 选第一个 AppRecentsView.initiateSplitSelect() → SplitSelectStateController.setInitialTaskSelect() → Launcher 进入 SplitScreenSelectState显示第一个 App 占位 UIStep 2 — 选第二个 AppRecentsView.confirmSplitSelect() → SplitSelectStateController.launchSplitTasks() → launchTasks(taskId1, intent1, taskId2, intent2, stagePosition, ...)Step 3 — Launcher → ShellSystemUiProxy.startTasks(taskId1, options1, taskId2, options2, splitPosition, splitRatio, remoteTransition, instanceId) → ISplitScreen.startTasks() [Binder 跨进程]Step 4 — Shell 构建 WCTStageCoordinator.startTasks()核心逻辑setSideStagePosition(splitPosition, wct)— 设置 SideStage 位置上/左 或 下/右第一个 task → SideStageaddActivityOptions(options1, mSideStage)wct.startTask(taskId1, options1)startWithTask()处理第二个 taskmMainStage.activate(wct, false)— 激活 MainStagemSplitLayout.setDivideRatio(splitRatio)— 设置分割比例updateWindowBounds(mSplitLayout, wct)— 计算各 Stage bounds第二个 task → MainStageaddActivityOptions(mainOptions, mMainStage)wct.startTask(mainTaskId, mainOptions)SplitScreenTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_PAIR_OPEN, ...)Step 5 — system_server 应用 WCTWindowOrganizerController.applyTransaction(wct) → Task reparent 到 WINDOWING_MODE_MULTI_WINDOW root → TaskOrganizerController 回调 ShellShellTaskOrganizerStep 6 — 完成进入StageCoordinator.finishEnterSplitScreen()mSplitLayout.init()— 初始化 boundssetDividerVisibility(true, t)— 显示分割线updateSurfaceBounds()— 更新 Surface boundsupdateRecentTasksSplitPair()— 注册分屏对到 RecentTasks7.3 拖拽进入分屏用户拖拽 App 图标 → DragAndDropController 显示 DragLayout分屏区域 → DragAndDropPolicy 解析目标左/右/上/下 → SplitScreenController.startIntent() / startTask() → StageCoordinator.prepareEnterSplitScreen() launch7.4 将已有 Task 移入分屏SplitScreenController.enterSplitScreen(taskId, leftOrTop) → moveToStage() → prepareEnterSplitScreen(wct, taskInfo, startPosition)8. 退出分屏常见退出原因SplitScreenController定义常量含义EXIT_REASON_DRAG_DIVIDER拖动分割线超过阈值 dismiss 一侧EXIT_REASON_RETURN_HOME返回桌面EXIT_REASON_APP_FINISHEDApp 结束EXIT_REASON_DEVICE_FOLDED折叠屏折叠EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOWApp 不支持多窗口EXIT_REASON_CHILD_TASK_ENTER_PIP子任务进入 PiPEXIT_REASON_FULLSCREEN_SHORTCUT全屏快捷键EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP锁屏 show-on-topEXIT_REASON_ROOT_TASK_VANISHEDRoot task 消失9. 类关系图SplitScreen (interface) ↑ implemented by SplitScreenController ├── StageCoordinator (core logic) │ ├── MainStage extends StageTaskListener │ ├── SideStage extends StageTaskListener │ ├── SplitLayout implements SplitLayoutHandler │ │ └── SplitWindowManager → DividerView │ └── SplitScreenTransitions ├── DragAndDropController (drag-to-split) └── ISplitScreenImpl (AIDL stub) StageTaskListener └── ShellTaskOrganizer.createRootTask(MULTI_WINDOW) ↔ TaskOrganizerController (system_server) Launcher side: SplitSelectStateController → SystemUiProxy → ISplitScreen TopTaskTracker extends ISplitScreenListener RecentsView ↔ SplitSelectStateController ↔ SplitScreenSelectState10. 调试方法10.1 ADB 命令adb shell cmd splitscreenhelp10.2 Logcat 过滤adb logcat-sStageCoordinator SplitScreenController SplitSelectStateController10.3 排查优先级问题类型优先查看分屏行为、WCTStageCoordinator.java用户入口、动画SplitSelectStateController.java分割线交互SplitLayout.javaDividerView.javaTask 树策略TaskOrganizerController.java/WindowOrganizerController.javaLauncher 绑定SystemUiProxy.javaTouchInteractionService.java11. 关键源码索引功能文件关键方法启动两个 taskStageCoordinator.javastartTasks()完成进入分屏StageCoordinator.javafinishEnterSplitScreen()准备进入分屏StageCoordinator.javaprepareEnterSplitScreen()Launcher 发起分屏SplitSelectStateController.javalaunchSplitTasks()/launchTasks()跨进程调用SystemUiProxy.javastartTasks()分屏 API 定义ISplitScreen.aidlstartTasks(),exitSplitScreen()布局计算SplitLayout.javainit(),setDivideRatio()分割线 UIDividerView.java触摸 drag / double-tapShell 托管WMShell.javainitSplitScreen()

相关新闻

KV Cache 优化实战:6GB 显存上的每一 MB 都算数

KV Cache 优化实战:6GB 显存上的每一 MB 都算数

副标题: 量化、Flash Attention、模型架构——实测 6 种配置,告诉你 KV Cache 能省多少 日期: 2026年7月1日 一、引子:你每天都在用 KV Cache,但你未必知道 在上一篇博文中,我对比了 Ollama 和 llama.cpp …

2026/7/2 1:28:28阅读更多 →
V93000 WSRF 射频测试验收标准详解

V93000 WSRF 射频测试验收标准详解

V93000 WSRF 射频测试验收标准详解 本文基于 Advantest V93000 WSRF 射频板卡的官方技术规格,结合实际量产测试经验,对 ATE 开发项目中常见的射频精度验收要求进行系统性梳理。 关键词:WSRF、De-embedding、Thru/Open/Short/Load、功率校准、噪声系数、Advantest 一、概述 …

2026/7/2 1:28:28阅读更多 →
Midscene.js深度解析:3大技术突破重构跨平台AI自动化新范式

Midscene.js深度解析:3大技术突破重构跨平台AI自动化新范式

Midscene.js深度解析:3大技术突破重构跨平台AI自动化新范式 【免费下载链接】midscene AI-powered, vision-driven UI automation for every platform. 项目地址: https://gitcode.com/GitHub_Trending/mid/midscene Midscene.js作为一款创新的视觉驱动UI自动…

2026/7/2 1:28:28阅读更多 →
Python异步编程实战技巧全解析

Python异步编程实战技巧全解析

Python异步编程实战技巧全解析在当今高并发的网络应用开发中,异步编程已成为Python开发者必须掌握的核心技能。从传统的回调地狱到现代的async/await语法,Python异步编程经历了革命性的演进。本文将深入解析Python异步编程的实战技巧,帮助开发…

2026/7/2 2:48:33阅读更多 →
Python OpenCV图像识别实践

Python OpenCV图像识别实践

Python OpenCV图像识别实践:从像素到智能的跨越在人工智能浪潮席卷全球的今天,图像识别技术已成为连接数字世界与现实世界的桥梁。而Python与OpenCV的组合,则为这一领域的研究者和开发者提供了一把强大而灵活的工具。本文将深入探讨基于Pytho…

2026/7/2 2:48:33阅读更多 →
MySQL存储过程开发

MySQL存储过程开发

MySQL存储过程开发:从脚本到企业级数据逻辑封装在当今数据驱动的商业环境中,数据库不仅仅是静态存储容器,更是业务逻辑的核心载体。MySQL作为最流行的开源关系型数据库之一,其存储过程功能为企业级应用开发提供了强大的数据逻辑封…

2026/7/2 2:48:33阅读更多 →
React性能优化

React性能优化

React性能优化:构建高效前端应用的实践指南在当今快速发展的Web应用领域,React作为最流行的前端框架之一,其性能优化已成为开发者必须掌握的核心技能。随着应用规模不断扩大,性能问题往往成为制约用户体验的关键因素。本文将深入探…

2026/7/2 2:48:33阅读更多 →
前端工程化构建工具链配置实战教程

前端工程化构建工具链配置实战教程

前端工程化构建工具链配置实战教程前端工程化已成为现代Web开发的标配,它通过自动化流程提升开发效率、保障代码质量。本文将带你从零开始配置一套完整的前端工程化工具链,涵盖开发、构建、测试到部署的全流程。一、环境初始化与包管理首先确保已安装Nod…

2026/7/2 2:48:33阅读更多 →
【JAVA毕设源码分享】基于Web的社交媒体平台的设计与实现(程序+文档+代码讲解+一条龙定制)

【JAVA毕设源码分享】基于Web的社交媒体平台的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/2 2:43:33阅读更多 →
AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

6个月前的2025年12月,Boris Cherny 公开宣布自己卸载了 IDE。一时间,Vibe Coding 成了全行业最热的话题。6个月后,当我们回过头来拉一份真实账本,发现事情远没有"一句话生成一个App"那么浪漫。本文从产品经理和研发两个…

2026/7/1 4:42:14阅读更多 →
审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

引言:审计结束三个月了,审计员的权限还没关某城商行每年按照监管要求开展至少一次数据安全审计。审计期间,内审部门需要抽样检查各类业务数据——交易流水、客户信息、员工操作日志、权限配置记录。这些数据分布在不同系统中,审计…

2026/7/1 5:19:01阅读更多 →
塞尔达传说旷野之息存档修改器:3分钟掌握海拉鲁世界自由定制技巧

塞尔达传说旷野之息存档修改器:3分钟掌握海拉鲁世界自由定制技巧

塞尔达传说旷野之息存档修改器:3分钟掌握海拉鲁世界自由定制技巧 【免费下载链接】BOTW-Save-Editor-GUI A Work in Progress Save Editor for BOTW 项目地址: https://gitcode.com/gh_mirrors/bo/BOTW-Save-Editor-GUI 想在《塞尔达传说:旷野之息…

2026/7/2 0:03:01阅读更多 →
告别 AccessKey:多云平台 CLI OAuth 免密认证完全指南

告别 AccessKey:多云平台 CLI OAuth 免密认证完全指南

在本地开发环境使用云厂商 CLI 时,传统的 AccessKey(AK)方式需要手动创建、下载和保管密钥,不仅繁琐,还存在泄漏风险。其实,主流云平台都已提供基于 OAuth 2.0 的免密认证方案,让开发者可以通过浏览器登录一次性完成授权,CLI 自动管理临时凭证的刷新,兼顾了便利与安全…

2026/7/2 0:03:01阅读更多 →
基于13DOF传感器与PIC32MZ的高精度嵌入式导航系统设计

基于13DOF传感器与PIC32MZ的高精度嵌入式导航系统设计

1. 项目背景与核心价值在嵌入式系统开发领域,高精度定位与导航一直是极具挑战性的技术方向。传统方案往往面临成本、精度和实时性难以兼顾的困境。这个项目通过13DOF(13自由度)传感器组合与PIC32MZ2048EFH100高性能MCU的协同工作,…

2026/7/2 0:03:01阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/2 0:33:58阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/2 1:32:11阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/2 1:50:13阅读更多 →