Window、WindowManager 和 WMS
Window 是一个抽象类,具体实现是PhoneWindow
,它对View进行管理。
WindowManager 是一个接口,继承自 ViewManager ,具体实现类是 WindowManagerImpl
, 它是用来管理Window的, 对window的添加、删除都有它处理。
WMS(WindowManagerService) 是功能实现服务包括 Window 的功能实现和输入系统,WindowManager 和 WMS 通过 Binder 来进行跨进程通信。
Window 包含了 View 并对 View 进行管理,Window 用虚线来表示是因为 Window 是一个抽象概念,并不是真实存在,Window 的实体其实也是 View。WindowManager 用来管理 Window,而 WindowManager 所提供的功能最终会由 WMS 来进行处理。
WindowManager 体系
//frameworks/base/core/java/android/view/WindowManager.java
public void addView(View view, ViewGroup.LayoutParams params);//添加View
public void updateViewLayout(View view, ViewGroup.LayoutParams params);//更新View
public void removeView(View view);//删除View
public Display getDefaultDisplay();//得到 WindowManager 所管理的屏幕(Display)
public void removeViewImmediate(View view);//在这个方法返回前要立即执行View.onDetachedFromWindow(),来完成传入的 View 的销毁工作
除了一些常用方法,WM还有包括 Window 的类型和层级相关的常量、内部类以及一些方法。
Activity到绑定Window
WindowManager的结构图
Window 的属性
Type(Window 的类型)、Flag(Window 的标志) 和 SoftInputMode(软键盘相关模式)
Window 类型
Window 的类型有很多种,比如应用程序窗口、系统错误窗口、输入法窗口、PopupWindow、Toast、Dialog 等等。总来来说分为三大类分别是:Application Window(应用程序窗口)、Sub Windwow(子窗口)、System Window(系统窗口),每个大类又包含了很多种类型,它们都定义在 WindowManager 的静态内部类 LayoutParams 中。
// 应用程序窗口1~99
public static final int FIRST_APPLICATION_WINDOW = 1;//1
public static final int TYPE_BASE_APPLICATION = 1;//窗口的基础值,其他的窗口值要大于这个值
public static final int TYPE_APPLICATION = 2;//普通的应用程序窗口类型
public static final int TYPE_APPLICATION_STARTING = 3;//应用程序启动窗口类型,用于系统在应用程序窗口启动前显示的窗口。
public static final int TYPE_DRAWN_APPLICATION = 4;
public static final int LAST_APPLICATION_WINDOW = 99;//2
//子窗口1000~1999,它不能独立的存在,需要附着在其他窗口才可以,如PopupWindow
public static final int FIRST_SUB_WINDOW = 1000;//子窗口类型初始值
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4;
public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
public static final int LAST_SUB_WINDOW = 1999;//子窗口类型结束值
//系统窗口2000~2999 如Toast、输入法窗口、系统音量条窗口、系统错误窗口
public static final int FIRST_SYSTEM_WINDOW = 2000;//系统窗口类型初始值
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;//系统状态栏窗口
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;//搜索条窗口
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;//通话窗口
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;//系统ALERT窗口
public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;//锁屏窗口
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;//TOAST窗口
...
public static final int LAST_SYSTEM_WINDOW = 2999;//系统窗口类型结束值
窗口显示次序
当一个进程向 WMS 申请一个窗口时,WMS 会为窗口确定显示次序。
为了方便窗口显示次序的管理,手机屏幕可以虚拟的用 X、Y、Z 轴来表示,其中 Z 轴垂直于屏幕,从屏幕内指向屏幕外,这样确定窗口显示次序也就是确定窗口在 Z 轴上的次序,这个次序称为 Z-Oder。Type 值是 Z-Oder 排序的依据,我们知道应用程序窗口的 Type 值范围为 1 到 99,子窗口 1000 到 1999 ,系统窗口 2000 到 2999,,一般情况下,Type 值越大则 Z-Oder 排序越靠前,就越靠近用户。
Window 的标志
定义在WindowManager 的内部类 LayoutParams 中
FLAG | 描述 |
---|---|
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | 只要窗口可见,就允许在开启状态的屏幕上锁屏 |
FLAG_NOT_FOCUSABLE | 窗口不能获得输入焦点,设置该标志的同时,FLAG_NOT_TOUCH_MODAL 也会被设置 |
FLAG_NOT_TOUCHABLE | 窗口不接收任何触摸事件 |
FLAG_NOT_TOUCH_MODAL | 在该窗口区域外的触摸事件传递给其他的 Window, 而自己只会处理窗口区域内的触摸事件 |
FLAG_KEEP_SCREEN_ON | 只要窗口可见,屏幕就会一直亮着 |
FLAG_LAYOUT_NO_LIMITS | 允许窗口超过屏幕之外 |
FLAG_FULLSCREEN | 隐藏所有的屏幕装饰窗口,比如在游戏、播放器中的全屏显示 |
FLAG_SHOW_WHEN_LOCKED | 窗口可以在锁屏的窗口之上显示 |
FLAG_IGNORE_CHEEK_PRESSES | 当用户的脸贴近屏幕时(比如打电话),不会去响应此事件 |
FLAG_TURN_SCREEN_ON | 窗口显示时将屏幕点亮 |
设置Flag的相关方法
Window mWindow =getWindow();
//第一种
mWindow.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
//第二种
mWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
//第三种 给 LayoutParams 设置 Flag,然后通过 WindowManager 的 addView 方法进行添加
WindowManager.LayoutParams mWindowLayoutParams = new WindowManager.LayoutParams();
mWindowLayoutParams.flags=WindowManager.LayoutParams.FLAG_FULLSCREEN;
WindowManager mWindowManager =(WindowManager) getSystemService(Context.WINDOW_SERVICE);
TextView mTextView=new TextView(this);
mWindowManager.addView(mTextView,mWindowLayoutParams);
软键盘相关模式
在WindowManager 的静态内部类 LayoutParams 中定义了软键盘相关模式
SOFTINPUTMODE | 描述 |
---|---|
SOFT_INPUT_STATE_UNSPECIFIED | 没有指定状态, 系统会选择一个合适的状态或依赖于主题的设置 |
SOFT_INPUT_STATE_UNCHANGED | 不会改变软键盘状态 |
SOFT_INPUT_STATE_HIDDEN | 当用户进入该窗口时,软键盘默认隐藏 |
SOFT_INPUT_STATE_ALWAYS_HIDDEN | 当窗口获取焦点时,软键盘总是被隐藏 |
SOFT_INPUT_ADJUST_RESIZE | 当软键盘弹出时,窗口会调整大小 |
SOFT_INPUT_ADJUST_PAN | 当软键盘弹出时,窗口不需要调整大小,要确保输入焦点是可见的 |
//android:windowSoftInputMode
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
Window 的添加过程
对于不同类型的窗口添加过程会有所不同,但是对于 WMS 处理部分,添加的过程基本上是一样的。所以先分析 WindowManager 的处理部分,之后再集中分析WMS的处理。
系统窗口的添加过程
以系统窗口 StatusBar 为例
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
ViewRootImpl 身负了很多职责:implementing the needed protocol between View* and the WindowManager
- View 树的根并管理 View 树
- 触发 View 的测量、布局和绘制
- 输入事件的中转站
- 管理 Surface
- 负责与 WMS 进行进程间通信