前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >google 进入分屏后在横屏模式按home键界面错乱( 四)

google 进入分屏后在横屏模式按home键界面错乱( 四)

作者头像
用户1263308
发布2018-02-02 10:39:39
1.2K0
发布2018-02-02 10:39:39
举报
文章被收录于专栏:代码GG之家代码GG之家

google 进入分屏后在横屏模式按home键界面错乱( 四)

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

代码阅读,请到此处http://androidxref.com 查看原生代码

google 分屏 横屏模式 按home键界面错乱故障分析(三)

google 分屏 横屏模式 按home键界面错乱故障分析(二)

google 分屏 横屏模式 按home键界面错乱故障分析(一)

Android 关机对话框概率没有阴影故障分析

android recent key长按事件弹起触发最近列表故障分析

google 分屏 popup无法显示故障分析

前情回顾:

google 分屏 横屏模式 按home键界面错乱故障分析(三)

上一节我们主要围绕了分屏的退出过程,我们从suystemui的长按recent key开始,追踪整个退出流程,分析了在此过程中,系统调整task的动作,处理是否需要relauncher acitivty的判断,是否判断已经退出了分屏。

最后,我们延伸了一个分割线在退出的时候处理流程。

为了我们分屏整个系列的完整性,我们这节开始研究,分屏下的转屏过程。

00

我们先看下WMS的启动过程,看下PhoneWindowManager.java的初始化流程,因为PhoneWindowManager.java这个是我们分析转屏的切入位置,因此我们顺着学习(此章节没有用倒着思维,主要是自己从逆向去讲,有些绕,我们就正常顺着讲完这一节即可)

system_server进程,是我们android的核心进程,提供了了上层app所需要的大部分服务,我们开发使用的BT WIFI POWER AMS WMS都是在system_server进程里面,以线程的方式存在,系统其他app进程通过binder(一种跨进程通信方式),来进行交互。

于是,我们这里关注WMS的服务的启动过程。

我们从SystemServer.java文件开始走起:

runtimeinit里面,通过抛出异常,执行 调用此处的main,进行SystemServer的进程初始化过程。

main走入本文件的run方法:

继续startOtherServices方法:(去掉无关代码)

这里我们看到,使用main初始化构造了一个WindowManagerService,然后调用了wm.systemReady,我们关心这里的systemReady:

于是我们看下mPolicy是什么?

是个PhoneWindowManager,于是我们这里需要看PhoneWindowManager里面的systemReady方法。我们先看下WMS这边对于mPolicy的初始化地方:

WindowManagerService的构造函数里面有

我们看下这里的initPolicy方法,完成了初始化动作。

这里init方法,完成了一个关键的初始化

mOrientationListener 是注册转屏的关键监听,我们先说这里,转回去看下mPolicy 的systemReady 方法:

这里关键的就是updateOrientationListenerLp 和updateSettings两个方法,完成旋转屏的监听注册,以及更新设置动作。

由于我们不去详细讲解这里具体的设置过程,我们只是给出信息位置。此处会根据当前的设置值,如果当前开启了屏幕旋转,则会enable这个mOrientationListener。所以我们核心关注这里。

01

我们看下mOrientationListener

发现了继承自WindowOrientationListener,核心的方法为onProposedRotationChanged,此方法接收旋转改变的变化,扔出一个post出来,看到post的run方法,便是updateRotation,我们转屏就此开始处理。

我们看下WindowOrientationListener,只关注它的构造,我们看个内容:

这里关注AccelSensorJudge ,这个是检测sensor变化的类,我们前面讲过,系统在WMS的初始化时候,初始化了一个PhoneWindowManager,这里在systemready里面进行判断当前系统状态,是否需要开启转屏,如果当前系统开启转屏,会调用WindowOrientationListener里面的enable方法:

通过mSensorManager将这个转屏检测设置下去。我们此处不去深入mSensorManager内部实现,此节不专门跟进此流程。我们只需要关注的就是,系统在开机之后,判断当前如果没有关闭检测转屏,此时就会调用enable将mOrientationJudge注册进入mSensorManager,来实时检测转屏消息,如果发生改变,则会进入自己内部的callback方法,具体为:onSensorChanged

我们这里不截屏了,onSensorChanged会去计算,当前是否达到了转屏所需要的角度,如果到了,触发 onProposedRotationChanged方法,此方法就会来到

PhoneWindowManager.java里面mOrientationListener实现的onProposedRotationChanged方法:

于是,我们知道了,转屏产生时,这里关注点是updateRotation方法了。上面的,我们再给个图,来看下这个的传递过程:

如上,流程清晰了,我们就专注看updateRotation方法了。

03

我们看下updateRotation的代码:

继续追踪:

再看:

这里会去调用updateRotationUncheckedLocked来判断是否转屏了,如果是,则会走sendNewConfiguration,去通知系统,当前需要更新状态了。关于updateRotationUncheckedLocked,我们当前不具体分析,我们讲解主要围绕分屏来扩展,因此跳过这个方法,直接去看sendNewConfiguration,看下这个代码。

04

在看这个代码之前,我们打个断点,看下我们要跟踪的流程:

我们就是要顺这个思路。我们看sendNewConfiguration方法:

这里就走入了AMS了。

computeNewConfiguration 计算出最新的配置值,然后更新。我们看updateConfigurationLocked

继续往下来看,就到了我们需要分析的核心位置了:

嗯,核心地方,代码又是一大堆,郁闷。我们慢慢看,需要关注的又给你高亮了。

mSystemThread.applyConfigurationToResources 更新当前system_server进程的资源信息。

app.thread.scheduleConfigurationChanged 通知所有的application,当前配置有变化。此过程会调用到activity的onConfigurationChanged方法,用来通知activity当前配置的更改。

紧接着两个广播:

ACTION_CONFIGURATION_CHANGED

ACTION_LOCALE_CHANGED

这个只有变更属于位置的时候才发生,主要就是语言变化。

用broadcastIntentLocked 广播出去的。

接下来有到了繁杂的流程中了:

这里使用setNewConfiguration方法,去判断是否需要变更的stack,将所有需要变更的栈,返回,然后调用resizeStackLocked,将栈里面的所有task进行修正。setNewConfiguration的内容为:

这里就是关注下onConfigurationChanged方法,此方法返回需要resize的stack列表。

defaultDisplayContent.getDockedDividerController().onConfigurationChanged(); 这个方法完成屏幕方向变化,更新当前分割线的数据。

我们再去systemUi那边,看下Divider.java里面,也有onConfigurationChanged,还是复写的方法,我们需要关注这个,因为此方法是在转屏的时候,会触发。

我们来到SystemUIApplication.java这个是systemui进程的application实现,它会在转屏的时候,收到通知过来,我们看它里面的方法:

按照我们之前讲的,mServices里面有Divider,于是这条线就对上了。系统方向改变,会调用SystemUIApplication.java里面的onConfigurationChanged方法,这里它会调用注册进来的所有mServices,去依次通知onConfigurationChanged,这里面便有我们的分割线,嗯,就是这么完美。

05

我们回到WindowManagerService.java这里的onConfigurationChanged,前面讲解了会返回resize的stack列表,于是我们关心这里的返回值是谁给出的。

我们看到mChangedStackList用来返回,所以我们的关注点进入到stack.onConfigurationChanged()方法里面,这里for循环用来完成遍历所有的stack,来进行判断是否需要resize。

这里去掉无关的内容,我们关注updateBoundsAfterConfigChange方法。mFullscreen变量,来判断是否是全屏stack,如果是直接返回。由于我们当前在分屏模式下,这里会将全屏栈的所有TASK变为非全屏,于是我们全屏栈的TASK此处都会走下来(mFullscreen==false)我们这里看到,系统给了DOCKED_STACK_ID特殊的处理。

计算当前是否DockSide改变了,这个改变了就是代表分割线的方向。此处我们知道,当系统进入分屏模式,DOCK栈和FULL栈都会是非全屏状态,于是这里的默认返回都是true,也就意味着,这些TASK都会进行resize。这个是关健,resize决定了改变当前每个stack的大小,对应的就会修改task的大小,一直到acitivty的大小,这里会存储在activity的对应task的config里面,需要时候可以通过接口获取。

06

回到ActivityManagerService.java里面,我们看完了mWindowManager.setNewConfiguration,这里依据当前的改变,来判断是否有stack需要变化,我们因为在分屏模式下,于是这里会有需要更新的stack,于是我们此处返回有值,那么我们会进入到:

关于这里的resizeStackLocked,我们之前几节都在重复讲解,此处不再细化了。完成了这个动作(主要的内容就是这里,需要resize来处理task的updateOverrideConfiguration方法,会完成relauncher等一系列动作),下来的内容为:

拿到主栈,当前focus的栈。拿到最上面的activity(用ActivityRecord记录),然后调用ensureActivityConfigurationLocked更新它的状态。我们再简单阅读下

mStackSupervisor.ensureActivitiesVisibleLocked,为什么简单阅读呢,因为里面内容过多,没法细化去讲解,主要的含义为:判断哪些activity需要显示出来,然后我们将这些状态更新一下。(比如我最前面是个半屏透明窗口,那么系统必然要将此窗口下面的另个窗口内容显示出来,此方法便是完成这个任务)

详细的ensureActivitiesVisibleLocked内容为:(高亮关键部分,不做细致分析)

此方法的注释为:Make sure that all activities that need to be visible (that is, they currently can be seen by the user) actually are. 就是完成activity的显示判断依据。

阅读此文,可以参照

http://blog.csdn.net/jinzhuojun/article/details/50085491 两边对应来看,会更加清晰明了。此文讲的内容偏少,那就回看下之前内容,温故而知新。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-03-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 代码GG之家 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档