Android 7.1 GUI系统-窗口管理WMS-窗口属性(二)

来源:互联网 发布:php saas平台架构设计 编辑:程序博客网 时间:2024/06/07 22:05

窗口类型及属性。

1),Android都有那些窗口类型,定义在WindowManager.java的内部类LayoutParams中。

public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable @WindowManager.java{//代表通常的应用程序窗口的开始。public static final int FIRST_APPLICATION_WINDOW = 1;//应用窗口的基础值,其他应用窗口都在这之上。public static final int TYPE_BASE_APPLICATION   = 1;//普通的应用窗口,它属于一个Activity token identifying。public static final int TYPE_APPLICATION        = 2;//启动窗口,它不是被应用程序自身用的,而是被系统使用来显示某些东西,在应用程序能显示它自己的窗口之前。public static final int TYPE_APPLICATION_STARTING = 3;//应用窗口的结束值。 public static final int LAST_APPLICATION_WINDOW = 99;//子窗口的起始值,这类必须设置它依附的窗口,在Z-order上,子窗口的类型紧邻它依附的窗口,子窗口的坐标空间也是相对于它的依附窗口。public static final int FIRST_SUB_WINDOW = 1000;//应用程序的panel窗口,比如hint窗口,pop窗口等,这类窗口在父窗口之上。public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;//显示多媒体的窗口,如Video,这类窗口在父窗口之下。public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;//应用的sub-panel窗口,显示在父窗口和TYPE_APPLICATION_PANEL之上。public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;//类似与TYPE_APPLICATION_PANEL,但是这个窗口的layout发生像顶层窗口,而不是向容器的子窗口。public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;//多媒体窗口的覆盖层,位于TYPE_APPLICATION_MEDIA 和应用窗口之间,通常是透明的才有意义。public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4;//子窗口的结束值。public static final int LAST_SUB_WINDOW = 1999;//系统窗口的起始值。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;//alert窗口,通常在应用窗口之上。public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;//锁屏窗口。public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;//短暂的通知窗口。public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;//系统的overlay窗口,显示在一切之上,但是不能有input焦点,否则会妨碍keyguard。public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;//电话优先窗口,即使keyguard是active的,也会显示。public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;//从状态栏下拉出的panel,recentpanel。public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;//输入法窗口。public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;//墙纸窗口,位于任何想在wallpaper之上的窗口后面。public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;//音量条窗口。public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;//屏保窗口,仅仅在keyguard之上。public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;//系统窗口的结束值。public static final int LAST_SYSTEM_WINDOW      = 2999;}

当进程想WMS申请一个窗口时,要指定窗口类型,WMS会根据申请的窗口类型及当前系统中已有窗口的情况,分配层级值,层级越大的窗口越靠近用户。层级的分配规则主要由assignLayersLocked实现。


final void assignLayersLocked(WindowList windows)@WindowLayersController.java {int curBaseLayer = 0;int curLayer = 0;//windows保存了当前系统中的所有窗口。for (int i = 0, windowCount = windows.size(); i < windowCount; i++) {final WindowState w = windows.get(i);boolean layerChanged = false;int oldLayer = w.mLayer;if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i > 0 && w.mIsWallpaper)) {//这个窗口的基础层级跟前一个窗口的基础层级一致,只要添加间隔WINDOW_LAYER_MULTIPLIER。这个间隔值是5。curLayer += WINDOW_LAYER_MULTIPLIER;}else{//如果不一致,把 curBaseLayer设置为这个窗口的值。curBaseLayer = curLayer = w.mBaseLayer;}}}

一个窗口的mBaseLayer的值是怎么来的呢?一个窗口有关的信息都是在WindowState中保存的。


WindowState(...WindowState attachedWindow,WindowManager.LayoutParams a,...)@WindowState.java{if ((mAttrs.type >= FIRST_SUB_WINDOW &&mAttrs.type <= LAST_SUB_WINDOW)) {//如果子窗口,层级值取决于父窗口的类型,每种类型在窗口管理策略中有一个对照表,来确定基础层级值。mBaseLayer = mPolicy.windowTypeToLayerLw(attachedWindow.mAttrs.type) *WindowManagerService.TYPE_LAYER_MULTIPLIER+ WindowManagerService.TYPE_LAYER_OFFSET;//子窗口,还有一个相对父窗口的偏移值,这个偏移值决定了子窗口可能在父窗口之上,也可能在父窗口之下。mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);}else{//基础层级值还要乘上TYPE_LAYER_MULTIPLIER(10000),加上偏移 TYPE_LAYER_OFFSET(1000),因为系统中可能出现同类型的多个窗口,所以要有一个较大的间隔。mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)* WindowManagerService.TYPE_LAYER_MULTIPLIER+ WindowManagerService.TYPE_LAYER_OFFSET;}}

上面计算层级值时,用到mPolicy,就是窗口管理策略类的实例。Android手机系统,默认的窗口管理策略类是PhoneWindowManager,在WindowManagerService.java中直接实例化了相应对象。

finalWindowManagerPolicy mPolicy = new PhoneWindowManager();

所以WindowState构造函数中用到的两个函数windowTypeToLayerLwsubWindowTypeToLayerLw都是PhoneWindowManager中的方法。


public int windowTypeToLayerLw(int type)@PhoneWindowManager.java {        if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {            return 2;        }        switch (type) {        case TYPE_PRIVATE_PRESENTATION:            return 2;        case TYPE_WALLPAPER:            // wallpaper is at the bottom, though the window manager may move it.            return 2;        case TYPE_DOCK_DIVIDER:            return 2;        case TYPE_QS_DIALOG:            return 2;        case TYPE_PHONE:            return 3;        case TYPE_SEARCH_BAR:        case TYPE_VOICE_INTERACTION_STARTING:            return 4;        case TYPE_VOICE_INTERACTION:            // voice interaction layer is almost immediately above apps.            return 5;        case TYPE_INPUT_CONSUMER:            return 6;        case TYPE_SYSTEM_DIALOG:            return 7;        case TYPE_TOAST:            // toasts and the plugged-in battery thing            return 8;        case TYPE_PRIORITY_PHONE:            // SIM errors and unlock.  Not sure if this really should be in a high layer.            return 9;        case TYPE_DREAM:            // used for Dreams (screensavers with TYPE_DREAM windows)            return 10;        case TYPE_SYSTEM_ALERT:            // like the ANR / app crashed dialogs            return 11;        case TYPE_INPUT_METHOD:            // on-screen keyboards and other such input method user interfaces go here.            return 12;        case TYPE_INPUT_METHOD_DIALOG:            // on-screen keyboards and other such input method user interfaces go here.            return 13;        case TYPE_KEYGUARD_SCRIM:            // the safety window that shows behind keyguard while keyguard is starting            return 14;        case TYPE_STATUS_BAR_SUB_PANEL:            return 15;        case TYPE_STATUS_BAR:            return 16;        case TYPE_STATUS_BAR_PANEL:            return 17;        case TYPE_KEYGUARD_DIALOG:            return 18;        case TYPE_VOLUME_OVERLAY:            // the on-screen volume indicator and controller shown when the user            // changes the device volume            return 19;        case TYPE_SYSTEM_OVERLAY:            // the on-screen volume indicator and controller shown when the user            // changes the device volume            return 20;        case TYPE_NAVIGATION_BAR:            // the navigation bar, if available, shows atop most things            return 21;        case TYPE_NAVIGATION_BAR_PANEL:            // some panels (e.g. search) need to show on top of the navigation bar            return 22;        case TYPE_SCREENSHOT:            // screenshot selection layer shouldn't go above system error, but it should cover            // navigation bars at the very least.            return 23;        case TYPE_SYSTEM_ERROR:            // system-level error dialogs            return 24;        case TYPE_MAGNIFICATION_OVERLAY:            // used to highlight the magnified portion of a display            return 25;        case TYPE_DISPLAY_OVERLAY:            // used to simulate secondary display devices            return 26;        case TYPE_DRAG:            // the drag layer: input for drag-and-drop is associated with this window,            // which sits above all other focusable windows            return 27;        case TYPE_ACCESSIBILITY_OVERLAY:            // overlay put by accessibility services to intercept user interaction            return 28;        case TYPE_SECURE_SYSTEM_OVERLAY:            return 29;        case TYPE_BOOT_PROGRESS:            return 30;        case TYPE_POINTER:            // the (mouse) pointer layer            return 31;        }        Log.e(TAG, "Unknown window type: " + type);        return 2;}

public int subWindowTypeToLayerLw(int type) @PhoneWindowManager.java{        switch (type) {        case TYPE_APPLICATION_PANEL:        case TYPE_APPLICATION_ATTACHED_DIALOG:            return APPLICATION_PANEL_SUBLAYER;        case TYPE_APPLICATION_MEDIA:            return APPLICATION_MEDIA_SUBLAYER;        case TYPE_APPLICATION_MEDIA_OVERLAY:            return APPLICATION_MEDIA_OVERLAY_SUBLAYER;        case TYPE_APPLICATION_SUB_PANEL:            return APPLICATION_SUB_PANEL_SUBLAYER;        case TYPE_APPLICATION_ABOVE_SUB_PANEL:            return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;        }        Log.e(TAG, "Unknown sub-window type: " + type);        return 0;    }


2),窗口都有那些属性。

窗口属性除了前面的窗口类型外,还有窗口标记,都是放置在WindowManager.LayoutParams中。


public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable @WindowManager.java{//只要这个窗口是可见的,即使屏幕是开启的也允许锁屏,可以单独使用,也可以结合FLAG_KEEP_SCREEN_ON,或者FLAG_SHOW_WHEN_LOCKED。public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001;//在这个窗口背后的所有东西都会变暗,使用dimAmount控制变暗的程度。public static final int FLAG_DIM_BEHIND        = 0x00000002;//这个窗口不获取按键输入焦点,所以不能把key或别的button事件给它,这些事件会发给它后面的窗口,这个标记会enable FLAG_NOT_TOUCH_MODAL。public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;//这个窗口不接收touch 事件。public static final int FLAG_NOT_TOUCHABLE      = 0x00000010;//如果FLAG_NOT_FOCUSABLE没有设置,这个窗口是focusable的,允许这个窗口外的pointer事件发给它后面的窗口,如果这个窗口是not focusable的,它自己会处理所有的pointer事件。public static final int FLAG_NOT_TOUCH_MODAL    = 0x00000020;//设置这个flag,如果设备睡眠了,你可以接收到第一次touch 事件,通常第一次的touch事件是被系统消费,因为用户看不到他们按到的是什么。public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;//只要窗口是可见的,就要设备保持屏幕是亮的。public static final int FLAG_KEEP_SCREEN_ON     = 0x00000080;//让窗口在整个屏幕范围内,忽略边上的装饰条(如状态栏)。public static final int FLAG_LAYOUT_IN_SCREEN   = 0x00000100;//允许窗口超过屏幕区域。public static final int FLAG_LAYOUT_NO_LIMITS   = 0x00000200;//隐藏所有的屏幕装饰条,全屏的窗口会忽略SOFT_INPUT_ADJUST_RESIZE整个值,窗口依然保持全屏不会resize。这个flag可以在主题中控制,如:android.R.attr#windowFullscreen,Theme_Black_NoTitleBar_Fullscreen。。。public static final int FLAG_FULLSCREEN      = 0x00000400;//会覆盖掉FLAG_FULLSCREEN,强制显示屏幕装饰条。public static final int FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800;//认为窗口的内容是受保护的,禁止出现在屏幕截图中,或者不安全的显示中。public static final int FLAG_SECURE             = 0x00002000;//有时跟屏幕贴的很近,如打电话时,这种情况下的某些事件可能是无意的,不应该响应。public static final int FLAG_IGNORE_CHEEK_PRESSES    = 0x00008000;//窗口可以显示在锁屏窗口之上,结合FLAG_KEEP_SCREEN_ON,点亮屏幕时在显示锁屏窗口前,可以直接显示这个窗口;结合FLAG_DISMISS_KEYGUARD,可以自动退出非安全的锁屏。public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;//系统墙纸会显示在窗口后面,只有窗口surface是透明的区域才能看到后面的墙纸。可以通过主题控制,android.R.attr#windowShowWallpaper,android.R.style#Theme_Wallpaper_NoTitleBar...public static final int FLAG_SHOW_WALLPAPER = 0x00100000;//窗口显示时,点亮屏幕。public static final int FLAG_TURN_SCREEN_ON = 0x00200000;//窗口显示时,退出非安全锁屏。public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;//设置这个flag的窗口会接收它范围之外的touch事件,发送给支持多点触控的其他窗口。public static final int FLAG_SPLIT_TOUCH = 0x00800000;//窗口是否需要硬件加速。可以通过编程的方式控制,比如:Window w = activity.getWindow();in Activity's onCreate();w.setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);这个flag的设置要在setContentView之前。如果在manifest中用android.R.attr#hardwareAccelerated打开了硬件加速,上面的方法不能disable。这个flag在activity和应用的xml属性中,是被系统默认enable的,在manifest把它disable,就可以在Activity或者dialog中通过上面的方法enable或者disable。public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000;//允许窗口的内容超出屏幕的overscan区域,窗口应该正确的调整它的内容来适应overscan区域。这个flag也可以在主题中控制,android.R.attr#windowOverscan,android.R.style#Theme_Holo_NoActionBar_Overscan…设置这个flag的窗口,正常的内容出现在overscan区域可能会有一定程度的模糊,为了确保内容的关键部分可以对用户可见,可以使用View.setFitsSystemWindows(boolean),设置view层次中一些点有适当的偏移量。类似的方法属性有:android.R.attr#fitsSystemWindows,View.fitSystemWindows(Rect),View.setSystemUiVisibility(int)...public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;//设置透明的状态栏,可以在主题中通过属性控制:android.R.attr#windowTranslucentStatus,android.R.style#Theme_Holo_NoActionBar_TranslucentDecor…设置这个flag的窗口,会自动设置View#SYSTEM_UI_FLAG_LAYOUT_STABLE,View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREENpublic static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;//使窗口置于本地焦点模式,这个模式下的窗口可以使用Window#setLocalFocus(boolean, boolean),控制焦点独立于windowmanager,通常这个模式下的窗口不会从WindowManager得到touch,key事件,而是仅仅通过本地injection(Window#injectInputEvent(InputEvent)).public static final int FLAG_LOCAL_FOCUS_MODE = 0x10000000;}

窗口标记的设置方法:

Windoww = activity.getWindow();

w.setFlags(W,indowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,

WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);


3),除了WindowManager.LayoutParams中的属性外,View.java中的一些Flag也会影响窗口的显示,如SystemUI相关的。


public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource @View.java{//setSystemUiVisibility(int),view请求systemUI可见。public static final int SYSTEM_UI_FLAG_VISIBLE = 0;//View请求systemUI进入低调模式,通常用于games,book readers,video plahers,或者其他身临其境的应用,这个模式下,状态栏或者导航图标会变暗。public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001;//View请求进入普通的全屏模式,以便在用户跟应用交互时,它的内容可以占据整个屏幕。这个flag跟WindowManager.LayoutParams.FLAG_FULLSCREEN有相同的视觉效果,在这中模式下的view 窗口,非关键性的屏幕装饰都会被隐藏,如果通过Window.FEATURE_ACTION_BAR_OVERLAY让ActionBar处于overlay模式,SYSTEM_UI_FLAG_FULLSCREEN这个flag也会隐藏actionbar。如果需要长时间的全屏,使用WindowManager.LayoutParams#FLAG_FULLSCREEN是较好的选择,如果是短暂的全屏可以使用SYSTEM_UI_FLAG_FULLSCREEN。public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004;public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100;public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200;public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400;public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800;public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000;...}

可以通过setSystemUiVisibility(int)设置一个View的属性,如果要设置整个Viewtree的属性,可以在ActivityonCreate中,setContentView之前,通过以下代码设置:

intviewFlag = View.SYSTEM_UI_FLAG_FULLSCREEN |SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION

|SYSTEM_UI_FLAG_LAYOUT_STABLE;

getWindow(),getDecorView().setSystemUiVisibility(viewFlag);


阅读全文
0 0
原创粉丝点击