当前位置: 首页 > news >正文

修复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

http://www.jsqmd.com/news/812968/

相关文章:

  • 2026模具超声波清洗机源头厂家盘点:单槽超声波清洗机源头厂家+碳氢超声波清洗机厂家+超声波震板厂家推荐合集 - 栗子测评
  • (最新版)实测有效Windows 10/11 AI 智能体 OpenClaw安装教程
  • 超级电容器充电系统设计与CICV技术详解
  • 5月8日AIoT双标落地,中国企业如何借势完成量级跃迁?
  • DLP技术在汽车AR HUD中的应用与光学设计突破
  • 2026废水处理设备厂家推荐:高难废水处理厂家+工业水处理药剂厂家+海水淡化设备厂家+废水零排放设备厂家名录 - 栗子测评
  • 如何快速掌握Vue 3动态展示组件的完整指南
  • 雷达技术核心原理、测试挑战与工程实践全解析
  • DS4Windows完全指南:让你的PS4手柄在Windows上大放异彩 [特殊字符]
  • 2026防爆超声波清洗机定制厂家合集:多槽超声波清洗机生产厂家+除油脱脂清洗机源头厂家优选 - 栗子测评
  • LLDP:网络拓扑的“自动发现者”与故障定位利器
  • IoT产品指标体系设计方法:构建“用户 × 设备 × 数据 × 收入”的全链路指标系统
  • 2026超声波水表生产厂家推荐:超声波水表厂家+超声波水表源头工厂+智能水表源头工厂指南,附荣现水表测评 - 栗子测评
  • AI播客生成器实战:从YAML配置到自动化音频制作全流程解析
  • Agent-Harness:为AI编程助手构建结构化协作框架的工程实践
  • Redis分布式锁进阶第三十篇
  • 5分钟掌握Nexus Mods App:告别模组管理烦恼的终极解决方案
  • ROS2从入门到“重启解决”:21讲8~12章踩坑血泪史与核心总结
  • 量子纠缠蒸馏技术:原理、实现与应用
  • 6G时代下的电磁信息论:探索无线通信的新边界
  • 服务器频繁遭暴力攻击?IP 更换、防护加固一站式解决方案
  • Chrome垂直标签页快捷键设置
  • 技术人的职业倦怠:当你对代码失去热情时该怎么办?
  • 字节面试灵魂拷问:2-3个if else,用策略模式真的多余吗?
  • BG3模组管理器版本兼容性终极指南:告别游戏崩溃和模组失效
  • 软考高项备考重点考点23:组织通用管理
  • IC卡水表哪家好?2026智能水表厂家推荐:IC卡水表厂家+靠谱的预付费水表厂家+智能水表定制厂家推荐 - 栗子测评
  • AI智能体开发实战:从AwesomeClaw看开源框架与工具集成
  • 智能工厂能源监测管理平台解决方案
  • GenAIScript:用代码思维重构提示工程,实现AI应用工程化