你确定你了解分屏的整个流程?

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第1张图片

代码也是有情感,你若爱她,就调试她吧。

代码阅读,请到此处http://androidxref.com 查看原生代码分享此文便是对代码GG的支持,也是爱的表达方式,所以让爱来的猛烈些吧。

之前分析文章列表:

Android 关机对话框概率没有阴影故障分析
android recent key长按事件弹起触发最近列表故障分析
google 分屏 popup无法显示故障分析

问题描述
[Dialer&&MMS]进入分屏后在横屏模式按home键界面错乱

操作步骤
1.进入拨号盘2.长按recent进入分屏,按home回主界面3.点击MMs进入短信,转到横屏模式4按home键,故障发生

环境描述

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

故障效果(看状态栏,出现两条黑线)
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第2张图片
分析
00
套路,使用hierarchyviewer 工具,去找下出错的内容属于谁,属于哪个类。(为什么频繁使用这个呢?快速便捷的定位,能不高呼)

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第3张图片
展看DockedStackDivider,查看界面信息:
这里看到定位信息真多,我们看到这里三个View都是自定义的,这就让我们轻而易举的找到了地方
于是我们快马加鞭,来项目里面查找下DividerView
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第4张图片这里我们看到了代码属于packages\systemui下面,于是我们可以得出一个结论,分屏的线条是在SystemUI进程,于是乎,我们是可以调试SystemUI的,我们先不去调试,直接看代码分析。
01

缓下,我们先要去看DividerView.java是个什么内容。按照之前的讲法,我们来看看(只说重点了,详细的去之前文章阅读了)


非常普通了,就是个简单的自定义View而已android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第5张图片这个onFinishInflate方法就是初始化View的地方,于是我们看到一些View,我们此处关注mBackground 和mMinimizedShadow(为什么,因为我们出错的就是这两个显示出来了)
这里我高亮了mHandle,这个是拖动分割线的响应View哦。(内心激动的人,可以先去看本文件里面的onTouch函数即可)
我们先处理此问题,关于分屏流程,后面展开。

本文搜索mBackground,核心关注它变为隐藏的时候。我们看到只找关键的了,定义的和设置变量的一些乱七八糟的就没截图了。我们看下 mBackground.setScaleY(MINIMIZE_DOCK_SCALE);的代码上下文然后我们看到完整代码:(有两处,一个是有动画,一个没有而已)android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第6张图片
 MINIMIZE_DOCK_SCALE的定义为:看到这里,有隐藏view的逻辑,setScaleX(MINIMIZE_DOCK_SCALE=0)便会将此View隐藏。我们看下这里的逻辑,如果不是最小化minimized(就是显示的了),那就走resetBackground方法。这里我们看到,系统将mBackground设置了锚点居中,缩放还原为1,设置mMinimizedShadow隐藏如果mDockSide == WindowManager.DOCKED_TOP 设置PivotY为0(锚点为0,作为缩放的原点)然后将Y方向缩为0如果mDockSide == WindowManager.DOCKED_LEFT或者DOCKED_RIGHT ,设置锚点,设置X缩放为0
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第7张图片
(此处代码有些搞笑,都是隐藏,你这时候缩放X Y方向为0有区别吗?并且在上面resetBackground是直接将XY的缩放都回到1),人家还原的时候都不管你之前到底缩放了哪个方位,你自己缩放判断个鬼。so。。。出错就在这里了,你说你搞笑不?

这里有个很有意思的套路:mMinimizedShadow.setAlpha(minimized ? 1f : 0f);看这里是不是反的? 如果最小化,显示这个,如果不是最小化,隐藏。这里他做这个是干嘛的呢?其实google这个在最小化的时候显示mMinimizedShadow,按照这个名字,它会是个shadow(让你知道这个是分屏了,有个阴影效果),如果显示分屏的时候,它就隐藏了。(它就是想在你分屏隐藏的时候,在状态栏上做个阴影,让你知道你处在分屏模式下而已)
我们看下除了DOCKED_TOP ,此枚举都有哪几个值:
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第8张图片
看这个的目的,我们可以看出上面的代码,是否忽略掉了一些状态,于是我们继续来看。

02
我们再看下我们的代码
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第9张图片
会发现我们的else是不是没有全部的选择,少了DOCKED_BOTTOM 和 DOCKED_INVALID,于是我们假如这里的mDockSide==这两个的其中一个,会发现什么问题呢?
mBackground 没有隐藏哦mMinimizedShadow 是设置了显示,但是我们再去它的类去瞅瞅吧。

mMinimizedShadow  类的方法里面有:(onLayout 和onDraw都是自定义view的关键实现,还有一个是onMeasure,此处没有复写而已)
我们看下这几个方法:
onLayout
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第10张图片
updatePaint方法:

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第11张图片

onDraw
看到了没这里它也没管这个值DOCKED_INVALID(DOCKED_BOTTOM),于是用了默认的颜色,而默认画出来是黑色,你说这就没意思了吧。忽略DOCKED_BOTTOM这个枚举我们可以解释,因为当前系统设计不会放置在下面的,于是DOCKED_BOTTOM值可以忽略,所以我们看到,此处有一个 DOCKED_INVALID状态,会导致在隐藏分割线的时候,没有处理代码,引起分割线显示在上面。而系统自以为所有手机都跟它一样,配置很高,but现实是还有低配机子的啦,于是此状态会产生,引出此问题。于是,我们看完了代码,从逻辑上分析出来是这个原因,那么事实觉得这个情况会发生吗? 我们补充log,查看下这里的错误时候的值,发现,此处为-1( DOCKED_INVALID),于是得出结论了。到这里,此问题就算完结了,但是,但是,我要讲故障修复,就没必要这么繁琐了,因此,我们还要继续深入,去看看代码。我要去讲下分屏这条线索,追个路径出来。
03

搜索DividerView,我们继续来深入
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第12张图片
我们打开Divider.java,发现了很多内容。

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第13张图片

首先,我们看下它继承了谁?SystemUI,这个要干嘛呢?我们搜索Divider,通过筛选(只在SystemUI包下,为什么,之前已经说过,这个类在这个包下,别的应用引用的机会基本为0)我们看到如下内容:(筛检过)

然后我们在SystemUIApplication.java 里面稍微停留下:看到 android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第14张图片startServicesIfNeeded方法
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第15张图片

这里遍历了我们上面的mServices里面的所有元素,有我们的Divider.java(看这里都转为了SystemUI类处理了,所以我们Divider要继承SystemUI,没毛病)主要走里面的start方法 和onBootCompleted方法我们先不回到Divider的start方法,我们再继续深入看下,看startServicesIfNeeded如何调用起来的。
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第16张图片

我们跟了下KeyguardService.java  发现不对路,放弃掉。我们忽略自己本身的方法,于是来到SystemUIService.java里面

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第17张图片
发现onCreate里面调用了startServicesIfNeeded方法,于是我们继续看,搜索SystemUIService

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第18张图片
我们忽略注释和xml,以及本身的文件,于是我们看到了SystemServer.java(熟悉不?系统server创建的地方),我们看看去
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第19张图片android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第20张图片
看到了不?系统创建完server,会到mActivityManagerService的systemReady,这里面启动了systemUI,然后调用了一个SystemUIService,这个在创建自己的时候,调用了SystemUIApplication里面的startServicesIfNeeded,完成了systemui的组件创建和初始化,而这里,也有我们分屏的Divider
04
逛完了系统创建systemui的过程,我们再次回来,慢慢来看我们的分隔线Divider.java
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第21张图片
从上面的流程来看,我们需要调用关注它的start方法,我们看下:这里我高亮了几个内容:DividerWindowManager ,分隔线管理者。(等会细看)update 这个主要更新我们的参数,主要为移除Divider,然后添加(依据当前屏幕的横竖屏处理),判断是否为最小化,是的话就要想办法隐藏了。mDockDividerVisibilityListener 这个类DockDividerVisibilityListener,我们看下:
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第22张图片

这里我们发现,它的继承为:IDockedStackListener.Stub,于是乎,它是跨进程调用这里我们使用ssp.registerDockedStackListener(mDockDividerVisibilityListener);将这个监听注册到系统里面去(后面分析它)mForcedResizableController 暂时先放过,后面分析。
05
我们说完了大概,然后我们回来看下DividerWindowManager这个类
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第23张图片

没有继承,只有方法,于是我们看方法add(关键),直接通过windowmanager给系统加入了一个View。高亮一个信息TYPE_DOCK_DIVIDER(专门给它量身定做的类型,是不是很开心,我们又找到了关键字)android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第24张图片
remove,移除这个View。

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第25张图片

setSlippery 设置是否在滑动中,中间的那个线是可拖拽的。

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第26张图片
setTouchable是否可点击。
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第27张图片

我们回过头看看Divider里面的update方法:

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第28张图片

(看下这里的removeDivider 和addDivider)removeDivider
这里mWindowManager就是DividerWindowManager,我们不用说了吧。
addDivider
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第29张图片
加载布局,设置大小,设置宽高,加载到windowmanager里面去。
06

总结上面的内容:
systemui里面有个Divider,里面管理着分割线的布局,有个监测系统的服务端(mDockDividerVisibilityListener),系统要不要显示,通过这条线回调回来,再通知界面显示与否即可。这里Divider还有个方法:onConfigurationChanged,当系统属性发生改变时候,会通过这条线路发送回来(这里会做简单的事情,先移除view,然后依据当前的屏幕方向,新建view,然后根据是否要显示,默认是显示的。如果不需要显示,则隐藏掉view–用了缩放XY大小为0和Alpha来做的)
07

总结看完,继续奔波,我们先向系统层迈进,于是我们仔细来看下DockDividerVisibilityListener
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第30张图片
看看它有哪些实现onDividerVisibilityChanged显示隐藏的通知onDockedStackExistsChanged 存在与否的通知onDockedStackMinimizedChanged最小化的通知(我们当前在这个里面,因为我们没有退出分屏,只是进入了主界面,分割线会最小化)onAdjustedForImeChanged 当有输入法的时候,调整大小和位置的通知onDockSideChanged 当dock的位置调整的时候,主要就是dock在左边还是右边,这种信息。我们先不去看这里面每个方法的具体实现,我们找下它们在哪里被调用的(我们以onDockedStackMinimizedChanged来作为搜索依据)

自己本身可以忽略NavigationBarView里面是个空实现,忽略我们看到了DockedStackDividerController.java
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第31张图片

继续搜索

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第32张图片

ActivityManagerInternal.java,注释忽略

ActivityManagerService.java  关键地方,主要完成dockstack的动作
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第33张图片
DockedStackDividerController.java android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第34张图片registerDockedStackListener 注册的地方(我们之前在Divider的start里面,有注册这个的动作)
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第35张图片
setMinimizedDockedStack 
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第36张图片

这是个内部方法,我们说过,内部方法外部不能直接调用,所以我们要找这个在本文里哪里调用了
animateForMinimizedDockedStack 内部,我们还是要找谁用它了
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第37张图片WindowManagerService.java 是个case,然后调用了

mAmInternal(ActivityManagerInternal)的通知即可。mAmInternal是谁呢?



android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第38张图片
几经周转,在ActivityManagerService.java里面有

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第39张图片

这么多,发现线索主要在
setMinimizedDockedStack方法
(DockedStackDividerController.java)
animateForMinimizedDockedStack 方法                      (DockedStackDividerController.java)
和ActivityManagerService.java里面

于是我们线索收敛了。我们继续向下走

08

我们不做太多扩散,我们从setMinimizedDockedStack切入下在DockedStackDividerController.java里面找setMinimizedDockedStack
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第40张图片
(突然发现,这里面代码错综复杂,如此分析下去,我要陷入其中,系统还是调用太复杂,要讲清千丝万缕,不能如此细致入微去讲了,汗,于是我们先从单向切入看下)我们看这个是退出与否的状态切换
**android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第41张图片我们先继续看看notifyDockedStackExistsChanged的调用地方,我现在不去用编辑器来只是简单搜搜了(如此下去,没有尽头,调用地方太多,于是我们换个思路),开始调试system_server我们关注下WindowManagerService里面的 代码

这个是多用户时候,需要判断当前用户是否处在分屏模式下,我们暂时可以忽略。
android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第42张图片

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第43张图片

按照注释,是attachstack的时候有通知 (DOCKED_STACK_ID ,特殊栈id,主要就是标志谁在分屏的那个栈上)所以这两个函数是个关键点,我们可以下断点,去跟踪代码流程。detachStackLocked 退出也有调用notifyDockedStackExistsChanged,于是乎我们上断点,调试下

attachstack 方法的栈信息为:

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第44张图片

detachStackLocked 的栈信息为:

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第45张图片

这里关注的栈方法为:

通过两个栈信息,我们便可以得到关键的两个东西:启动分屏的栈,关闭分屏的栈,这两个在分屏模式如此重要的方法,已经被我们拦到,其余的不是迎刃而解吗?

我们继续跟踪detachStackLocked流程,会发现我们的notifyDockedStackMinimizedChanged 方法被触发了。

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第46张图片

这个是我们退出分屏的时候,发送回来的消息,于是我们需要看下这个是谁调用的

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第47张图片

看看看,又是windowAnimator,又是animateLocked方法,我们清晰的看到了
doFrame(如呼吸一般)如期的出现在眼前。 我们看下animateLocked方法里面的一行

来到了DockedStackDividerController的animate方法

android google 分屏 多窗口 按home键界面错乱故障分析(一)分屏的整个流程分析_第48张图片

看此处,如果mAnimatingForMinimizedDockedStack为真,则走入我们的最小化方法了。

先消化下,下一章节再见。

下一章节,继续分析分屏,主要讲解分屏的启动过程。

如果有收获,赞赏鼓励下作者。
更多内容,关注微信公众号:代码GG之家。
加微信 code_gg_boy  进入代码GG交流群

更多相关文章

  1. Android 4.0 ICS 用户界面概述
  2. Android移动应用界面的模板化设计【自定义BaseActivity】
  3. RadioButton使用的过程中Text文本和图片显示的问题
  4. 从零开始--系统深入学习android(实践-让我们开始写代码-Android框
  5. Android和iPhone应用程序界面布局示例
  6. Android 三大图片缓存原理、特性对比
  7. Android调用系统相机、自定义相机、处理大图片
  8. Android小项目之十二 设置中心的界面
  9. Android界面开发问题总结

随机推荐

  1. eclipse下android的sdk配置问题
  2. 我是如何自学Android,资料分享(2015 版)
  3. Android中的Shape美化
  4. Android(安卓)TextView文字横向自动滚动(
  5. Android 技术专题系列之三 -- 编译(build)
  6. Android 相对布局:RelativeLayout
  7. Android分区解释:boot, system, recovery,
  8. Android(安卓)init 启动过程分析1
  9. Android平板上开发应用的一点心得——精
  10. 使用Lint 和 Annotations来提升代码质量