android google 分屏 多窗口 popup无法显示故障分析

article/2025/9/15 15:49:27

原创无极限,欢迎加微信公众号 code_gg_home ,关注更多内容

问题描述
[Message][Input method]Display is wrong when message at split mode.
分屏模式下短信界面显示不正确

操作步骤
1.打开message然后退出
2.打开一个app如Call,然后长按recent键进入分屏模式
3.让message在分屏模式中处于底部,然后在message中编辑一些字符
4.长按这些字符串,不能显示出”CUT COPY SHARE”这3项  
–KO

环境描述
 android7.0.1
 屏幕分辨率 720*1280
 手机:eng版本

首先
按照bug描述,此时无法弹出pop框(cut copy…),我们第一步方向,去跟踪代码,追到此框弹出路径。(根据log分析, 使用调试工具Eclipse打断,跟踪流程),得到一条调用栈信息:

Editor.java 
—>startSelectionActionModeInternal
—>mTextView.startActionMode

DecorView.java 
—>startActionModeForChild
—>startActionMode
—>createFloatingActionMode
—>FloatingActionMode

FloatingActionMode.java
—>repositionToolbar
—>updateViewLocationInWindow
—>repositionToolbar
结论

确定位置FloatingActionMode.java  的 repositionToolbar方法上,此处 if (isContentRectWithinBounds()) 判断上:


分析

前面的结论,写的非常粗糙,只是给出了大致结果,没有给出如何处理此问题的,如下我们慢慢展开。

01
使用hierarchyviewer 工具,我们全屏下操作出来copy 对话框,去看它的视图信息。

展看后我们看到了:

看下cut copy这个框中的元素,发现最终类为:FloatingActionMode.java,因此直接定位在了这个类。

大致去阅读下这个类,同时工程下搜索下这个类,很快可以看到一条轨迹。在轨迹路途加入断点,快速定位流程,搜索内容如下:


我们可以排除StatusBarWindowView.java(因为我们不属于这里),我们忽略本身的FloatingActionMode.java ,来到了DecorView.java位置,(一看代码,有戏)

于是我们上断点,定位出来流程。

02
通过跟踪,对比全屏和分屏下出错的流程,发现问题点在于updateToolbarVisibility 函数的调用上,全屏下会调用这个show,而出错的在分屏下的底部时,没有调用。

于是我们继续定位,去找谁调用了这个函数。再次筛选,我们需要调用到show方法上。寻着这个路径,我们看到了本文件里面的调用关系:mMovingOff调用了updateToolbarVisibility方法

继续找mMovingOff的调用位置,可以得到如下

两个条件,最终确定是第一个条件出现问题,出现点为:


这里代码的意思为:
mContentRectOnScreen 弹出框在全屏的显示区域
mScreenRect  全屏区域  (错误点在这里)
mViewRectOnScreen view在全屏的显示区域

此段代码做了校验,判断popup框是否在屏幕外,如果在,就不要画了(画了你也看不见)

错误是因为:此段代码判断结论为,popup不在可见范围,不用画。(我擦,有没搞错,我在编辑框上选个内容,需要复制,粘贴,怎么会不在可见范围,哭晕..)
然而错误的原因你会泪奔的,原因是
mContext.getResources().getDisplayMetrics().heightPixels 的值为558,而popup的位置是579(系统判断579>558 ,所以在屏幕外?OMG,我觉得是在开玩笑),郁闷的是我们手机屏幕是720*1280的,(579<1280,应该要画的)。于是我们愤怒转移到了getDisplayMetrics().heightPixels方法,此方法取出来的不是屏幕高,是不是有些崩溃,那么为什么不是呢?
03
让我们停止怀疑人生,继续来追踪
mContext.getResources().getDisplayMetrics().heightPixels 为什么会给错呢?
最终

我们发现:
  系统getDisplayMetrics().heightPixels此方法给出的是当前task的高度值,并非屏幕的高度值。
  由于之前我们没有分屏机制,所以task就是全屏的,这两个值一致,没有问题。当分屏产生时,此值大小则不是屏幕的高度了。这个属于分屏开发暴露的问题。
  至于为什么分屏在上面时候,pop能弹出来,留个疑问给大家。

我们现在来查询heightPixels从何处来。此过程太过漫长,喝杯茶,容我慢慢道来。

mContext.getResources() 找到这个方法实现的地方,通过断点,找到此处的mContext在ContextImpl.java里面

getResources() 返回mResources ,于是我们要去找mResources的赋值地方,发现在ContextImpl的构造里面:


于是在ContextImpl的构造函数设置断点,发现确实此处传递的overrideConfiguration参数中有我们需要的错误值。
因此可以断定,此处之前已经有问题啦。

通过栈信息,我们可以看到,此时传递的路径为WindowManagerService.java的 handle里面的ADD_STARTING case里面,调用了addStartingWindow 方法

于是乎,我们看到了wtoken.mTask.mOverrideConfig 这个值决定了此处的overrideConfig。

如何去找哪里触发的这个case,我们搜索ADD_STARTING 

在调用地方设置断点,如此可以找到调用路径。

于是我们发现setAppStartingWindow 里面调用了,我们向上去找,发现了此处的wtoken里面的值已经出错(此处为279,densityDpi值为2,和之前的558对应上了),于是我们的方向便是去找这个值从哪里来的。

通过栈信息,我们找到了ActivityStarter.java 里面的 startActivityUnchecked方法,看到了此处的mStartActivity.task值已经出错,于是我们需要在此处确认此值的来源。

于是我们向上跟踪,发现修改地方在setTaskFromReuseOrCreateNewTask函数里面,继续跟进去看:

结论已经出现:
由于我们的task的isResizeable()返回true,使得方法进入task.updateOverrideConfiguration(mBounds);此处task处在分屏时候,此时task的大小需要使用activity的边界值做覆盖,覆盖之后,使得我们最终调用mContext.getResources().getDisplayMetrics().heightPixels拿到的是task的高,并非屏幕的高。

等等,我们好像发现了什么?

这里我们再去细分析,发现此处逻辑没有问题,当前task如果是isResizeable的,那么我们是需要覆盖这个值的,因此这里值没有问题,此处逻辑追踪的只是想确定错误值的来源。通过看完,发现此值本身没有疑问,是task的大小,没有问题。

我们错了?why??

那我们再返回到我们定位的起点,此处判断错误,引起没有去显示popup框

mContentRectOnScreen 弹出框在全屏的显示区域
mScreenRect  全屏区域  (错误点在这里)
mViewRectOnScreen view在全屏的显示区域

mScreenRect 系统期望拿到的是屏幕大小,(task默认不分屏下是等于屏幕大小)而此处因为分屏了,task的大小不等于屏幕大小了。

而此段代码认为mContext.getResources().getDisplayMetrics().heightPixels拿到还是系统屏幕大小,导致出错的。

结论
mContext.getResources().getDisplayMetrics().heightPixels 真正意义上是task的大小,在不分屏下,和屏幕大小相等(当然这里屏幕大小不是真正物理屏幕大小,因为还有状态栏和虚拟按键不在task的范围内,具体就不扩展了)

  于是我们的修改思路便是,需要找到此处可以拿到屏幕大小的方法,解决此问题。

修复
FloatingActionMode.java 里面,修改isContentRectWithinBounds的方法实现,具体修改为:

  修改前:

修改后:

编译版本,验证OK。

扫描下方二维码,关注代码GG ,或者微信搜索 code_gg_home


http://chatgpt.dhexx.cn/article/6xUTji5e.shtml

相关文章

Android分屏模式代码实现

文章目录 生命周期开发者相关相关模块和主要类ActivityManagerWindowManagerFramework APISystemUI 多窗口的功能实现两个系统服务简介ActivityManagerService负责Activity管理。WindowManagerService负责Window管理。 Activity启动过程Task和Stack多窗口与Stack分屏模式 参考链…

android分屏资源适配,Android N 分屏适配

支持和禁止分屏功能 android:resizeableActivity"true|false" 通过AndroidManifest中进行配置&#xff0c;来支持或者禁止分屏功能 监听是否进入分屏模式 重写Activity或者FragmentActivity的onMultiWindowModeChanged方法 Override public void onMultiWindowModeCh…

Android多窗口分屏(原生方法)

事实上KitKat已经可以实现多窗口分屏&#xff0c;只是功能不全&#xff0c;Google并没有把这个功能提供给用户。 使用am stack boxes可以查看当前系统存在的Activity Stack&#xff1a; 1 am stack boxes output: Box id1 weight0.0 verticalfalse bounds[0,38][800,1208] Sta…

Android实现一键开启自由窗口、分屏、画中画模式——自由窗口模式

转载请注明出处&#xff1a;https://blog.csdn.net/sunmmer123 忙过一段时间后&#xff0c;新需求又来了“多个应用/页面间在不用退出或者切换的情况下&#xff0c;可同时操作” 咋一听是不是很迷惑&#xff0c;简单来说“此时你在爱奇艺刷着剧&#xff0c;不退出爱奇艺的情况下…

android6.0分屏插件,xposed分屏模块安卓6.0下载

安卓6.0系统分屏软件(xposed分屏插件)是一款支持分屏多任务软件&#xff0c;具有多窗口/双窗口功能&#xff0c;在众多智能分屏app中算是比较好用的啦&#xff0c;推荐给有需要的用户下载使用&#xff01; 安卓6.0多窗口分屏软件简介 XHFW3在6.0下能用&#xff0c;很多以前的xp…

Android实现一键开启自由窗口、分屏、画中画模式——分屏模式

转载请注明出处&#xff1a;https://blog.csdn.net/sunmmer123 Android实现一键开启自由窗口、分屏、画中画模式系列 一键开启自由窗口模式一键开启进入分屏模式一键开启画中画模式 通过上一篇博文&#xff0c;我们学习了一些多窗口模式的基本概念以及如何自定义入口开启自由窗…

AndroidQ 分屏窗口尺寸计算 (WMS部分)

1. 分屏窗口尺寸计算 1.1 窗口添加到WMS Activity首次启动之后&#xff0c;在其resume阶段会将自己的Window添加到WMS&#xff1a; void makeVisible() {if (!mWindowAdded) {ViewManager wm getWindowManager();//顶层DecorViewwm.addView(mDecor, getWindow().getAttribut…

android T分屏流程

概览 分屏前的order Task display areas in top down Z order:TaskDisplayArea DefaultTaskDisplayAreamPreferredTopFocusableRootTaskTask{919dc1b #1 typehome ?? U0 visibletrue visibleRequestedtrue modefullscreen translucentfalse sz1}mLastFocusedRootTaskTask{919…

android 分屏切换流程,一种切换分屏模式和多窗口模式的方法与流程

本发明涉及一种切换分屏模式和多窗口模式的方法,适用于常见的带有触摸的电子设备,包括但不限于在系统的用户界面中使用触摸的方法进行导航的电子设备。 背景技术: 分屏模式是一种将两个应用扩充到全屏幕的交互方法。近几年随着技术的发展,使用触摸作为设备的输入方式已经被…

Android 分屏模式-多窗口支持

第一篇博客请多多担待&#xff0c;测试一下。 来自于https://developer.android.com/guide/topics/ui/multi-window.html#lifecycle Android N 添加了同时显示多个应用窗口的支持&#xff0c;在手持设备上&#xff0c;两个应用可以在“分屏”模式中左右并排或者上下并排显示。…

AndroidQ 分屏窗口模式 (AMS部分)

1. 多窗口 1.1 栈 Android7.0开始支持多窗口&#xff0c;多窗口分为三种&#xff0c;画中画&#xff0c;分屏&#xff0c;自由窗口&#xff0c;多窗口的核心原理其实就是分栈和设置栈边界&#xff0c; 分栈即把不同窗口模式下的Activity放在不同的ActivityStack中&#xff0…

Android分屏显示(多窗口支持) 开发总结

最近公司有分屏显示需求&#xff0c;遇到几点问题 &#xff0c;在此记录&#xff0c;以做备忘。 我所谓的分屏显示&#xff0c;是在同一个界面内&#xff0c;分屏显示两个app的界面 或者是 注意点1&#xff1a; 系统好像没有获取应用显示的左右或者上下位置的方法&#xff0c;…

android安卓手机分屏多窗口实现方法

效果图 frameborder"0" allowtransparency"true" scrolling"no" vspace"0" hspace"0" style"display: block; position: static; padding: 0px; margin: 0px; border-style: none; vertical-align: baseline; width: 3…

Android实现一键开启自由窗口、分屏、画中画模式——画中画模式

转载请注明出处&#xff1a;https://blog.csdn.net/sunmmer123 Android实现一键开启自由窗口、分屏、画中画模式系列 一键开启进入自由窗口模式一键开启进入分屏模式一键进入画中画模式 通过前俩篇博文&#xff0c;我们学习了一些多窗口模式中的自由窗口模式与分屏模式的知识 最…

Android多窗口模式(分屏模式)

Android N 支持多窗口模式&#xff0c;或者叫分屏模式&#xff0c;即在屏幕上可以同时显示多个窗口。 在手机模式下&#xff0c;两个应用可以并排或者上下同时显示&#xff0c;如图 1 所示&#xff0c;屏幕上半部分的窗口是系统的 CLOCK 应用&#xff0c;下半部分是系统设置功能…

git 命令怎么创建新分支?

问题 比如&#xff1a;我们要以 dev 分支创建一个 test-branch 分支。 解决 1、在本地创建一个 test-branch 分支&#xff0c;并切换到该分支。 git checkout -b test-branch执行完&#xff0c;可以使用下面命令查看是否创建了该本地分支 git branch -a2、把分支推到远程仓…

git命令之快速搭建远程仓库

首先使用系统管理员账号登录远程服务器&#xff0c;具体步骤如下所示&#xff1a; 1 安装git应用程序 sudo apt-get install git 2 创建git用户组和git用户&#xff0c;具体命令如下所示&#xff1a; groupadd git adduser git -g git 3 修改git用户默认shell为git-shell…

Git命令常用操作 代码拉取和提交

常规的git命令就是以下几个语句 项目首次拉取 git clone 项目地址url拉取并同步代码到本地 git pull将本地所有更改的文件添加到缓存区 git add .添加备注&#xff0c;方便之后查看历史提交记录 git commit -m "本次提交备注信息"提交到git仓库 git push

git命令之新建仓库

一. 配置git用户名 1&#xff09;安装git&#xff0c;配置用户名和邮箱 git config --global user.name "你的用户名" git config --global user.email "你的注册邮箱" 2&#xff09;使用git config --global --list查看配置 二. 工作区操作 1&#x…

常见Git命令使用

常见Git命令使用 1.初始化创库 git init 2.git status 这个命令顾名思义就是查看状态&#xff0c; 这个命令可以算是使用最频繁的一个命令了&#xff0c; 建议大家没事就输入下这个命令&#xff0c; 来查看你当前 git 仓库的一些状态。 3.git add 文件名 将文件添加到git仓库…