文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8498908java
咱们知道,在Android系统中,Activity是以堆栈的形式组织在ActivityManagerService服务中的。与 Activity相似,Android系统中的窗口也是以堆栈的形式组织在WindowManagerService服务中的,其中,Z轴位置较低的窗口 位于Z轴位置较高的窗口的下面。在本文中,咱们就详细分析WindowManagerService服务是如何以堆栈的形式来组织窗口的。android
从前面Android应用程序启动过程源代码分析一文能够知道,应用程序进程中的每个Activity组件在Activity管理服务ActivityManagerService中都对应有一个ActivityRecord对象。从前面Android应用程序窗口(Activity)与WindowManagerService服务的链接过程分析一文又能够知道,Activity管理服务ActivityManagerService中每个ActivityRecord对象在Window管理服务WindowManagerService中都对应有一个AppWindowToken对象。windows
此外,在输入法管理服务InputMethodManagerService中,每个输入法窗口都对应有一个Binder对象,这个Binder对象在 Window管理服务WindowManagerService又对应有一个WindowToken对象。session
与输入法窗口相似,在壁纸管理服务WallpaperManagerService中,每个壁纸窗口都对应有一个Binder对象,这个Binder对 象在Window管理服务WindowManagerService也对应有一个WindowToken对象。app
在Window管理服务WindowManagerService中,不管是AppWindowToken对象,仍是WindowToken对象,它们都 是用来描述一组有着相同令牌的窗口的,每个窗口都是经过一个WindowState对象来描述的。例如,一个Activity组件窗口可能有一个启动窗 口(Starting Window),还有若干个子窗口,那么这些窗口就会组成一组,而且都是以Activity组件在Window管理服务 WindowManagerService中所对应的AppWindowToken对象为令牌的。从抽象的角度来看,就是在Window管理服务 WindowManagerService中,每个令牌(AppWindowToken或者WindowToken)都是用来描述一组窗口 (WindowState)的,而且每个窗口的子窗口也是与它同属于一个组,即都有着相同的令牌。框架
上述的窗口组织方式如图1所示:svg
图1 窗口在WindowManagerService服务中的组织方式函数
其中,Activity Stack是在ActivityManagerService服务中建立的,Token List和Window Stack是在WindowManagerService中建立的,而Binder for IM和Binder for WP分别是在InputMethodManagerService服务和WallpaperManagerService服务中建立的,用来描述一个输入 法窗口和一个壁纸窗口。布局
图1中的对象的对应关系以下所示:学习
1. ActivityRecord-J对应于AppWindowToken-J,后者描述的一组窗口是{WindowState- A, WindowState-B, WindowState-B-1},其中, WindowState-B-1是WindowState-B的子窗 口。
2. ActivityRecord-K对应于AppWindowToken-K,后者描述的一组窗口是{WindowState- C, WindowState-C-1, WindowState-D, WindowState-D-1},其中, WindowState-C-1是 WindowState-C的子窗口,WindowState-D-1是WindowState-D的子窗口。
3. ActivityRecord-N对应于AppWindowToken-N,后者描述的一组窗口是{WindowState-E},其中, WindowState-E是系统当前激活的Activity窗口。
4. Binder for IM对应于WindowToken-I,后者描述的一组窗口是{WindowState-I},其中, WindowState-I是WindowState-E的输入法窗口。
5. Binder for WP对应于WindowToken-W,后者描述的一组窗口是{WindowState-W},其中, WindowState-W是WindowState-E的壁纸窗口。
从图1还能够知道,Window Stack中的WindowState是按照它们所描述的窗口的Z轴位置从低到高排列的。
以上就是WindowManagerService服务组织系统中的窗口的抽象模型,接下来咱们将分析AppWindowToken、 WindowToken和WindowState的一些增长、移动和删除等操做,以即可以对这个抽象模型有一个更深入的认识。
1. 增长AppWindowToken
从前面Android应用程序窗口(Activity)与WindowManagerService服务的链接过程分析一文能够知道,一个Activity组件在启动的过程当中,ActivityManagerService服务会调用调用WindowManagerService类的成员函数addAppToken来为它增长一个AppWindowToken,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
WindowManagerService类有三个成员变量mTokenMap、mTokenList和mAppTokens,它们都是用来描述系统中的窗口的。
成员变量mTokenMap指向的是一个HashMap,它里面保存的是一系列的WindowToken对象,每个WindowToken对象都是用 来描述一个窗口的,而且是以描述这些窗口的一个Binder对象的IBinder接口为键值的。例如,对于Activity组件类型的窗口来讲,它们分别 是以用来描述它们的一个ActivityRecord对象的IBinder接口保存在成员变量mTokenMap所指向的一个HashMap中的。
成员变量mTokenList指向的是一个ArrayList,它里面保存的也是一系列WindowToken对象,这些WindowToken对象与 保存在成员变量mTokenMap所指向的一个HashMap中的WindowToken对象是同样的。成员变量mTokenMap和成员变量 mTokenList的区别就在于,前者在给定一个IBinder接口的状况下,能够迅速指出是否存在一个对应的WindowToken对象,然后者能够 迅速遍历WindowManagerService服务中的WindowToken对象。
成员变量mAppTokens指向的也是一个ArrayList,不过它里面保存的是一系列AppWindowToken对象,每个 AppWindowToken对象都是用来描述一个Activity组件窗口的,而这些AppWindowToken对象是以它们描述的窗口的Z轴坐标由 小到大保存在这个ArrayList中的,这样咱们就能够经过这个ArrayList来从上到下或者从下到上地遍历系统中的全部Activity组件窗 口。因为这些AppWindowToken对象所描述的Activity组件窗口也是一个窗口,而且AppWindowToken类是从 WindowToken继承下来的,所以,这些AppWindowToken对象还会同时被保存在成员变量mTokenMap所指向的一个HashMap 和成员变量mTokenList所指向的一个ArrayList中。
理解了WindowManagerService类的这三个成员变量的含义以后,它的成员函数addAppToken的实现就好理解了,其中,参数 token指向的即是用来描述正在启动的Activity组件所对应的一个ActivityRecord对象,而参数addPos用来描述该 Activity组件在堆栈中的位置,这个位置同时也是接下来要建立的AppWindowToken对象在WindowManagerService类的 mTokenList所描述的一个ArrayList中的位置。
WindowManagerService类的成员函数addAppToken首先调用另一个成员函数findAppWindowToken来在成员 变量mTokenMap所描述的一个HashMap检查是否已经存在一个AppWindowToken。若是已经存在的话,那么 WindowManagerService类的成员函数addAppToken就什么也不作就返回了,不然的话,就会使用参数token来建立一个 AppWindowToken对象,而且会将该AppWindowToken对象分别保存在WindowManagerService类的成员变量 mTokenMap、mTokenList和mAppTokens中。
2. 删除AppWindowToken
删除AppWindowToken是经过调用WindowManagerService类的成员函数removeAppTokensLocked来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
WindowManagerService类的成员函数removeAppTokensLocked能够同时删除一组AppWindowToken对象。
参数tokens所描述的是一个IBinder接口列表,与这些IBinder接口所对应的AppWindowToken对象就是接下来要删除的。 WindowManagerService类的成员函数removeAppTokensLocked经过一个for循环来依次调用另一个成员函数 findAppWindowToken,以即可以找到保存在列表tokens中的每个IBinder接口所对应的AppWindowToken对象,然 后将该AppWindowToken对象从WindowManagerService类的成员变量mAppTokens所描述的一个ArrayList中 删除。
注意,WindowManagerService类的成员函数removeAppTokensLocked是在内部使用的,它只是把一个 AppWindowToken对象从成员变量mAppTokens中删除,而没有从另外两个成员变量mTokenMap和mTokenList中删除。
3. 移动AppWindowToken至指定位置
移动AppWindowToken至指定位置是经过调用WindowManagerService类的成员函数moveAppToken来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
参数token描述的是要移动的AppWindowToken对象所对应的一个IBinder接口,而参数index描述的是该 AppWindowToken对象要移动到的位置。注意,移动一个AppWindowToken对象到指定的位置是须要 android.Manifest.permission.MANAGE_APP_TOKENS权限的。
WindowManagerService类的成员函数moveAppToken首先找到与参数token所对应的AppWindowToken对 象,而且将该AppWindowToken对象从WindowManagerService类的成员变量mAppTokens所描述的一个 ArrayList中移除,这样作的目的是为了接下来能够将该AppWindowToken对象移动至该ArrayList中的指定位置上,即参数 index所描述的位置上。
注意,上述操做只是将参数token所对应的AppWindowToken对象移动到了WindowManagerService类的成员变量 mAppTokens所描述的一个ArrayList的指定位置上,接下来还须要同时将与该AppWindowToken对象所对应的 WindowState对象移动至WindowManagerService服务内部的一个WindowState堆栈合适位置上去。
移动对应的WindowState对象的操做一样也是分两步执行的:第一步先调用WindowManagerService类的成员函数 tmpRemoveAppWindowsLocked来将这些WindowState对象从原来的WindowState堆栈位置移除;第二步再调用 WindowManagerService类的成员函数reAddAppWindowsLocked来将这些WindowState对象插入到 WindowState堆栈的合适位置去。
对应的WindowState对象被移动到的合适位置是经过调用WindowManagerService类的成员函数findWindowOffsetLocked来得到的,它的实现以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
参数tokenPos描述的是一个AppWindowToken对象在WindowManagerService类的成员变量mAppTokens所描述 的一个ArrayList的位置,WindowManagerService类的成员函数findWindowOffsetLocked的目标就要找到与 该AppWindowToken对象所对应的WindowState对象在WindowManagerService服务内部的一个 WindowState堆栈的起始偏移位置。有了这个起始偏移位置以后,咱们就能够将对应的全部WindowState对象有序地插入到该 WindowState堆栈中去。WindowManagerService服务内部的WindowState堆栈是经过 WindowManagerService类的成员变量mWindows来描述的。接下来咱们就分两种状况来分析这个起始偏移位置的计算过程。
第一种状况是参数tokenPos的值大于WindowManagerService类的成员变量mAppTokens所描述的一个ArrayList的 大小。这是一种异常状况,通常来讲,参数tokenPos是指向mAppTokens列表的某一个位置的,不过这时候意味着它所描述的 AppWindowToken对象的Z轴位置要大于mAppTokens列表的最上面的一个AppWindowToken对象的Z轴位置的。这也就是说, 与参数tokenPos所描述的AppWindowToken对象所对应的WindowState对象的要位于与mAppTokens列表的最上面的一个 AppWindowToken对象所对应的任一个WindoState对象的上面。所以,就须要找到与mAppTokens列表的最上面的一个 AppWindowToken对象所对应的Z轴位置最大的一个WindoState对象在WindowState堆栈中的位置i,而后就能够知道与参数 tokenPos所描述的AppWindowToken对象所对应的WindowState对象在WindowState堆栈的起始偏移位置为i+1。
如何找到mAppTokens列表的最上面的一个AppWindowToken对象所对应的Z轴位置最大的一个WindoState对象在 WindowState堆栈中的位置i呢?从图1能够可获得一个结论:WindowManagerService服务内部中的全部WindowState 对象都是按照Z轴从位置从小到大排列在WindowState堆栈中的,而且在mAppTokens列表中,位于上面的一个AppWindowToken 对象所对应的那些WindowState对象的Z轴位置是必定大于位于下面的一个AppWindowToken对象所对应的那些WindowState对 象的Z轴位置的。所以,咱们只要从WindowState堆栈的顶端开始往下遍历,找到这样的一个WindowState对象,它是属于一个 AppWindowToken对象的,即它的成员函数getAppToken的返回值不等于null,那么它在WindowState堆栈中的位置就是我 们要找到的位置i。有了这个位置i以后,将它的值加上1,就能够获得参数t所描述的AppWindowToken对象所对应的WindowState对象 在WindowState堆栈的起始偏移位置了。
第二种状况是参数tokenPos的值小于WindowManagerService类的成员变量mAppTokens所描述的一个ArrayList的 大小。根据前面获得的推论,咱们只要在mAppTokens列表中找到一个AppWindowToken对象,它知足如下三个条件:
A. 它在mAppTokens列表中的位置小于tokenPos;
B. 它在WindowState堆栈中对应有WindowState对象;
C. 它不是将要置于WindowState堆栈的底部。
若是一个AppWindowToken对象在WindowState堆栈中对应有WindowState对象,那么这些WindowState对象也会同 时按照Z轴从小到大的顺序保存它的成员变量windows所描述的一个ArrayList中,这意味着若是一个AppWindowToken对象知足条件 B,那么它的成员变量windows所描述的一个ArrayList的大小就大于0。
若是一个AppWindowToken对象不是将要置于WindowState堆栈的底部,那么它的成员变量sendingToBottom的值就不等于true,这也意味这个AppWindowToken对象知足条件C。
若是能找到知足上述条件的一个AppWindowToken对象wtoken,那么咱们只要找到与它所对应的Z轴位置最大的WindowState对象在 WindowManagerService服务内部的WindowState堆栈中的位置i,那么将它的值加1,就能够获得与参数tokenPos所描述 的AppWindowToken对象所对应的WindowState对象在WindowState堆栈的起始偏移位置了。
那么如何找到与这个AppWindowToken对象wtoken对应的Z轴位置最大的WindowState对象在 WindowManagerService服务内部的WindowState堆栈中的位置i呢?从前面的图1能够知道,一个AppWindowToken 对象所对应的WindowState对象能够划分为两种类型:第一种类型是父窗口类型的;第二种是子窗口类型的。若是一个WindowState对象所描 述的窗口是父窗口,那么它的子窗口就保存在它的成员变量mChildWindows所描述的一个ArrayList中,而且这些子窗口是按照Z轴位置从小 到大的顺序排列的,同时,该WindowState对象也会保存在与它所对应的一个AppWindowToken对象的成员变量windows所描述的一 个ArrayList中。
有了上述结论,而且假设存在一个可以知足上述三个条件的AppWindowToken对象wtoken,那么就能够从上到下遍历保存在它的成员变量windows所描述的一个ArrayList中的每个WindowState对象win:
I. 若是WindowState对象win所描述的一个窗口具备子窗口,那么就继续从上到下遍历这些子窗口,即从上到下遍历WindowState对象win 的成员变量mChildWindows所描述的一个ArrayList。若是能找到一个WindowState对象cwin,它的成员变量 mSubLayer的值大于等于0,那么该WindowState对象cwin在WindowManagerService服务内部的 WindowState堆栈中的位置就是咱们要获得的位置i。注意,若是WindowState对象cwin的成员变量mSubLayer的值小于0,那 么它虽然是一个子窗口,可是它倒是位于父窗口的后面的,即它的Z轴位置是小于父窗口的Z轴位置的。
II. 若是WindowState对象win所描述的一个窗口不具备子窗口,即它的成员变量mChildWindows所描述的一个ArrayList的大小等 于0,那么它在WindowManagerService服务内部的WindowState堆栈中的位置就是咱们要获得的位置i。
获得了位置i以后,将它的值加1,那么就能够获得与参数tokenPos所描述的AppWindowToken对象所对应的WindowState对象在WindowState堆栈的起始偏移位置了。
回到WindowManagerService类的成员函数moveAppToken中,调整好参数token所描述的AppWindowToken对象 所对应的WindowState对象在WindowState堆栈中的位置以后,即调用了成员函数reAddAppWindowsLocked以后,这时 候系统中的窗口的布局就会发生了变化,即系统中的窗口的Z轴位置关系发生了变化,那么接下来就须要调用成员函数 updateFocusedWindowLocked来从新计算系统中的窗口的Z轴位置,而且调用成员函数 performLayoutAndPlaceSurfacesLocked来从新布局系统中的窗口。
4. 移动AppWindowToken至顶端
移动AppWindowToken至顶端是经过调用WindowManagerService类的成员函数moveAppTokensToTop来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
WindowManagerService类的成员函数moveAppTokensToTop能够同时将一组AppWindowToken移至顶端,同时 须要调用者具备android.Manifest.permission.MANAGE_APP_TOKENS权限。
参数tokens所描述的是一个IBinder接口列表,与这些IBinder接口所对应的AppWindowToken对象就是接下来要移至顶端 的。在将保存在参数tokens中的IBinder接口所对应的AppWindowToken对象移至顶端之 前,WindowManagerService类的成员函数首先会调用前面所描述的成员函数removeAppTokensLocked来删除这些 AppWindowToken对象,而后再依次将它们添加到WindowManagerService类的成员变量mAppTokens所描述的一个 ArrayList的末尾去。
注意,WindowManagerService类的成员变量mNextAppTransition用来描述系统当前是否正在切换Activity窗口。 若是是的话,那么它的值就不等于WindowManagerPolicy.TRANSIT_UNSET,这时候就须要:
A. 将全部要移至顶端的AppWindowToken对象都保存在WindowManagerService类的另一个成员变量mToTopApps所描述 的一个ArrayList中去,而且将这些AppWindowToken对象的成员变量sendingToTop的值设置为true。
B. 将全部要移至顶端的AppWindowToken对象所对应WindowState对象都移至WindowManagerService服务内部 的一个WindowState堆栈的顶端去,这是经过调用另一个成员函数moveAppWindowsLocked来实现的。
执行完成上述两个操做以后,与要移至顶端的AppWindowToken对象所对应的窗口就会位于窗口堆栈的最上面了。
5. 移动AppWindowToken至底端
移动AppWindowToken至顶端是经过调用WindowManagerService类的成员函数moveAppTokensToBottom来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
WindowManagerService类的成员函数moveAppTokensToBottom能够同时将一组AppWindowToken移至底 端。将一组AppWindowToken移至底端与将一组AppWindowToken移至顶端的实现是相似的,只不过是移动的方向相反而已。因 此,WindowManagerService类的成员函数moveAppTokensToBottom的实现能够参考前面所分析的成员函数 moveAppTokensToTop的实现,这里再也不详述。
6. 增长WindowToken
从图1能够知道,若是一个WindowState对象不是与一个AppWindowToken对象对应的,那么它就必需要与一个WindowToken对 象对应。例如,用来描述输入法窗口和壁纸窗口的WindowState对象对应的就是WindowToken对象,而不是AppWindowToken对 象,由于它们不是Activity类型的窗口。
输入法窗口和壁纸窗口分别是由输入法管理服务InputMethodManagerService和壁纸管理服务 WallpaperManagerService调用WindowManagerService类的成员函数addWindowToken来增长对应的 WindowToken对象的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
调用WindowManagerService类的成员函数addWindowToken须要具备android.Manifest.permission.MANAGE_APP_TOKENS权限。
对于输入法窗口和壁纸窗口来讲,参数token指向的是与它们所关联的一个Binder对象的IBinder接口,而参数type描述的是要在WindowManagerService服务内部增长WindowToken对象的窗口的类型。
WindowManagerService类的成员函数addWindowToken首先检查在成员变量mTokenMap所描述的一个 HashMap检查是否已经存在一个WindowToken对象与参数token对应。若是已经存在的话,那么WindowManagerService 类的成员函数addWindowToken就什么也不作就返回了,不然的话,就会使用参数token来建立一个WindowToken对象,而且会将该 WindowToken对象分别保存在WindowManagerService类的成员变量mTokenMap和mTokenList中。
这里有两个地方须要注意:
A. 因为这里增长的是WindowToken对象,而不是AppWindowToken对象,所以,与增长AppWindowToken不一样,这里不须要将新 建立的WindowToken对象保存在WindowManagerService类的成员变量mAppTokens中。
B. 若是参数type的值等于TYPE_WALLPAPER,那么就意味着新建立的WindowToken对象是用来描述壁纸窗口的,这时候还须要将新建立的 WindowToken对象保存在WindowManagerService类的成员变量mWallpaperTokens所描述的一个 ArrayList中,以方便管理壁纸窗口。
对于非输入法窗口、非壁纸窗口以及非Activity窗口来讲,它们所对应的WindowToken对象是在它们增长到WindowManagerService服务的时候建立的。从前面Android应用程序窗口(Activity)与WindowManagerService服务的链接过程分析一文能够知道,增长一个窗口WindowManagerService服务最终是经过调用WindowManagerService类的成员函数addWindow来实现的,接下来咱们就主要分析与建立WindowToken相关的逻辑,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
若是参数attrs所描述的一个WindowManager.LayoutParams对象的成员变量token所指向的一个IBinder接口在 WindowManagerService类的成员变量mTokenMap所描述的一个HashMap中没有一个对应的WindowToken对象,而且 该WindowManager.LayoutParams对象的成员变量type的值不等于TYPE_INPUT_METHOD、 TYPE_WALLPAPER,以及不在FIRST_APPLICATION_WINDOW和LAST_APPLICATION_WINDOW,那么就意 味着这时候要增长的窗口就既不是输入法窗口,也不是壁纸窗口和Activity窗口,所以,就须要以参数attrs所描述的一个 WindowManager.LayoutParams对象的成员变量token所指向的一个IBinder接口为参数来建立一个WindowToken 对象,而且将该WindowToken对象保存在WindowManagerService类的成员变量mTokenMap和mTokenList中。
7. 删除WindowToken
删除WindowToken是经过调用WindowManagerService类的成员函数removeWindowToken来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
调用WindowManagerService类的成员函数removeWindowToken须要具备android.Manifest.permission.MANAGE_APP_TOKENS权限。
WindowManagerService类的成员函数removeWindowToken首先找到与参数token所描述的Binder接口所对应的 WindowToken对象,接着再将该WindowToken对象从WindowManagerService类的成员变量mTokenMap和 mTokenList中删除。
删除了一个WindowToken对象以后,若是该WindowToken对象不是处于不可见的状态,即它的成员变量hidden的值不等于false, 那么就意味着它所描述窗口口也有多是可见的,那么WindowManagerService类的成员函数removeWindowToken就须要做以 下两个检查:
A. 若是该WindowToken对象所描述的窗口的其中一个处于动画显示过程,即用来描述该窗口的一个WindowState对象的成员函数 isAnimating的返回值等于true,那么就须要该WindowToken对象的状态设置为正在退出状态,即将它保存在 WindowManagerService类的成员变量mExitingTokens所描述的一个ArrayList中。
B. 若是该WindowToken对象所描述的窗口是可见的,即用来描述该窗口的一个WindowState对象的成员函数isVisibleNow的 返回值等于true,那么就须要调用WindowManagerService类的成员函数applyAnimationLocked来给它应用一个退出 动画,该退出动画是经过调用WindowManagerService类的成员函数 performLayoutAndPlaceSurfacesLocked来实现的。当一个窗口退出了以后,系统当前得到焦点的窗口可能会发生变化,这时 候就须要调用WindowManagerService类的成员函数updateFocusedWindowLocked来从新调整系统当前得到焦点的窗 口。
注意,若是正在删除的WindowToken对象是用来描述壁纸窗口的,那么还须要将该WindowToken对象从WindowManagerService类的成员变量mWallpaperTokens所描述的一个ArrayList中删除。
8. 增长WindowState
从前面Android应用程序窗口(Activity)与WindowManagerService服务的链接过程分析一文能够知道,增长一个窗口WindowManagerService服务最终是经过调用WindowManagerService类的成员函数addWindow来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
WindowManagerService类有两个成员变量mWindowMap和mWindows是用来保存系统中的WindowState对象。 其中,成员变量mWindowMap指向的是一个HashMap,它的关键字是一个IBinder接口,通常这个IBinder接口指向的是一个 Binder代理对象,引用了运行在应用程序进程这一侧的一个类型为W的Binder本地对象,用来描述一个窗口;成员变量mWindows指向的是一个 ArrayList,保存在它里面的WindowState对象是按照其Z轴位置从小到大的顺序排列的。成员变量mWindowMap和mWindows 的区别在于,前者给在定一个IBinder接口的状况下,能够快速找到与对应的WindowState对象,然后者用来从上到下或者下到上遍历系统的 WindowState对象。因为系统中的WindowState对象是按照其Z轴位置从小到大的顺序排列在成员变量mWindows中的,所以,成员变 量mWindows所指向的ArrayList就是咱们在前面图1中所说的Window Stack。
理解了WindowManagerService类有两个成员变量mWindowMap和mWindows的做用以后,WindowManagerService类的成员函数addWindow增长一个WindowState对象的过程就容易理解了。
参数client是一个Binder代理对象,引用了运行在应用程序进程这一侧的一个类型为W的Binder本地对象,用来描述要增长到 WindowManagerService服务中的一个窗口。WindowManagerService类的成员函数addWindow首先建立一个 WindowState对象win,接着再以参数client所描述的一个Binder代理对象的IBinder接口为关键字,将WindowState 对象win保存在WindowManagerService类的成员变量mWindowMap中,最后还会根据要增长到 WindowManagerService服务中的窗口的类型来调用不一样的成员函数将WindowState对象win增长到 WindowManagerService类的成员变量mWindows中:
A. 若是要增长的是输入法窗口,即参数attrs所描述的一个WindowManager.LayoutParams对象的成员变量type的值等于 TYPE_INPUT_METHOD,那么就会调用成员函数addInputMethodWindowToListLocked来将 WindowState对象win增长到WindowManagerService类的成员变量mWindows中去,而且会将WindowState对 象win保存在WindowManagerService类的成员变量mInputMethodWindow中。
B. 若是要增长的是输入法对话框,即参数attrs所描述的一个WindowManager.LayoutParams对象的成员变量type的值等于 TYPE_INPUT_METHOD_DIALOG,那么就会调用成员函数addWindowToListInOrderLocked来将 WindowState对象win增长到WindowManagerService类的成员变量mWindows中去,而且会将WindowState对 象win保存在WindowManagerService类的成员变量mInputMethodDialogs中,以及调用成员函数 adjustInputMethodDialogsLocked来调整刚才所添加的输入法窗口在窗口堆栈中的位置,使得它位于系统当前须要输入法窗口的窗 口的上面。
C. 若是要增长的是壁纸窗口,即参数attrs所描述的一个WindowManager.LayoutParams对象的成员变量type的值等于 TYPE_WALLPAPER,那么就会调用成员函数addWindowToListInOrderLocked来将WindowState对象win增 加到WindowManagerService类的成员变量mWindows中去,而且会调用成员函数 adjustWallpaperWindowsLocked来调整刚才所添加的壁纸窗口在窗口堆栈中的位置,使得它位于系统当前须要壁纸窗口的窗口的下 面。
D . 若是要增长的既不是输入法窗口,也不是输入法对话框和壁纸窗口,那么就只会调用成员函数addWindowToListInOrderLocked来将 WindowState对象win增长到WindowManagerService类的成员变量mWindows中去,可是若是要增长的窗口须要显示壁 纸,即参数attrs所描述的一个WindowManager.LayoutParams对象的成员变量flags的 FLAG_SHOW_WALLPAPER位等于1,那么还会继续调用成员函数adjustWallpaperWindowsLocked来调整系统中的壁 纸窗口在窗口堆栈中的位置,使得它位于刚才所添加的窗口的下面。
在后面的两篇文章中,咱们再详细分析WindowManagerService类的成员函数 addInputMethodWindowToListLocked、adjustInputMethodDialogsLocked和 adjustWallpaperWindowsLocked的实现,其中,前二者是与输入法窗口相关的,然后者是与壁纸窗口相关的。本文主要关注 WindowManagerService类的成员函数addWindowToListInOrderLocked的实现,它会将一个指定的 WindowState对象增长到窗口堆栈中的合适位置上去。
9. 增长WindowState到窗口堆栈
从前面的分析能够知道,将一个WindowState对象增长到WindowManagerService服务内部中的窗口堆栈,即 WindowManagerService类的成员变量mWindows,是经过调用WindowManagerService类的成员函数 addWindowToListInOrderLocked来实现的。
WindowManagerService类的成员函数addWindowToListInOrderLocked的实现比较复杂,咱们先列出它的框架,而后再详细分析它的实现,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
咱们首先分析一下WindowManagerService类的成员函数addWindowToListInOrderLocked的几个本地变量的含义:
A. token。本地变量token指向的是参数win所描述的一个WindowState对象的成员变量mToken所指向一个WindowToken对象,这个WindowToken对象用来描述WindowState对象win所对应的窗口令牌。
B. localmWindows。 本地变量localmWindows指向的是WindowManagerService类的成员变量mWindows所描述的一个ArrayList,即 一个窗口堆栈,WindowManagerService类的成员函数addWindowToListInOrderLocked的目标就是要将参数 win所描述的一个WindowState对象增长到该窗口堆栈的合适位置上去。
C. attached。 本地变量attached指向的是参数win所描述的一个WindowState对象的成员变量mAttachedWindow 所指向的一个WindowState对象,若是它的值不等于null,那么就意味参数win所描述的窗口要附加在本地变量attached所描述的窗口 上。
D. tokenWindowsPos。本地变量tokenWindowsPos用来描述与窗口令牌token所对应的窗口的数量。
E. token.appWindowToken。从前面Android应用程序窗口(Activity)与WindowManagerService服务的链接过程分析一 文能够知道,若是一个WindowToken对象的成员变量appWindowToken的值不等于null,那么就意味着该WindowToken对象 的实际类型为是AppWindowToken,即它所描述的是一个Activity窗口令牌,这种类型的令牌的特色是在 ActivityManagerService服务的Activity组件堆栈中对应有一个ActivityRecord对象,如图1所示。
F. index。本地变量index的值等于tokenWindowsPos-1,若是它的值大于等于0,那么就意味着窗口令牌tokent已经存在其它窗口,不然的话,就意味着窗口令牌tokent还没有存在任何窗口。
从这些本地变量的含义,咱们就能够分状况来将参数win所描述的一个WindowState对象增长到WindowManagerService服务内部的窗口堆栈的合适位置上去:
CASE 1:要增长的窗口win没有附加在其它窗口上
----CASE 1.1:要增长的窗口win是一个Activity窗口
----CASE 1.1.1:用来要增长的窗口win的令牌token已存在其它窗口。这时候意味着窗口win须要保存在其它已经存在的窗口的附近,所以,咱们只要找到这些已经存在的窗口在窗口堆栈中的位置,那么再根据其它属性,就能够将窗口win保存在已经存在的窗口的上面或者下面。
----CASE 1.1.2: 用来要增长的窗口win的令牌token还没有存在任何窗口。虽然这时候窗口win在窗口堆栈中没有位置能够参考,可是它毕竟是一个Activity窗口, 咱们能够经过与它所对应的AppWindowToken对象在App Token List(即WindowManagerService类的成员变量mAppTokens所描述的一个ArrayList)中的位置来得到它窗口堆栈中的 位置。回忆咱们在前面第3节分析移动AppWindowToken至指定位置的操做时获得的结论:WindowManagerService服务内部中的 全部WindowState对象都是按照Z轴从位置从小到大排列在WindowState堆栈中的,而且在mAppTokens列表中,位于上面的一个 AppWindowToken对象所对应的那些WindowState对象的Z轴位置是必定大于位于下面的一个AppWindowToken对象所对应的 那些WindowState对象的Z轴位置的。所以,咱们只要找到用来描述窗口win的一个AppWindowToken对象 (token.appWindowToken)的上一个或者下一个AppWindowToken对象所对应的窗口在窗口堆栈中的位置,那么就能够这个位置 为参考,获得窗口win在窗口堆栈中的位置。
----CASE 1.2:要增长的窗口win不是一个Activity窗口。这时候既然要增长的窗口也没有附加在其它窗口上,那么就意味着要增长的窗口win在窗口堆栈中没有位置能够参考,所以,咱们就须要根据它的Z轴位置来决定它在窗口堆栈的位置。
CASE 2:要增长的窗口win附加在窗口attached上。这时候就意味着要增长的窗口win要保存在窗口attached的上面,即窗口在窗口堆栈的位置要以窗口attached在窗口堆栈的位置为参考。
从上面的分析就能够知道,CASE 1.1.1、CASE 1.1.2和CASE 2都有一个共同特色,即要增长的窗口win在窗口堆栈的位置有一个参考值,而在CASE 1.2中,要增长的窗口win在窗口堆栈的位置没有参考值,须要经过其Z轴位置来肯定。
在分析上述四种状况以前, 咱们还须要再说明一下WindowManagerService类的成员函数addWindowToListInOrderLocked的参数 addToToken的含义。参数addToToken是一个布尔变量,若是它的值等于true,那么就说明须要将参数win所描述的一个 WindowState对象添加用来描述它的窗口令牌token的成员变量windows所描述的一个ArrayList中去。注意,窗口令牌token 的成员变量windows所描述的一个ArrayList里面所保存的WindowState对象是按照Z轴位置从小到大的顺序来排列的,所以,在将 WindowState对象win保存到这个ArrayList以前,首先要按照它的Z轴位置计算获得它在这个ArrayList中的位置 tokenWindowsPos。另外一方面,在参数addToToken的值等于true,而且参数win所描述的是一个Activity窗口,即它的成 员变量mAppToken不等于null的状况下,还须要将参数win所描述的一个WindowState对象保存在用来描述它的窗口令牌,即一个 AppWindowToken对象成员变量allAppWindows所描述的一个ArrayList中去,以即可以知道一个 AppWindowToken对象对应的Activity窗口都有哪些。
接下来,咱们就分别分析这四种状况是如何将窗口win增长窗口堆栈中去的。
CASE 1.1.1对应的代码为:
这段代码又分为三种状况来将参数win所描述的一个WindowState对象添加到窗口堆栈中:
A. 参数win描述的窗口的类型为TYPE_BASE_APPLICATION。在一个令牌对应的全部窗口中,类型为 TYPE_BASE_APPLICATION的窗口位于其它类型的窗口的下面。所以,这段代码就会调用WindowManagerService类的成员 函数placeWindowBefore来将参数win所描述的一个WindowState对象保存窗口堆栈中,而且它是位于令牌token的窗口列表的 第0个位置的WindowState对象的下面。这时候变量tokenWindowsPos的值会被设置为0,表示参数win所描述的一个 WindowState对象要保存窗口令牌token的窗口列表的第0个位置上。
B. 参数win描述的一个WindowState对象的成员变量mAppToken的值不等于null,这意味着参数win描述的是一个Activity窗 口,这时候若是窗口令牌atoken(与token描述的是同一个窗口令牌)的窗口列表的第index个位置(即最上面的一个位置) 的WindowState对象描述的是一个Activity启动窗口,即与窗口令牌atoken的成员变量startingWindow描述的是同一个窗 口,那么就说明窗口令牌atoken的窗口列表的第index个位置的WindowState对象描述的是窗口win的启动窗口。因为一个窗口的启动窗口 老是位于它的上面,所以,这段代码就会调用WindowManagerService类的成员函数placeWindowBefore来将参数win所描 述的一个WindowState对象保存窗口堆栈中,而且它是位于令牌atoken的窗口列表的第index个位置的WindowState对象的下面。 这时候变量tokenWindowsPos的值减小1,即至关因而等于index,表示参数win所描述的一个WindowState对象要插入在窗口令 牌token的窗口列表的第index个位置上。
C. 参数win所描述的窗口的类型既不是TYPE_BASE_APPLICATION,并且它也没有启动窗口,那么这时候就须要将它保存在窗口令牌token 的窗口列表的最上面一个窗口的上面。窗口令牌token的窗口列表的最上面一个窗口在窗口堆栈中的位置newIdx是经过调用 WindowManagerService类的成员函数findIdxBaseOnAppTokens来得到的,这时候参数win所描述的一个 WindowState对象就应该保存在窗口堆栈,即变量localmWindows所描述的一个ArrayList的第newIdx+1个位置上。
CASE 1.1.2对应的代码为:
这段代码要能冠军WindowManagerService服务内部的一个AppWindowToken列表mAppTokens来在窗口堆栈中找到一个参数位置来保存参数win所描述的一个WindowState对象。
最上面的一个for循环执行完成以后,咱们假设变量pos的值不等于null,这时候它与变量i以及变量token的关系如图2所示:
图2 窗口win位于窗口C的下面
这时候位于令牌token上面的令牌在窗口堆栈中对应有WindowState对象。注意,这时候第i+2个令牌在窗口堆栈中不对应有 WindowState对象,而第i+3个令牌在窗口堆栈中对应有C和D两个WindowState对象,而且这两个WindowState对象所描述的 窗口都不是即将要切换到窗口堆栈的底部的。因为第i+3个令牌位于令牌token的上面,而且这两个令牌之间的其它令牌在窗口堆栈中不对应有 WindowState对象,所以,这时候参数win所描述的WindowState对象在窗口堆栈中的位置应该以第i+3个令牌所对应的Z轴位置最小的 WindowState对象在窗口堆栈中的位置为参考,即以WindowState对象C在窗口堆栈中的位置为参考,而WindowState对象C也正 好是变量pos所指向的WindowState对象。
接下来,上述代码会继续检查WindowState对象C是否附加有SubLayer值小于0的窗口。若是有的话,那么就会将变量pos指向 SubLayer值最小的那个WindowState对象,这是由于该WindowState对象是在WindowState对象C的最下面的,而且它与 WindowState对象C是同属一个令牌的。最后,上述代码就会调用WindowManagerService类的成员函数 placeWindowBefore来将参数win所描述的一个WindowState对象保存窗口堆栈中由变量pos所指向的那个 WindowState对象的下面。
假设最上面的一个for循环执行完成以后,变量pos的值等于null,那么就说明位于令牌token上面的令牌在窗口堆栈中都没有对应有 WindowState对象,或者说它们所对应的WindowState对象都是即将要切换到窗口堆栈的底部去的,这时候就须要经过位于令牌token上 面的令牌来在窗口堆栈中找到一个参考位置来保存参数win所描述的WindowState对象,这是经过中间的while循环来实现的。
中间的while循环执行完成以后,假设变量pos的值不等于null,这时候它与变量i以及变量token的关系如图3所示:
图3 窗口win位于窗口D的上面
这时候位于令牌token上面的令牌在窗口堆栈中没有对应有WindowState对象。注意,这时候第i-1个令牌在窗口堆栈中不对应有 WindowState对象,而第i-2个令牌在窗口堆栈中对应有C和D两个WindowState对象。因为第i-2个令牌位于令牌token的下面, 而且这两个令牌之间的其它令牌在窗口堆栈中不对应有WindowState对象,所以,这时候参数win所描述的WindowState对象在窗口堆栈中 的位置应该以第i-2个令牌所对应的Z轴位置最大的WindowState对象在窗口堆栈中的位置为参考,即以WindowState对象D在窗口堆栈中 的位置为参考,而WindowState对象D也正好是变量pos所指向的WindowState对象。
接下来,上述代码会继续检查WindowState对象D是否附加有SubLayer值大于等于0的窗口。若是有的话,那么就会将变量pos指向 SubLayer值最大的那个WindowState对象,这是由于该WindowState对象是在WindowState对象D的最上面的,而且它与 WindowState对象D是同属一个令牌的。最后,上述代码就会调用WindowManagerService类的成员函数 placeWindowAfter来将参数win所描述的一个WindowState对象保存窗口堆栈中由变量pos所指向的那个WindowState 对象的上面。
假设中间的while循环执行完成以后,变量pos的值等于null,这时候就说明在窗口堆栈中实在是找不到参考位置来保存参数win所描述的 WindowState对象了,所以,就只能经过参数win所描述的WindowState对象的Z轴位置,即它的成员变量mBaseLayer的值来在 窗口堆栈中找到一个合适的位置了,如最下面的for循环所示。因为窗口堆栈中的WindowState对象是按照它们的Z轴位置由小到大的顺序来排列的, 所以,最下面的for循环只要从下到上找到一个Z轴位置比参数win所描述的WindowState对象的Z轴位置大的一个WindowState对象在 窗口堆栈中的位置i,那么就能够将参数win所描述的WindowState对象插入在窗口堆栈的第i个位置上了。
CASE 1.2对应的代码为:
因为这时候在窗口堆栈中是没有参考位置来保存参数win所描述的WindowState对象的,所以,这段代码就只能经过参数win所描述的 WindowState对象的Z轴位置,即它的成员变量mBaseLayer的值来在窗口堆栈中找到一个合适的位置了,如这段代码中的for循环所示。由 于窗口堆栈中的WindowState对象是按照它们的Z轴位置由小到大的顺序来排列的,所以,这段代码中的for循环只要从上到下找到一个 WindowState对象,它的Z轴位置小于或者等于参数win所描述的WindowState对象的Z轴位置,那么该WindowState对象在窗 口堆栈中的位置i就能够用插入参数win所描述的WindowState对象了。
CASE 2对应的代码为:
这段代码要将参数win所描述的WindowState对象附加在变量attached所描述的WindowState对象的上面或者下面,取决于它的成员变量mSubLayer的值是大于0仍是小于0。咱们分四种状况来考虑。
第一种状况是参数win所描述的WindowState对象的成员变量mSubLayer的值小于0,而且这时候在附加在窗口attached的 WindowState对象中,存在一个WindowState对象,它的成员变量mSubLayer的值大于等于参数win所描述的 WindowState对象的成员变量mSubLayer的值,如图4和图5所示:
图4 窗口win插入到窗口B的下面
图5 窗口win插入在窗口attached的下面
在图4和图5中,WindowState对象A和B均是附加在WindowState对象attached中。
在图4中,WindowState对象A和B的成员变量mSubLayer的值均小于0,而WindowState对象win的成员变量 mSubLayer的值比WindowState对象A的大,可是比WindowState对象B的小,这时候WindowState对象win在窗口堆 栈中就应该位于WindowState对象B的下面,这是经过调用WindowManagerService类的成员函数 placeWindowBefore来实现的。
在图5中,WindowState对象A和B的成员变量mSubLayer的值均大于0,因为WindowState对象win的成员变量 mSubLayer的值小于0,这时候WindowState对象win在窗口堆栈中就应该位于WindowState对象attached的下面,这是 经过调用WindowManagerService类的成员函数placeWindowBefore来实现的。
第二种状况是参数win所描述的WindowState对象的成员变量mSubLayer的值大于0,而且这时候在附加在窗口attached的 WindowState对象中,存在一个WindowState对象,它的成员变量mSubLayer的值大于参数win所描述的WindowState 对象的成员变量mSubLayer的值,如图6所示:
图6 窗口win插入在窗口B的下面
在图6中,WindowState对象A和B均是附加在WindowState对象attached中。其中,WindowState对象A和B的成员变量mSubLayer的值均大于0,而WindowState对象win的成员变量mSubLayer的值比WindowState对象A的大,可是比WindowState对象B的小,这时候WindowState对象win在窗口堆栈中就应该位于WindowState对象B的下面,这是经过调用WindowManagerService类的成员函数placeWindowBefore来实现的。
第三种状况是参数win所描述的WindowState对象的成员变量mSubLayer的值小于0,可是在附加在窗口attached的WindowState对象中,找不到一个WindowState对象,它的成员变量mSubLayer的值比WindowState对象的成员变量mSubLayer的值大,如图7所示:
图7 窗口win插入在窗口attached的下面
在图7中,WindowState对象A和B均是附加在WindowState对象attached中。其中,WindowState对象A和B以及win的成员变量mSubLayer的值均小于0,可是WindowState对象win的成员变量mSubLayer的值比WindowState对象A和B的都要大,这时候WindowState对象win在窗口堆栈中就应该位于WindowState对象attached的下面,这是经过调用WindowManagerService类的成员函数placeWindowBefore来实现的。
第四种状况是参数win所描述的WindowState对象的成员变量mSubLayer的值大于等于0,可是在附加在窗口attached的WindowState对象中,找不到一个WindowState对象,它的成员变量mSubLayer的值比WindowState对象的成员变量mSubLayer的值大,如图8和图9所示:
图8 窗口win插入在窗口B的上面
图9 窗口win插入在窗口attached的上面
在图8和图9中,WindowState对象A和B均是附加在WindowState对象attached中。
在图8中,WindowState对象A和B的成员变量mSubLayer的值均大于0,而且WindowState对象win的成员变量mSubLayer的值比WindowState对象A和B的都要大,这时候WindowState对象win在窗口堆栈中就应该位于WindowState对象B的上面,这是经过调用WindowManagerService类的成员函数placeWindowAfter来实现的。
在图9中,WindowState对象A和B的成员变量mSubLayer的值均小于等于0,而WindowState对象win的成员变量mSubLayer的值大于0,这时候WindowState对象win在窗口堆栈中就应该位于WindowState对象attached的上面,这是经过调用WindowManagerService类的成员函数placeWindowAfter来实现的。
注意,在这四种状况中,若是参数addToToken的值等于true,那么都须要将参数win所描述的WindowState对象增长到与它所对应的窗口令牌token的窗口列表windows中去。
10. 删除WindowState
删除WindowState是经过调用WindowManagerService类的成员函数tmpRemoveWindowLocked来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
WindowManagerService类的成员函数tmpRemoveWindowLocked将参数win所描述的窗口及其子窗口从WindowManagerService服务内部的窗口堆栈中删除,即从 WindowManagerService类的成员变量mWindows所描述的一个ArrayList中删除。
若是每个被删除的窗口在窗口堆栈中的位置比参数interestingPos的值小,那么WindowManagerService类的成员函数tmpRemoveWindowLocked还会将参数interestingPos的值减小1,这至关因而计算当删除参数win所描述的窗口及其子窗口以后,原来位于窗口堆栈中第interestingPos个位置的窗口如今位于窗口堆栈的位置,这个位置最终会做为WindowManagerService类的成员函数tmpRemoveWindowLocked的返回值。
11. 在指定位置增长WindowState
在指定位置增长WindowState是经过调用WindowManagerService类的成员函数reAddWindowLocked来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
参数win描述的即为要增长的WindowState对象,而参数index描述的即为要将参数win所描述的WindowState对象及其子WindowState对象要增长到窗口堆栈中的起始位置。
因为参数win所描述的WindowState对象的子WindowState对象的成员变量mSubLayer的值可能会小于0,也可能大于0。大于 0的子WindowState对象位于参数win所描述的WindowState对象的上面,而小于0的子WindowState对象位于参数win所描 述的WindowState对象的下面。所以,WindowManagerService类的成员函数reAddWindowLocked先增长那些小于0的子WindowState对象,接着再增长参数win所描述的WindowState对象,最后增长那些大于0的子WindowState对象。
假设WindowManagerService类的成员函数reAddWindowLocked一共在窗口堆栈中增长了N个WindowState对象,那么它的返回值就等于index + N,这样调用者就能够知道参数win所描述的WindowState对象及其子WindowState对象在窗口堆栈中的最高位置是多少。
基于第九、第10和第11这三操做,能够组合成不少其它的WindowState操做,如接下来的第十二、第1三、第14和第15个操做所示。
12. 将一个WindowState对象及其全部子WindowState对象增长到窗口堆栈中
将一个WindowState对象及其全部子WindowState对象增长到窗口堆栈中是经过调用WindowManagerService类的成员函数reAddWindowToListInOrderLocked来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
为了获得参数win所描述的WindowState对象的子WindowState对象在窗口堆栈中的起始位置,WindowManagerService 类的成员函数reAddWindowToListInOrderLocked首先将参数win所描述的WindowState对象增长到窗口堆栈中,这是 经过调用前面所分析的成员函数addWindowToListInOrderLocked来实现的,目的是为了得到它在窗口堆栈的位置。有了这个位置之 后,WindowManagerService类的成员函数reAddWindowToListInOrderLocked就能够调用前面所分析的成员函数reAddWindowLocked来将WindowState对象及其全部子WindowState对象增长到窗口堆栈中去了,不过在调用以前,要先将参数win所描述的WindowState对象从窗口中堆栈删除。
13. 将一个WindowToken对象对应的全部WindowState对象及其子WindowState对象增长到窗口堆栈的指定位置上
将一个WindowToken对象对应的全部WindowState对象都增长到窗口堆栈中是经过调用WindowManagerService类的成员函数reAddAppWindowsLocked来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
与参数token所描述的WindowToken对象所对应的WindowState对象保存在它的成员变量windows所描述的一个ArrayList中。经过遍历这个ArrayList,就能够将与参数token所描述的WindowToken对象所对应的WindowState对象及其子WindowState对象都增长到窗口堆栈的指定的起始位置上去,这是经过调用前面所分析的成员函数reAddWindowLocked来实现的。
参数index描述的即是最初指定的起始位置,每一次调用WindowManagerService类的成员函数reAddWindowLocked以后,它的值都便会被更新为下一个WindowState对象及其子WindowState对象要增长到窗口堆栈中的位置。
最后,WindowManagerService类的成员函数reAddAppWindowsLocked将与参数token所描述的WindowToken对象所对应的WindowState对象在窗口堆栈中的最高位置加1后的获得结果返回给调用者。
14. 将一个AppWindowToken对象所对应的WindowState对象及其子 WindowState对象移动到窗口堆栈的指定位置上
将一个AppWindowToken对象所对应的WindowState对象及其子 WindowState对象移动到窗口堆栈的指定位置上是经过调用WindowManagerService类的成员函数moveAppWindowsLocked来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
参数wtoken描述的是要移动其所对应的WindowState对象的一个AppWindowToken对象,而参数tokenPos描述的是该 AppWindowToken对象在WindowManagerService服务内部的AppWindowToken列表中的新位置。
WindowManagerService 类的成员函数moveAppWindowsLocked首先调用前面所分析的成员函数tmpRemoveAppWindowsLocked来移除全部与参 数wtoken所描述的AppWindowToken对象所对应的WindowState对象,接着再调用也是前面所分析的成员函数 findWindowOffsetLocked来得到与参数wtoken所描述的AppWindowToken对象所对应的WindowState对象在窗口堆栈中的起始位置。有了这个起始位置以后,就能够也是前面所分析的成员函数reAddAppWindowsLocked来将与参数wtoken所描述的AppWindowToken对象所对应的WindowState对象及其子WindowState对象移动到窗口堆栈上去了。
最后,若是参数updateFocusAndLayout的值等于true,那么WindowManagerService类的成员函数moveAppWindowsLocked还会更新系统当前得到焦点的窗口,以及从新计算系统中的全部窗口的Z轴位置以及从新布局系统中的全部窗口,这三个操做分别是经过调用WindowManagerService类的成员函数updateFocusedWindowLocked、assignLayersLocked和performLayoutAndPlaceSurfacesLocked来实现的。
15. 将一组AppWindowToken对象所对应的WindowState对象及其子 WindowState对象移动到窗口堆栈的指定位置上
将一组AppWindowToken对象所对应的WindowState对象及其子WindowState对象移动到窗口堆栈的指定位置上是经过调用WindowManagerService类的另一个版本的成员函数moveAppWindowsLocked来实现的,以下所示:
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
这个操做与前面分析的第14个操做是相似,区别只在于前者是批量地移动一组AppWindowToken对象所对应的WindowState对象及其子 WindowState对象,然后者是只移动一个AppWindowToken对象所对应的WindowState对象及其子WindowState对象,此外,前者老是会调用WindowManagerService 类的成员函数updateFocusedWindowLocked、assignLayersLocked和 performLayoutAndPlaceSurfacesLocked来更新系统当前得到焦点的窗口、以及从新计算每个窗口的Z轴位置,而且对这些 窗口进行从新布局。
至此,咱们就分析完成WindowManagerService服务组织系统中的窗口的方式了。从分析的过程当中,能够获得如下结论:
1. WindowManagerService服务维护有一个AppWindowToken堆栈和一个WindowState堆栈,它们与ActivityManagerService服务维护的Actvity堆栈是有关相同的Z轴位置关系的。
2. ActivityManagerService服务中的每个ActivityRecord对象在WindowManagerService服务中都对应有一个AppWindowToken对象,而WindowManagerService服务中的每个AppWindowToken对象都对应有一组WindowState对象。
3. 在WindowState堆栈中,AppWindowToken堆栈中的第i+1个AppWindowToken对象所对应的WindowState对象都位于第i个AppWindowToken对象所对应的WindowState对象的上面。
4. 一个WindowState对象能够附加在另一个WindowState对象上面,此外,一个WindowState对象还能够有子WindowState对象,它们都是与同一个AppWindowToken对象或者WindowToken对象所对应的。
5. WindowManagerService服务有两个特殊的WindowToken,它们分别用来描述系统中的输入法窗口令牌和壁纸窗口令牌,其中,输入法窗口位于须要输入法的窗口的上面,而壁纸窗口位于须要壁纸的窗口的下面。
最后,咱们能够将WindowManagerService服务中的AppWindowToken理解成一个Activity组件令牌,而将它所对应的WindowState对象理解成一个Activity窗口。有了这些概念以后,就为学习WindowManagerService服务的各类实现打下坚实的基础。在接下来的两篇文章中,咱们就会在本文的基础上,继续分析WindowManagerService服务是如何管理系统中的输入法窗口和壁纸窗口的,敬请关注!
老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!