news 2026/5/14 3:56:10

修复OpenFDE14缩放窗口时标题栏与应用窗口的宽度不同步的问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
修复OpenFDE14缩放窗口时标题栏与应用窗口的宽度不同步的问题

1.问题描述

在OpenFDE 14上缩放应用窗口大小时,会出现标题栏宽度与应用窗口宽度无法保持同步变化的问题,在一些简单布局的应用缩放场景下,同步效果比较好,但对于较复杂布局的应用场景下,不同步的现象就比较明显,如下图所示。

2.原因分析

从Android 14开始,自由窗口模式下缩放窗口,CaptionWindow被放到SystemUI进程中刷新,应用窗口还是在应用进程中刷新,由于CaptionWindow的布局非常简单,只有几个Button控件,所以layout速度非常快,而对于Actvitity来说,会选择合适的时机进行刷新图层信息,因此Activity窗口的刷新频率远远跟不上CaptionWindow的刷新频率,且两者之间没有任何同步机制,所以在拖动时标题栏与Acitivity窗口的宽度就无法保持一致。

既然是由于Activity窗口刷新太慢导致,那么只能让标题栏窗口去同步Activity窗口大小,这样改动带来的副作用是最小的,这里我们从SurfaceFlinger的角度进行分析,因为所有图层都会由SurfaceFlinger提交给hwc显示,那么我们可以在SurfaceFlinger中对标题栏窗口和应用窗口进行一次宽度同步,防止标题栏宽度显示超出应用窗口。

根据dumpsys SurfaceFlinger信息,可以看到应用窗口和标题栏窗口的layer的关系,如下所示。

ROOT ├─ Display 0 name="内置屏幕"#1 │ ├─ WindowedMagnification:0:31#2 │ │ ├─ HideDisplayCutout:0:14#3 │ │ │ └─ OneHanded:0:14#4 │ │ │ ├─ FullscreenMagnification:0:12#5 │ │ │ │ ├─ DefaultTaskDisplayArea#7 │ │ │ │ │ └─ Task=224#326 │ │ │ │ │ ├─ ActivityRecord{bdc594a u0 com.tencen[...]ntv2.activity.MainActivity t224}#339 │ │ │ │ │ │ ├─ 942c0bb ActivityRecordInputSink com.[...]ssistantv2.activity.MainActivity#342 │ │ │ │ │ │ └─ d666f1 com.tencent.android.qqdownloa[...]ssistantv2.activity.MainActivity#343 │ │ │ │ │ │ └─ com.tencent.android.qqdownloader/com[...]ssistantv2.activity.MainActivity#344 │ │ │ │ │ └─ Decor container of Task=224#334 │ │ │ │ │ ├─ TaskInputSink of Surface(name=Decor container of Task=224)/@0x54597fa#338 │ │ │ │ │ └─ Caption container of Task=224#335 │ │ │ │ │ └─ Caption of Task=224Leash#336 │ │ │ │ │ └─ Caption of Task=224#337

其中com.tencent.android.qqdownloader/com[...]ssistantv2.activity.MainActivity#344就是应用窗口的layer,Caption of Task=224#337则是标题栏的layer,他们存在一个相同的父layer,即Task=224#326,那么每一次更新LayerSnapshot时,会从上至下遍历更新所有需要更新的layer,即会先更新应用窗口的layerBounds,然后再更新标题栏的layerBounds,所以我们可以根据顶层Activity的包名先计算出应用窗口的宽度,最后在更新标题栏时重设其geomLayerBounds的值,这样就可以保证每一次提交给hwc的图层中CaptionWindow和Activity窗口宽度一致。

3.解决方案

3.1.确定需要更新的Activity窗口和标题栏窗口

在WindowDecoration中,当CaptionWindow触发relayout时,记录下当前的标题栏名称,顶层应用包名,父layer的名称,这3个属性将提供给SurfaceFlinger来查找对应layer的关键字。同时可以同步SurfaceFlinger计算出来的真实的标题栏宽度。参考修改如下:

fix caption and window are not synchronized when window is scaling by pngcui · Pull Request #82 · openfde/lineageos_android_frameworks_base

3.2.SurfaceFlinger同步窗口宽度

在LayerSnapshotBuilder中,当调用updateLayerBounds时,根据顶层应用名包的geomLayerBounds来计算出最终窗口总宽度,这里需要考虑多窗口并排显示的场景,所以需要对窗口宽度进行累加,多窗口场景的SurfaceFlinger信息如下所示:

ROOT ├─ Display 0 name="内置屏幕"#1 │ ├─ WindowedMagnification:0:31#2 │ │ ├─ HideDisplayCutout:0:14#3 │ │ │ └─ OneHanded:0:14#4 │ │ │ ├─ FullscreenMagnification:0:12#5 │ │ │ │ │ └─ Task=226#108 │ │ │ │ │ ├─ TaskFragment{6bfc908 mode=freeform}#124 │ │ │ │ │ │ └─ ActivityRecord{a55c0bb u0 com.android.settings/.Settings t226}#121 │ │ │ │ │ │ ├─ 2de39d8 ActivityRecordInputSink com.[...]omepage.SettingsHomepageActivity#123 │ │ │ │ │ │ └─ 351bf02 com.android.settings/com.android.settings.Settings#127 │ │ │ │ │ │ └─ com.android.settings/com.android.settings.Settings#131 │ │ │ │ │ ├─ TaskFragment{31938a1 mode=freeform}#125 │ │ │ │ │ │ └─ ActivityRecord{e845ac6 u0 com.androi[...]s$NetworkDashboardActivity t226}#126 │ │ │ │ │ │ ├─ d272a87 ActivityRecordInputSink com.[...]ettings$NetworkDashboardActivity#130 │ │ │ │ │ │ └─ abbecb2 com.android.settings/com.and[...]ettings$NetworkDashboardActivity#128 │ │ │ │ │ │ └─ com.android.settings/com.android.set[...]ettings$NetworkDashboardActivity#132 │ │ │ │ │ └─ Decor container of Task=226#113 │ │ │ │ │ ├─ TaskInputSink of Surface(name=Decor container of Task=226)/@0xf9bc044#120 │ │ │ │ │ └─ Caption container of Task=226#114 │ │ │ │ │ └─ Caption of Task=226Leash#116 │ │ │ │ │ └─ Caption of Task=226#117

当被查找的layer图层的父layer名称与WindowDecoration标记的父layer名称一致时,表示此layer是当前Activity的有效图层,需要记录下他的宽度,直到所有图层都遍历完,当更新的layer是标题栏时,则把记录下来的最终宽度值设置到标题栏的geomLayerBounds数据结构中,并把该值同步给WindowDecoration模块,参考修改如下:
fix caption and window are not synchronized when window is scaling by pngcui · Pull Request #4 · openfde/lineageos_android_frameworks_native
fix x11-windows and captionbar are not synchronized during window scaling by pngcui · Pull Request #5 · openfde/lineageos_android_frameworks_native

fix captionbar appears too short by pngcui · Pull Request #17 · openfde/lineageos_android_frameworks_native

4.方案不足之处

4.1.多应用并排显示场景

对于双Activity类的应用,当2个Activity分别属于不同的包名时,此方案无法精准识别完整的标题栏宽度,此时会丢弃本次优化,此场景的SurfaceFlinger信息如下所示:

ROOT ├─ Display 0 name="内置屏幕"#1 │ ├─ WindowedMagnification:0:31#2 │ │ ├─ HideDisplayCutout:0:14#3 │ │ │ └─ OneHanded:0:14#4 │ │ │ ├─ FullscreenMagnification:0:12#5 │ │ │ │ │ └─ Task=243#117 │ │ │ │ │ ├─ TaskFragment{fafa2f1 mode=freeform}#133 │ │ │ │ │ │ └─ ActivityRecord{c208d76 u0 com.android.settings/.Settings t243}#122 │ │ │ │ │ │ ├─ 43a5f77 ActivityRecordInputSink com.[...]omepage.SettingsHomepageActivity#132 │ │ │ │ │ │ └─ d47c986 com.android.settings/com.android.settings.Settings#136 │ │ │ │ │ │ └─ com.android.settings/com.android.settings.Settings#140 │ │ │ │ │ ├─ TaskFragment{e6f7587 mode=freeform}#144 │ │ │ │ │ │ └─ ActivityRecord{9f85b75 u0 com.androi[...]ustomizationPickerActivity t243}#150 │ │ │ │ │ │ ├─ c1ac70a ActivityRecordInputSink com.[...]cker.CustomizationPickerActivity#152 │ │ │ │ │ │ └─ 5249d0d com.android.wallpaper/com.an[...]cker.CustomizationPickerActivity#153 │ │ │ │ │ │ └─ com.android.wallpaper/com.android.wa[...]cker.CustomizationPickerActivity#154 │ │ │ │ │ └─ Decor container of Task=243#126 │ │ │ │ │ ├─ TaskInputSink of Surface(name=Decor container of Task=243)/@0xa589666#130 │ │ │ │ │ └─ Caption container of Task=243#127 │ │ │ │ │ └─ Caption of Task=243Leash#128 │ │ │ │ │ └─ Caption of Task=243#129

4.2.录屏场景

由于Android14上录屏是录制的虚拟屏,会把录制的窗口映射到虚拟屏上,导致在虚拟屏上存在同样的一份Layer信息,所以SurfaceFlinger在计算窗口宽度时,会重复计算2次,导致异常,针对这种情况,也只能丢弃本次优化,相关修改如下:

fix captionbar appears too long when srceenrecording by pngcui · Pull Request #14 · openfde/lineageos_android_frameworks_native

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/14 3:55:26

复杂仓储AGV路径规划优化【附程序】

✨ 长期致力于复杂环境、路径规划、融合算法、AGV研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1)环境建模与分层搜索空间分割: 针对仓储…

作者头像 李华
网站建设 2026/5/14 3:54:35

第二篇:工业级 C++/Qt 项目预编译头(PCH)完整配置指南:从 0 到 1 部署,编译速度提升 80%

前言 大型 Qt 项目的编译速度往往是开发效率的瓶颈:修改一个业务文件,要等几分钟才能看到结果。预编译头(PCH)技术可以将几乎不修改的系统库、Qt 库提前编译成二进制缓存,让后续编译直接复用,通常能将编译速度提升 30%~80%。 本文将结合工业级项目规范,从零开始讲解预…

作者头像 李华
网站建设 2026/5/14 3:52:25

Chrome垂直标签页快捷键设置

用 Hammerspoon 给 Chrome 侧边栏加一个快捷键 Chrome 有个内置的垂直标签页侧边栏(Vertical Tab Sidebar),体验不错,但有一个致命问题:没有键盘快捷键来切换它。每次想收起或展开侧边栏,都得用鼠标去点那…

作者头像 李华
网站建设 2026/5/14 3:51:47

人机环境系统认知对抗中如何以跳频和猝发方式干扰态、势、感、知

在人机环境系统的认知对抗中,利用跳频和猝发技术来干扰敌方的“态、势、感、知”,核心在于打破其OODA(观察-调整-决策-行动)循环。通过制造电磁频谱的“迷雾”与“盲区”,不仅阻断其物理层面的信息传输,更在…

作者头像 李华
网站建设 2026/5/14 3:50:05

半导体制造中的金属填充技术:原理与应用

1. 金属填充技术概述在半导体制造工艺中,金属填充(Metal Fill)是一项至关重要的后端工艺技术。简单来说,就是在芯片设计的空白区域(White Space)添加非功能性金属结构,以达到平衡整个芯片金属密…

作者头像 李华
网站建设 2026/5/14 3:47:26

Python工程实战进阶:从语法到高效编程的核心技巧与避坑指南

1. 项目概述与核心价值最近在GitHub上看到一个名为“heamlk/Python-Skill”的项目,点进去一看,发现这并非一个传统的、功能单一的库或框架,而是一个内容相当丰富的Python技能知识库。作为一名在数据分析和自动化领域摸爬滚打了十来年的老码农…

作者头像 李华