您现在的位置:首页 > 博客 > Android开发 > 正文
Android窗口管理服务WindowManagerService对窗口的组织方式分析
http://www.drovik.com/      2013-2-1 15:40:35      来源:老罗的Android之旅      点击:
     我们知道,在Android系统中,Activity是以堆栈的形式组织在ActivityManagerService服务中的。与Activity类似,Android系统中的窗口也是以堆栈的形式组织在WindowManagerService服务中的,其中,Z轴位置较低的窗口位于Z轴位置较高的窗口的下面。在本文中,我们就详细分析WindowManagerService服务是如何以堆栈的形式来组织窗口的。

        从前面Android应用程序启动过程源代码分析一文可以知道,应用程序进程中的每一个Activity组件在Activity管理服务ActivityManagerService中都对应有一个ActivityRecord对象。从前面Android应用程序窗口(Activity)与WindowManagerService服务的连接过程分析一文又可以知道,Activity管理服务ActivityManagerService中每一个ActivityRecord对象在Window管理服务WindowManagerService中都对应有一个AppWindowToken对象。

        此外,在输入法管理服务InputMethodManagerService中,每一个输入法窗口都对应有一个Binder对象,这个Binder对象在Window管理服务WindowManagerService又对应有一个WindowToken对象。

        与输入法窗口类似,在壁纸管理服务WallpaperManagerService中,每一个壁纸窗口都对应有一个Binder对象,这个Binder对象在Window管理服务WindowManagerService也对应有一个WindowToken对象。

        在Window管理服务WindowManagerService中,无论是AppWindowToken对象,还是WindowToken对象,它们都是用来描述一组有着相同令牌的窗口的,每一个窗口都是通过一个WindowState对象来描述的。例如,一个Activity组件窗口可能有一个启动窗口(Starting Window),还有若干个子窗口,那么这些窗口就会组成一组,并且都是以Activity组件在Window管理服务WindowManagerService中所对应的AppWindowToken对象为令牌的。从抽象的角度来看,就是在Window管理服务WindowManagerService中,每一个令牌(AppWindowToken或者WindowToken)都是用来描述一组窗口(WindowState)的,并且每一个窗口的子窗口也是与它同属于一个组,即都有着相同的令牌。

        上述的窗口组织方式如图1所示:


图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,如下所示:

  1. public class WindowManagerService extends IWindowManager.Stub    
  2.         implements Watchdog.Monitor {    
  3.     ......    
  4.     
  5.     /**  
  6.      * Mapping from a token IBinder to a WindowToken object.  
  7.      */    
  8.     final HashMap<IBinder, WindowToken> mTokenMap =    
  9.             new HashMap<IBinder, WindowToken>();    
  10.     
  11.     /**  
  12.      * The same tokens as mTokenMap, stored in a list for efficient iteration  
  13.      * over them.  
  14.      */    
  15.     final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();    
  16.     ......    
  17.     
  18.     /**  
  19.      * Z-ordered (bottom-most first) list of all application tokens, for  
  20.      * controlling the ordering of windows in different applications.  This  
  21.      * contains WindowToken objects.  
  22.      */    
  23.     final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();    
  24.     ......    
  25.     
  26.     public void addAppToken(int addPos, IApplicationToken token,    
  27.             int groupId, int requestedOrientation, boolean fullscreen) {    
  28.         ......    
  29.     
  30.         synchronized(mWindowMap) {    
  31.             AppWindowToken wtoken = findAppWindowToken(token.asBinder());    
  32.             if (wtoken != null) {    
  33.                 ......    
  34.                 return;    
  35.             }    
  36.             wtoken = new AppWindowToken(token);    
  37.             ......    
  38.             mAppTokens.add(addPos, wtoken);    
  39.             ......    
  40.             mTokenMap.put(token.asBinder(), wtoken);    
  41.             mTokenList.add(wtoken);    
  42.     
  43.             ......   
  44.         }    
  45.     }    
  46.     
  47.     ......    
  48. }    
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { ...... /** * Mapping from a token IBinder to a WindowToken object. */ final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<IBinder, WindowToken>(); /** * The same tokens as mTokenMap, stored in a list for efficient iteration * over them. */ final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>(); ...... /** * Z-ordered (bottom-most first) list of all application tokens, for * controlling the ordering of windows in different applications. This * contains WindowToken objects. */ final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>(); ...... public void addAppToken(int addPos, IApplicationToken token, int groupId, int requestedOrientation, boolean fullscreen) { ...... synchronized(mWindowMap) { AppWindowToken wtoken = findAppWindowToken(token.asBinder()); if (wtoken != null) { ...... return; } wtoken = new AppWindowToken(token); ...... mAppTokens.add(addPos, wtoken); ...... mTokenMap.put(token.asBinder(), wtoken); mTokenList.add(wtoken); ...... } } ...... }        这个函数定义在文件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来实现的,如下所示:

  1. public class WindowManagerService extends IWindowManager.Stub    
  2.         implements Watchdog.Monitor {    
  3.     ......    
  4.     
  5.     private void removeAppTokensLocked(List<IBinder> tokens) {  
  6.         // XXX This should be done more efficiently!  
  7.         // (take advantage of the fact that both lists should be  
  8.         // ordered in the same way.)  
  9.         int N = tokens.size();  
  10.         for (int i=0; i<N; i++) {  
  11.             IBinder token = tokens.get(i);  
  12.             final AppWindowToken wtoken = findAppWindowToken(token);  
  13.             if (!mAppTokens.remove(wtoken)) {  
  14.                 ......  
  15.                 i--;  
  16.                 N--;  
  17.             }  
  18.         }  
  19.     }  
  20.    
  21.     ......    
  22. }    
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { ...... private void removeAppTokensLocked(List<IBinder> tokens) { // XXX This should be done more efficiently! // (take advantage of the fact that both lists should be // ordered in the same way.) int N = tokens.size(); for (int i=0; i<N; i++) { IBinder token = tokens.get(i); final AppWindowToken wtoken = findAppWindowToken(token); if (!mAppTokens.remove(wtoken)) { ...... i--; N--; } } } ...... }         这个函数定义在文件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来实现的,如下所示:

  1. public class WindowManagerService extends IWindowManager.Stub    
  2.         implements Watchdog.Monitor {    
  3.     ......    
  4.     
  5.     public void moveAppToken(int index, IBinder token) {  
  6.         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,  
  7.                 "moveAppToken()")) {  
  8.             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");  
  9.         }  
  10.   
  11.         synchronized(mWindowMap) {  
  12.             ......  
  13.             final AppWindowToken wtoken = findAppWindowToken(token);  
  14.             if (wtoken == null || !mAppTokens.remove(wtoken)) {  
  15.                 ......  
  16.                 return;  
  17.             }  
  18.             mAppTokens.add(index, wtoken);  
  19.             ......  
  20.   
  21.             final long origId = Binder.clearCallingIdentity();  
  22.             ......  
  23.             if (tmpRemoveAppWindowsLocked(wtoken)) {  
  24.                 ......  
  25.                 reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);  
  26.                 ......  
  27.                 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);  
  28.                 mLayoutNeeded = true;  
  29.                 performLayoutAndPlaceSurfacesLocked();  
  30.             }  
  31.             Binder.restoreCallingIdentity(origId);  
  32.         }  
  33.     }  
  34.    
  35.     ......    
  36. }    
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { ...... public void moveAppToken(int index, IBinder token) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "moveAppToken()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } synchronized(mWindowMap) { ...... final AppWindowToken wtoken = findAppWindowToken(token); if (wtoken == null || !mAppTokens.remove(wtoken)) { ...... return; } mAppTokens.add(index, wtoken); ...... final long origId = Binder.clearCallingIdentity(); ...... if (tmpRemoveAppWindowsLocked(wtoken)) { ...... reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken); ...... updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES); mLayoutNeeded = true; performLayoutAndPlaceSurfacesLocked(); } Binder.restoreCallingIdentity(origId); } } ...... }         这个函数定义在文件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来获得的,它的实现如下所示:

  1. public class WindowManagerService extends IWindowManager.Stub    
  2.         implements Watchdog.Monitor {    
  3.     ......    
  4.   
  5.     /** 
  6.      * Z-ordered (bottom-most first) list of all Window objects. 
  7.      */  
  8.     final ArrayList<WindowState> mWindows = new ArrayList<WindowState>();  
  9.     ......  
  10.     
  11.     private int findWindowOffsetLocked(int tokenPos) {  
  12.         final int NW = mWindows.size();  
  13.   
  14.         if (tokenPos >= mAppTokens.size()) {  
  15.             int i = NW;  
  16.             while (i > 0) {  
  17.                 i--;  
  18.                 WindowState win = mWindows.get(i);  
  19.                 if (win.getAppToken() != null) {  
  20.                     return i+1;  
  21.                 }  
  22.             }  
  23.         }  
  24.   
  25.         while (tokenPos > 0) {  
  26.             // Find the first app token below the new position that has  
  27.             // a window displayed.  
  28.             final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);  
  29.             ......  
  30.             if (wtoken.sendingToBottom) {  
  31.                 ......  
  32.                 tokenPos--;  
  33.                 continue;  
  34.             }  
  35.             int i = wtoken.windows.size();  
  36.             while (i > 0) {  
  37.                 i--;  
  38.                 WindowState win = wtoken.windows.get(i);  
  39.                 int j = win.mChildWindows.size();  
  40.                 while (j > 0) {  
  41.                     j--;  
  42.                     WindowState cwin = win.mChildWindows.get(j);  
  43.                     if (cwin.mSubLayer >= 0) {  
  44.                         for (int pos=NW-1; pos>=0; pos--) {  
  45.                             if (mWindows.get(pos) == cwin) {  
  46.                                 ......  
  47.                                 return pos+1;  
  48.                             }  
  49.                         }  
  50.                     }  
  51.                 }  
  52.                 for (int pos=NW-1; pos>=0; pos--) {  
  53.                     if (mWindows.get(pos) == win) {  
  54.                         ......  
  55.                         return pos+1;  
  56.                     }  
  57.                 }  
  58.             }  
  59.             tokenPos--;  
  60.         }  
  61.   
  62.         return 0;  
  63.     }  
  64.    
  65.     ......    
  66. }    
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { ...... /** * Z-ordered (bottom-most first) list of all Window objects. */ final ArrayList<WindowState> mWindows = new ArrayList<WindowState>(); ...... private int findWindowOffsetLocked(int tokenPos) { final int NW = mWindows.size(); if (tokenPos >= mAppTokens.size()) { int i = NW; while (i > 0) { i--; WindowState win = mWindows.get(i); if (win.getAppToken() != null) { return i+1; } } } while (tokenPos > 0) { // Find the first app token below the new position that has // a window displayed. final AppWindowToken wtoken = mAppTokens.get(tokenPos-1); ...... if (wtoken.sendingToBottom) { ...... tokenPos--; continue; } int i = wtoken.windows.size(); while (i > 0) { i--; WindowState win = wtoken.windows.get(i); int j = win.mChildWindows.size(); while (j > 0) { j--; WindowState cwin = win.mChildWindows.get(j); if (cwin.mSubLayer >= 0) { for (int pos=NW-1; pos>=0; pos--) { if (mWindows.get(pos) == cwin) { ...... return pos+1; } } } } for (int pos=NW-1; pos>=0; pos--) { if (mWindows.get(pos) == win) { ...... return pos+1; } } } tokenPos--; } return 0; } ...... }         这个函数定义在文件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来实现的,如下所示:

  1. public class WindowManagerService extends IWindowManager.Stub    
  2.         implements Watchdog.Monitor {    
  3.     ......    
  4.     
  5.     public void moveAppTokensToTop(List<IBinder> tokens) {  
  6.         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,  
  7.                 "moveAppTokensToTop()")) {  
  8.             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");  
  9.         }  
  10.   
  11.         final long origId = Binder.clearCallingIdentity();  
  12.         synchronized(mWindowMap) {  
  13.             removeAppTokensLocked(tokens);  
  14.             final int N = tokens.size();  
  15.             for (int i=0; i<N; i++) {  
  16.                 AppWindowToken wt = findAppWindowToken(tokens.get(i));  
  17.                 if (wt != null) {  
  18.                     mAppTokens.add(wt);  
  19.                     if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {  
  20.                         mToTopApps.remove(wt);  
  21.                         mToBottomApps.remove(wt);  
  22.                         mToTopApps.add(wt);  
  23.                         wt.sendingToBottom = false;  
  24.                         wt.sendingToTop = true;  
  25.                     }  
  26.                 }  
  27.             }  
  28.   
  29.             if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) {  
  30.                 moveAppWindowsLocked(tokens, mAppTokens.size());  
  31.             }  
  32.         }  
  33.         Binder.restoreCallingIdentity(origId);  
  34.     }  
  35.    
  36.     ......    
  37. }    
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { ...... public void moveAppTokensToTop(List<IBinder> tokens) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "moveAppTokensToTop()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } final long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { removeAppTokensLocked(tokens); final int N = tokens.size(); for (int i=0; i<N; i++) { AppWindowToken wt = findAppWindowToken(tokens.get(i)); if (wt != null) { mAppTokens.add(wt); if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { mToTopApps.remove(wt); mToBottomApps.remove(wt); mToTopApps.add(wt); wt.sendingToBottom = false; wt.sendingToTop = true; } } } if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) { moveAppWindowsLocked(tokens, mAppTokens.size()); } } Binder.restoreCallingIdentity(origId); } ...... }         这个函数定义在文件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来实现的,如下所示:

  1. public class WindowManagerService extends IWindowManager.Stub    
  2.         implements Watchdog.Monitor {    
  3.     ......    
  4.     
  5.     public void moveAppTokensToBottom(List<IBinder> tokens) {  
  6.         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,  
  7.                 "moveAppTokensToBottom()")) {  
  8.             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");  
  9.         }  
  10.   
  11.         final long origId = Binder.clearCallingIdentity();  
  12.         synchronized(mWindowMap) {  
  13.             removeAppTokensLocked(tokens);  
  14.             final int N = tokens.size();  
  15.             int pos = 0;  
  16.             for (int i=0; i<N; i++) {  
  17.                 AppWindowToken wt = findAppWindowToken(tokens.get(i));  
  18.                 if (wt != null) {  
  19.                     mAppTokens.add(pos, wt);  
  20.                     if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {  
  21.                         mToTopApps.remove(wt);  
  22.                         mToBottomApps.remove(wt);  
  23.                         mToBottomApps.add(i, wt);  
  24.                         wt.sendingToTop = false;  
  25.                         wt.sendingToBottom = true;  
  26.                     }  
  27.                     pos++;  
  28.                 }  
  29.             }  
  30.   
  31.             if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) {  
  32.                 moveAppWindowsLocked(tokens, 0);  
  33.             }  
  34.         }  
  35.         Binder.restoreCallingIdentity(origId);  
  36.     }  
  37.    
  38.     ......    
  39. }    
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { ...... public void moveAppTokensToBottom(List<IBinder> tokens) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "moveAppTokensToBottom()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } final long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { removeAppTokensLocked(tokens); final int N = tokens.size(); int pos = 0; for (int i=0; i<N; i++) { AppWindowToken wt = findAppWindowToken(tokens.get(i)); if (wt != null) { mAppTokens.add(pos, wt); if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { mToTopApps.remove(wt); mToBottomApps.remove(wt); mToBottomApps.add(i, wt); wt.sendingToTop = false; wt.sendingToBottom = true; } pos++; } } if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) { moveAppWindowsLocked(tokens, 0); } } Binder.restoreCallingIdentity(origId); } ...... }         这个函数定义在文件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对象的,如下所示:

  1. public class WindowManagerService extends IWindowManager.Stub    
  2.         implements Watchdog.Monitor {    
  3.     ......    
  4.     
  5.     public void addWindowToken(IBinder token, int type) {  
  6.         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,  
  7.                 "addWindowToken()")) {  
  8.             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");  
  9.         }  
  10.   
  11.         synchronized(mWindowMap) {  
  12.             WindowToken wtoken = mTokenMap.get(token);  
  13.             if (wtoken != null) {  
  14.                 Slog.w(TAG, "Attempted to add existing input method token: " + token);  
  15.                 return;  
  16.             }  
  17.             wtoken = new WindowToken(token, type, true);  
  18.             mTokenMap.put(token, wtoken);  
  19.             mTokenList.add(wtoken);  
  20.             if (type == TYPE_WALLPAPER) {  
  21.                 mWallpaperTokens.add(wtoken);  
  22.             }  
  23.         }  
  24.     }  
  25.    
  26.     ......    
  27. }  
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { ...... public void addWindowToken(IBinder token, int type) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "addWindowToken()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } synchronized(mWindowMap) { WindowToken wtoken = mTokenMap.get(token); if (wtoken != null) { Slog.w(TAG, "Attempted to add existing input method token: " + token); return; } wtoken = new WindowToken(token, type, true); mTokenMap.put(token, wtoken); mTokenList.add(wtoken); if (type == TYPE_WALLPAPER) { mWallpaperTokens.add(wtoken); } } } ...... }        这个函数定义在文件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相关的逻辑,如下所示:

  1. public class WindowManagerService extends IWindowManager.Stub    
  2.         implements Watchdog.Monitor {    
  3.     ......    
  4.     
  5.     public int addWindow(Session session, IWindow client,  
  6.             WindowManager.LayoutParams attrs, int viewVisibility,  
  7.             Rect outContentInsets, InputChannel outInputChannel) {  
  8.         ......  
  9.   
  10.         synchronized(mWindowMap) {  
  11.             ......  
  12.   
  13.             boolean addToken = false;  
  14.             WindowToken token = mTokenMap.get(attrs.token);  
  15.             if (token == null) {  
  16.                 if (attrs.type >= FIRST_APPLICATION_WINDOW  
  17.                         && attrs.type <= LAST_APPLICATION_WINDOW) {  
  18.                     ......  
  19.                     return WindowManagerImpl.ADD_BAD_APP_TOKEN;  
  20.                 }  
  21.                 if (attrs.type == TYPE_INPUT_METHOD) {  
  22.                     ......  
  23.                     return WindowManagerImpl.ADD_BAD_APP_TOKEN;  
  24.                 }  
  25.                 if (attrs.type == TYPE_WALLPAPER) {  
  26.                     ......  
  27.                     return WindowManagerImpl.ADD_BAD_APP_TOKEN;  
  28.                 }  
  29.                 token = new WindowToken(attrs.token, -1false);  
  30.                 addToken = true;  
  31.             }  
  32.   
  33.             ......  
  34.   
  35.             if (addToken) {  
  36.                 mTokenMap.put(attrs.token, token);  
  37.                 mTokenList.add(token);  
  38.             }  
  39.    
  40.             ......  
  41.         }  
  42.   
  43.         ......  
  44.     }  
  45.            
  46.     ......    
  47. }  
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { ...... public int addWindow(Session session, IWindow client, WindowManager.LayoutParams attrs, int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) { ...... synchronized(mWindowMap) { ...... boolean addToken = false; WindowToken token = mTokenMap.get(attrs.token); if (token == null) { if (attrs.type >= FIRST_APPLICATION_WINDOW && attrs.type <= LAST_APPLICATION_WINDOW) { ...... return WindowManagerImpl.ADD_BAD_APP_TOKEN; } if (attrs.type == TYPE_INPUT_METHOD) { ...... return WindowManagerImpl.ADD_BAD_APP_TOKEN; } if (attrs.type == TYPE_WALLPAPER) { ...... return WindowManagerImpl.ADD_BAD_APP_TOKEN; } token = new WindowToken(attrs.token, -1, false); addToken = true; } ...... if (addToken) { mTokenMap.put(attrs.token, token); mTokenList.add(token); } ...... } ...... } ...... }        这个函数定义在文件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来实现的,如下所示:

  1. public class WindowManagerService extends IWindowManager.Stub    
  2.         implements Watchdog.Monitor {    
  3.     ......    
  4.     
  5.     public void removeWindowToken(IBinder token) {  
  6.         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,  
  7.                 "removeWindowToken()")) {  
  8.             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");  
  9.         }  
  10.   
  11.         final long origId = Binder.clearCallingIdentity();  
  12.         synchronized(mWindowMap) {  
  13.             WindowToken wtoken = mTokenMap.remove(token);  
  14.             mTokenList.remove(wtoken);  
  15.             if (wtoken != null) {  
  16.                 boolean delayed = false;  
  17.                 if (!wtoken.hidden) {  
  18.                     wtoken.hidden = true;  
  19.   
  20.                     final int N = wtoken.windows.size();  
  21.                     boolean changed = false;  
  22.   
  23.                     for (int i=0; i<N; i++) {  
  24.                         WindowState win = wtoken.windows.get(i);  
  25.   
  26.                         if (win.isAnimating()) {  
  27.                             delayed = true;  
  28.                         }  
  29.   
  30.                         if (win.isVisibleNow()) {  
  31.                             applyAnimationLocked(win,  
  32.                                     WindowManagerPolicy.TRANSIT_EXIT, false);  
  33.                             changed = true;  
  34.                         }  
  35.                     }  
  36.   
  37.                     if (changed) {  
  38.                         mLayoutNeeded = true;  
  39.                         performLayoutAndPlaceSurfacesLocked();  
  40.                         updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);  
  41.                     }  
  42.   
  43.                     if (delayed) {  
  44.                         mExitingTokens.add(wtoken);  
  45.                     } else if (wtoken.windowType == TYPE_WALLPAPER) {  
  46.                         mWallpaperTokens.remove(wtoken);  
  47.                     }  
  48.                 }  
  49.   
  50.                 ......  
  51.             } else {  
  52.                 Slog.w(TAG, "Attempted to remove non-existing token: " + token);  
  53.             }  
  54.         }  
  55.         Binder.restoreCallingIdentity(origId);  
  56.     }  
  57.            
  58.     ......    
  59. }  
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { ...... public void removeWindowToken(IBinder token) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "removeWindowToken()")) { throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); } final long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { WindowToken wtoken = mTokenMap.remove(token); mTokenList.remove(wtoken); if (wtoken != null) { boolean delayed = false; if (!wtoken.hidden) { wtoken.hidden = true; final int N = wtoken.windows.size(); boolean changed = false; for (int i=0; i<N; i++) { WindowState win = wtoken.windows.get(i); if (win.isAnimating()) { delayed = true; } if (win.isVisibleNow()) { applyAnimationLocked(win, WindowManagerPolicy.TRANSIT_EXIT, false); changed = true; } } if (changed) { mLayoutNeeded = true; performLayoutAndPlaceSurfacesLocked(); updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL); } if (delayed) { mExitingTokens.add(wtoken); } else if (wtoken.windowType == TYPE_WALLPAPER) { mWallpaperTokens.remove(wtoken); } } ...... } else { Slog.w(TAG, "Attempted to remove non-existing token: " + token); } } Binder.restoreCallingIdentity(origId); } ...... }        这个函数定义在文件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来实现的,如下所示:

  1. public class WindowManagerService extends IWindowManager.Stub    
  2.         implements Watchdog.Monitor {    
  3.     ......    
  4.   
  5.     /** 
  6.      * Mapping from an IWindow IBinder to the server's Window object. 
  7.      * This is also used as the lock for all of our state. 
  8.      */  
  9.     final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>();  
  10.     ......  
  11.   
  12.     /** 
  13.      * Z-ordered (bottom-most first) list of all Window objects. 
  14.      */  
  15.     final ArrayList<WindowState> mWindows = new ArrayList<WindowState>();  
  16.     ......  
  17.     
  18.     public int addWindow(Session session, IWindow client,    
  19.             WindowManager.LayoutParams attrs, int viewVisibility,    
  20.             Rect outContentInsets, InputChannel outInputChannel) {    
  21.         ......    
  22.     
  23.         WindowState win = null;    
  24.     
  25.         synchronized(mWindowMap) {    
  26.             ......    
  27.   
  28.             win = new WindowState(session, client, token,    
  29.                     attachedWindow, attrs, viewVisibility);    
  30.             ......    
  31.     
  32.             mWindowMap.put(client.asBinder(), win);    
  33.             ......  
  34.   
  35.             if (attrs.type == TYPE_INPUT_METHOD) {  
  36.                 mInputMethodWindow = win;  
  37.                 addInputMethodWindowToListLocked(win);  
  38.                 ......  
  39.             } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {  
  40.                 mInputMethodDialogs.add(win);  
  41.                 addWindowToListInOrderLocked(win, true);  
  42.                 adjustInputMethodDialogsLocked();  
  43.                 ......  
  44.             } else {  
  45.                 addWindowToListInOrderLocked(win, true);  
  46.                 if (attrs.type == TYPE_WALLPAPER) {  
  47.                     .......  
  48.                     adjustWallpaperWindowsLocked();  
  49.                 } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {  
  50.                     adjustWallpaperWindowsLocked();  
  51.                 }  
  52.             }  
  53.   
  54.             ......  
  55.         }  
  56.   
  57.         ......  
  58.     }  
  59.   
  60.     ......  
  61. }  
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor { ...... /** * Mapping from an IWindow IBinder to the server's Window object. * This is also used as the lock for all of our state. */ final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>(); ...... /** * Z-ordered (bottom-most first) list of all Window objects. */ final ArrayList<WindowState> mWindows = new ArrayList<WindowState>(); ...... public int addWindow(Session session, IWindow client, WindowManager.LayoutParams attrs, int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) { ...... WindowState win = null; synchronized(mWindowMap) { ...... win = new WindowState(session, client, token, attachedWindow, attrs, viewVisibility); ...... mWindowMap.put(client.asBinder(), win); ...... if (attrs.type == TYPE_INPUT_METHOD) { mInputMethodWindow = win; addInputMethodWindowToListLocked(win); ...... } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) { mInputMethodDialogs.add(win); addWindowToListInOrderLocked(win, true); adjustInputMethodDialogsLocked(); ...... } else { addWindowToListInOrderLocked(win, true); if (attrs.type == TYPE_WALLPAPER) { ....... adjustWallpaperWindowsLocked(); } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) { adjustWallpaperWindowsLocked(); } } ...... } ...... } ...... }        这个函数定义在文件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来调整系统中的壁纸窗口在窗口堆栈中的位置,使得它位于刚才所添加的窗口的下面。

                    

未完待续。。。

分享到:
发表评论(0)
姓名 *
评论内容 *
验证码 *图片看不清?点击重新得到验证码