1  背景

之因此写这一篇博客的缘由是由于以前有写过一篇《Android应用setContentView与LayoutInflater加载解析机制源码分析》, 而后有人在文章下面评论和微博私信中问我关于Android应用Activity、Dialog、PopWindow加载显示机制是咋回事,因此我就写一 篇文章来分析分析吧(本文以Android5.1.1 (API 22)源码为基础分析),以便你们在应用层开发时再也不迷糊。android

PS一句:不只有人微博私信我这个问题,还有人问博客插图这些是用啥画的,这里告诉你们。就是我,快来猛戳我windows

还记得以前《Android应用setContentView与LayoutInflater加载解析机制源码分析》这篇文章的最后分析结果吗?就是以下这幅图:安全

在那篇文章里咱们当时重点是Activity的View加载解析xml机制分析,当时说到了Window的东西,但只是皮毛的分析了Activity相关的一些逻辑。(PS:看到这不清楚上面啥意思的建议先移步到《Android应用setContentView与LayoutInflater加载解析机制源码分析》,完事再回头继续看这篇文章。)当时给你们承诺过咱们要从应用控件一点一点往下慢慢深刻分析,因此如今开始深刻,可是本篇的深刻也只是仅限Window相关的东东,以后文章还会继续慢慢深刻。app

2  浅析Window与WindowManager相关关系及源码

经过上面那幅图能够很直观的看见,Android屏幕显示的就是Window和各类View,Activity在其中的做用主要是管理生命周期、建 立窗口等。也就是说Window相关的东西对于Android屏幕来讲是相当重要的(虽然前面分析Activity的setContentView等原理 时说过一点Window,但那只是皮毛。),因此有必要在分析Android应用Activity、Dialog、PopWindow加载显示机制前再看 看Window相关的一些东西。ide

2-1  Window与WindowManager基础关系

在分析Window与WindowManager以前咱们先看一张图:函数

接下来看一点代码,以下:源码分析

1
2
3
4
5
6
7
8
9
/** Interface to let you add and remove child views to an Activity. To get an instance
   * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
   */
public interface ViewManager
{
     public void addView(View view, ViewGroup.LayoutParams params);
     public void updateViewLayout(View view, ViewGroup.LayoutParams params);
     public void removeView(View view);
}

能够看见,ViewManager接口定义了一组规则,也就是add、update、remove的操做View接口。也就是说ViewManager是用来添加和移除activity中View的接口。继续往下看:布局

1
2
3
4
5
6
7
8
9
10
public interface WindowManager extends ViewManager {
     ......
     public Display getDefaultDisplay();
     public void removeViewImmediate(View view);
     ......
     public static class LayoutParams extends ViewGroup.LayoutParams
             implements Parcelable {
         ......
     }
}

看见没有,WindowManager继承自ViewManager,而后本身仍是一个接口,同时又定义了一个静态内部类LayoutParams(这个 类比较重要,后面会分析。提早透漏下,若是你在APP作过相似360助手屏幕的那个悬浮窗或者作过那种相似IOS的小白圆点,点击展开菜单功能,你或多或 少就能猜到这个类的重要性。)。WindowManager用来在应用与Window之间的接口、窗口顺序、消息等的管理。继续看下 ViewManager的另外一个实现子类ViewGroup,以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
     //protected ViewParent mParent;
     //这个成员是View定义的,ViewGroup继承自View,因此也能够拥有。
     //这个变量就是前面咱们一系列文章分析View向上传递的父节点,相似于一个链表Node的next同样
     //最终指向了ViewRoot
     ......
     public void addView(View child, LayoutParams params) {
         addView(child, -1, params);
     }
 
     ......
 
     public void addView(View child, int index, LayoutParams params) {
         ......
         // addViewInner() will call child.requestLayout() when setting the new LayoutParams
         // therefore, we call requestLayout() on ourselves before, so that the child's request
         // will be blocked at our level
         requestLayout();
         invalidate( true );
         addViewInner(child, index, params,  false );
     }
     ......
}

这下理解上面那幅图了吧,因此说View经过ViewGroup的addView方法添加到ViewGroup中,而ViewGroup层层嵌套到最顶级都会显示在在一个窗口Window中(正如上面背景介绍中《Android应用setContentView与LayoutInflater加载解析机制源码分析》的示意图同样),其中每一个View都有一个ViewParent类型的父节点mParent,最顶上的节点也是一个viewGroup,也即前面文章分析的Window的内部类DecorView(从《Android应用setContentView与LayoutInflater加载解析机制源码分析》的总结部分或者《Android应用层View绘制流程与源码分析》的5-1小节均可以验证这个结论)对象。同时经过上面背景中那幅图能够看出来,对于一个Activity只有一个DecorView(ViewRoot),也只有一个Window。

2-2  Activity窗口添加流程拓展

前面文章说过,ActivityThread类的performLaunchActivity方法中调运了activity.attach(…)方法进行初始化。以下是Activity的attach方法源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
     final void attach(Context context, ActivityThread aThread,
             Instrumentation instr, IBinder token, int ident,
             Application application, Intent intent, ActivityInfo info,
             CharSequence title, Activity parent, String id,
             NonConfigurationInstances lastNonConfigurationInstances,
             Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
         ......
         //建立Window类型的mWindow对象,实际为PhoneWindow类实现了抽象Window类
         mWindow = PolicyManager.makeNewWindow( this );
         ......
         //经过抽象Window类的setWindowManager方法给Window类的成员变量WindowManager赋值实例化
         mWindow.setWindowManager(
                 (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                 mToken, mComponent.flattenToString(),
                 (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
         ......
         //把抽象Window类相关的WindowManager对象拿出来关联到Activity的WindowManager类型成员变量mWindowManager
         mWindowManager = mWindow.getWindowManager();
         ......
     }

看见没有,Activity类中的attach方法又建立了Window类型的新成员变量mWindow(PhoneWindow实现类)与 Activity相关联,接着在Activity类的attach方法最后又经过mWindow.setWindowManager(…)方法建立了与 Window相关联的WindowManager对象,最后又经过mWindow.getWindowManager()将Window的 WindowManager成员变量赋值给Activity的WindowManager成员变量mWindowManager。

接下来咱们看下上面代码中的mWindow.setWindowManager(…)方法源码(PhoneWindow没有重写抽象Window的setWindowManager方法,因此直接看Window类的该方法源码),以下:

1
2
3
4
5
6
7
8
9
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
         boolean hardwareAccelerated) {
     ......
     if  (wm ==  null ) {
         wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
     }
     //实例化Window类的WindowManager类型成员mWindowManager
     mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager( this );
}

能够看见,Window的setWindowManager方法中经过WindowManagerImpl实例的createLocalWindowManager方法获取了WindowManager实例,以下:

1
2
3
4
5
6
7
8
9
10
11
12
public final class WindowManagerImpl implements WindowManager {
     ......
     private WindowManagerImpl(Display display, Window parentWindow) {
         mDisplay = display;
         mParentWindow = parentWindow;
     }
     ......
     public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
         return  new  WindowManagerImpl(mDisplay, parentWindow);
     }
     ......
}

看见没有?这样就把Activity的Window与WindowManager关联起来了。Activity类的Window类型成员变量mWindow及WindowManager类型成员变量mWindowManager就是这么来的。

回过头继续看上面刚刚贴的Activity的attach方法代码,看见mWindow.setWindowManager方法传递的第一个参数 没?有人会想(WindowManager)context.getSystemService(Context.WINDOW_SERVICE)这行代 码是什么意思,如今告诉你。

《Android应用Context详解及源码解析》一 文中第三部分曾经说过ActivityThread中建立了Acitivty(执行attach等方法)等东东,在建立这个Activity以前获得了 Context的实例。记不记得当时说Context的实现类就是ContextImpl吗?下面咱们看下ContextImpl类的静态方法块,以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class ContextImpl extends Context {
     ......
     //静态代码块,类加载时执行一次
     static {
         ......
         //这里有一堆相似的XXX_SERVICE的注册
         ......
         registerService(WINDOW_SERVICE,  new  ServiceFetcher() {
                 Display mDefaultDisplay;
                 public Object getService(ContextImpl ctx) {
                     //搞一个Display实例
                     Display display = ctx.mDisplay;
                     if  (display ==  null ) {
                         if  (mDefaultDisplay ==  null ) {
                             DisplayManager dm = (DisplayManager)ctx.getOuterContext().
                                     getSystemService(Context.DISPLAY_SERVICE);
                             mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
                         }
                         display = mDefaultDisplay;
                     }
                     //返回一个WindowManagerImpl实例
                     return  new  WindowManagerImpl(display);
                 }});
         ......
     }
     //这就是你在外面调运Context的getSystemService获取到的WindowManagerImpl实例
     @Override
     public Object getSystemService(String name) {
         ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
         return  fetcher ==  null  null  : fetcher.getService( this );
     }
     //上面static代码块建立WindowManagerImpl实例用到的方法
     private static void registerService(String serviceName, ServiceFetcher fetcher) {
         if  (!(fetcher  instanceof  StaticServiceFetcher)) {
             fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
         }
         SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
     }
}

看见没有,咱们都知道Java的静态代码块是类加载是执行一次的,也就至关于一个全局的,这样就至关于每一个Application只有一个WindowManagerImpl(display)实例。

还记不记得《Android应用setContentView与LayoutInflater加载解析机制源码分析》一文2-6小节中说的,setContentView的实质显示是触发了Activity的resume状态,也就是触发了makeVisible方法,那咱们再来看下这个方法,以下:

1
2
3
4
5
6
7
8
9
10
11
void makeVisible() {
     if  (!mWindowAdded) {
         //也就是获取Activity的mWindowManager
         //这个mWindowManager是在Activity的attach中经过mWindow.getWindowManager()得到
         ViewManager wm = getWindowManager();
         //调运的实质就是ViewManager接口的addView方法,传入的是mDecorView
         wm.addView(mDecor, getWindow().getAttributes());
         mWindowAdded =  true ;
     }
     mDecor.setVisibility(View.VISIBLE);
}

特别注意,看见makeVisible方法的wm变量没,这个变量就是Window类中经过调运WindowManagerImpl的 createLocalWindowManager建立的实例,也就是说每个Activity都会新建立这么一个WindowManager实例来显示 Activity的界面的,有点和上面分析的ContextImpl中static块建立的WindowManager不太同样的地方就在于 Context的WindowManager对每一个APP来讲是一个全局单例的,而Activity的WindowManager是每一个Activity 都会新建立一个的(其实你从上面分析的两个实例化WindowManagerImpl的构造函数参数传递就能够看出来,Activity中Window的 WindowManager成员在构造实例化时传入给WindowManagerImpl中mParentWindow成员的是当前Window对象,而 ContextImpl的static块中单例实例化WindowManagerImpl时传入给WindowManagerImpl中 mParentWindow成员的是null值)。

继续看makeVisible中调运的WindowManagerImpl的addView方法以下:

1
2
3
4
5
6
7
8
9
10
11
12
public final class WindowManagerImpl implements WindowManager {
     //继承自Object的单例类
     private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
     ......
     public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
         applyDefaultToken(params);
         //mParentWindow是上面分析的在Activity中获取WindowManagerImpl实例化时传入的当前Window
         //view是Activity中最顶层的mDecor
         mGlobal.addView(view, params, mDisplay, mParentWindow);
     }
     ......
}

这里当前传入的view是mDecor,LayoutParams呢?能够看见是getWindow().getAttributes(),那咱们进去看看Window类的这个属性,以下:

1
2
// The current window attributes.
     private final WindowManager.LayoutParams mWindowAttributes =  new  WindowManager.LayoutParams();

原来是WindowManager的静态内部类LayoutParams的默认构造函数:

1
2
3
4
5
public LayoutParams() {
     super (LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
     type = TYPE_APPLICATION;
     format = PixelFormat.OPAQUE;
}

看见没有,Activity窗体的WindowManager.LayoutParams类型是TYPE_APPLICATION的。

继续回到WindowManagerImpl的addView方法,分析能够看见WindowManagerImpl中有一个单例模式的 WindowManagerGlobal成员mGlobal,addView最终调运了WindowManagerGlobal的addView,源码如 下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public final class WindowManagerGlobal {
     ......
     private final ArrayList<View> mViews =  new  ArrayList<View>();
     private final ArrayList<ViewRootImpl> mRoots =  new  ArrayList<ViewRootImpl>();
     private final ArrayList<WindowManager.LayoutParams> mParams =
             new  ArrayList<WindowManager.LayoutParams>();
     private final ArraySet<View> mDyingViews =  new  ArraySet<View>();
 
     ......
     public void addView(View view, ViewGroup.LayoutParams params,
             Display display, Window parentWindow) {
         ......
         //获取Activity的Window的getWindow().getAttributes()的LayoutParams 
         final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
         //若是是Activity中调运的,parentWindow=Window,若是不是Activity的,譬如是Context的静态代码块的实例化则parentWindow为null
         if  (parentWindow !=  null ) {
             //依据当前Activity的Window调节sub Window的LayoutParams
             parentWindow.adjustLayoutParamsForSubWindow(wparams);
         else  {
             ......
         }
 
         ViewRootImpl root;
         ......
         synchronized (mLock) {
             ......
             //为当前Window建立ViewRoot
             root =  new  ViewRootImpl(view.getContext(), display);
             view.setLayoutParams(wparams);
             //把当前Window相关的东西存入各自的List中,在remove中会删掉
             mViews.add(view);
             mRoots.add(root);
             mParams.add(wparams);
         }
 
         // do this last because it fires off messages to start doing things
         try  {
             //把View和ViewRoot关联起来,很重要!!!
             root.setView(view, wparams, panelParentView);
         catch  (RuntimeException e) {
             ......
         }
     }
     ......
}

能够看见,在addView方法中会利用LayoutParams得到Window的属性,而后为每一个Window建立ViewRootImpl, 最后经过ViewRootImpl的setView方法经过mSession向WindowManagerService发送添加窗口请求把窗口添加到 WindowManager中,而且由WindowManager来管理窗口的view、事件、消息收集处理等(ViewRootImpl的这一添加过程 后面会写文章分析,这里先记住这个概念便可)。

至此咱们对上面背景中那幅图,也就是《Android应用setContentView与LayoutInflater加载解析机制源码分析》这篇文章总结部分的那幅图又进行了更深刻的一点分析,其目的也就是为了下面分析Android应用Dialog、PopWindow、Toast加载显示机制作铺垫准备。

2-3  继续顺藤摸瓜WindowManager.LayoutParams类的源码

上面2-1分析Window与WindowManager基础关系时提到了WindowManager有一个静态内部类LayoutParams, 它继承于ViewGroup.LayoutParams,用于向WindowManager描述Window的管理策略。如今咱们来看下这个类(PS:在 AD上也能够看见,自备梯子点我看AD的),以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
     public static class LayoutParams extends ViewGroup.LayoutParams
             implements Parcelable {
         //窗口的绝对XY位置,须要考虑gravity属性
         public int x;
         public int y;
         //在横纵方向上为相关的View预留多少扩展像素,若是是0则此view不能被拉伸,其余状况下扩展像素被widget均分
         public float horizontalWeight;
         public float verticalWeight;
         //窗口类型
         //有3种主要类型以下:
         //ApplicationWindows取值在FIRST_APPLICATION_WINDOW与LAST_APPLICATION_WINDOW之间,是经常使用的顶层应用程序窗口,须将token设置成Activity的token;
         //SubWindows取值在FIRST_SUB_WINDOW和LAST_SUB_WINDOW之间,与顶层窗口相关联,需将token设置成它所附着宿主窗口的token;
         //SystemWindows取值在FIRST_SYSTEM_WINDOW和LAST_SYSTEM_WINDOW之间,不能用于应用程序,使用时须要有特殊权限,它是特定的系统功能才能使用;
         public int type;
 
         //WindowType:开始应用程序窗口
         public static final int FIRST_APPLICATION_WINDOW = 1;
         //WindowType:全部程序窗口的base窗口,其余应用程序窗口都显示在它上面
         public static final int TYPE_BASE_APPLICATION   = 1;
         //WindowType:普通应用程序窗口,token必须设置为Activity的token来指定窗口属于谁
         public static final int TYPE_APPLICATION        = 2;
         //WindowType:应用程序启动时所显示的窗口,应用本身不要使用这种类型,它被系统用来显示一些信息,直到应用程序能够开启本身的窗口为止
         public static final int TYPE_APPLICATION_STARTING = 3;
         //WindowType:结束应用程序窗口
         public static final int LAST_APPLICATION_WINDOW = 99;
 
         //WindowType:SubWindows子窗口,子窗口的Z序和坐标空间都依赖于他们的宿主窗口
         public static final int FIRST_SUB_WINDOW        = 1000;
         //WindowType: 面板窗口,显示于宿主窗口的上层
         public static final int TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW;
         //WindowType:媒体窗口(例如视频),显示于宿主窗口下层
         public static final int TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1;
         //WindowType:应用程序窗口的子面板,显示于全部面板窗口的上层
         public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2;
         //WindowType:对话框,相似于面板窗口,绘制相似于顶层窗口,而不是宿主的子窗口
         public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3;
         //WindowType:媒体信息,显示在媒体层和程序窗口之间,须要实现半透明效果
         public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW+4;
         //WindowType:子窗口结束
         public static final int LAST_SUB_WINDOW         = 1999;
 
         //WindowType:系统窗口,非应用程序建立
         public static final int FIRST_SYSTEM_WINDOW     = 2000;
         //WindowType:状态栏,只能有一个状态栏,位于屏幕顶端,其余窗口都位于它下方
         public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
         //WindowType:搜索栏,只能有一个搜索栏,位于屏幕上方
         public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;
         //WindowType:电话窗口,它用于电话交互(特别是呼入),置于全部应用程序之上,状态栏之下
         public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;
         //WindowType:系统提示,出如今应用程序窗口之上
         public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;
         //WindowType:锁屏窗口
         public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;
         //WindowType:信息窗口,用于显示Toast
         public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;
         //WindowType:系统顶层窗口,显示在其余一切内容之上,此窗口不能得到输入焦点,不然影响锁屏
         public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;
         //WindowType:电话优先,当锁屏时显示,此窗口不能得到输入焦点,不然影响锁屏
         public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;
         //WindowType:系统对话框
         public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;
         //WindowType:锁屏时显示的对话框
         public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;
         //WindowType:系统内部错误提示,显示于全部内容之上
         public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;
         //WindowType:内部输入法窗口,显示于普通UI之上,应用程序可从新布局以避免被此窗口覆盖
         public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;
         //WindowType:内部输入法对话框,显示于当前输入法窗口之上
         public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
         //WindowType:墙纸窗口
         public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;
         //WindowType:状态栏的滑动面板
         public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;
         //WindowType:安全系统覆盖窗口,这些窗户必须不带输入焦点,不然会干扰键盘
         public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;
         //WindowType:拖放伪窗口,只有一个阻力层(最多),它被放置在全部其余窗口上面
         public static final int TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16;
         //WindowType:状态栏下拉面板
         public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;
         //WindowType:鼠标指针
         public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
         //WindowType:导航栏(有别于状态栏时)
         public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
         //WindowType:音量级别的覆盖对话框,显示当用户更改系统音量大小
         public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;
         //WindowType:起机进度框,在一切之上
         public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;
         //WindowType:假窗,消费导航栏隐藏时触摸事件
         public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22;
         //WindowType:梦想(屏保)窗口,略高于键盘
         public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
         //WindowType:导航栏面板(不一样于状态栏的导航栏)
         public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
         //WindowType:universe背后真正的窗户
         public static final int TYPE_UNIVERSE_BACKGROUND = FIRST_SYSTEM_WINDOW+25;
         //WindowType:显示窗口覆盖,用于模拟辅助显示设备
         public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;
         //WindowType:放大窗口覆盖,用于突出显示的放大部分可访问性放大时启用
         public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
         //WindowType:......