zoukankan      html  css  js  c++  java
  • android Gui系统之WMS(1)----window flags & view flags

    SurfaceFlinger 前面说的,就是一个surface的合成。SurfaceFlinger就是一个默默的记录着,它不会对surface的内容有什么改动。

    WMS(WindowsManagerService)就是对surface的管理,或者说是一个大管家。它负责协调各方面资源。

    ViewRoot就是一个个演员,负责表演(产生surface)。

    从IO系统角度而言,WMS至少要干这几件事。

    全局窗口管理

    全局事件派发

    键盘

    触摸屏

    1.WMS综述

    1)WMS将以同AMS等一样的形式,系统server的一部分。

    由SystemServer负责启动

    知道系统关闭才能停止

    发生异常的时候,能够自我恢复

    2)SurfaceFlinger 和WMS将有很多交集。

    3)有显示需求的图层。可以想见,界面显示是分不同层级的。

    4)inputManagerService 当有按键或者触摸事件时,WMS时最好的管理员。

    5)AMS 同WMS 也有交互。

    6)Bind交互

    从WMS窗口的实现来讲,主要包含如下子功能

    窗口的添加和删除

    启动窗口

    窗口动画

    窗口大小

    窗口层级

    事件派发

    1.1WMS的启动

     servicesjavacomandroidserverSystemServer.java

    private void startOtherServices() {
                inputManager = new InputManagerService(context);
                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    
                traceBeginAndSlog("StartWindowManagerService");
                wm = WindowManagerService.main(context, inputManager,
                        mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                        !mFirstBoot, mOnlyCore);
                ServiceManager.addService(Context.WINDOW_SERVICE, wm);
                ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
    }

    1.2 WMS提供的服务

    public class IWindowManagerImpl implements IWindowManager 

    提供了很多功能,包含屏幕获取,获取窗口大小,启动窗口等

    1.3 WMS工作方式

    WMS很复杂,以工作方式作为切入点是比较合适的。

     WMS,AMS,Activity之间的关系

    WMS 可以和AMS相互调用,Activity有Window的对象。

       public ViewRootImpl(Context context, Display display) {
            mContext = context;
            mWindowSession = WindowManagerGlobal.getWindowSession();
    public static IWindowSession getWindowSession() {
            synchronized (WindowManagerGlobal.class) {
                if (sWindowSession == null) {
                    try {
                        InputMethodManager imm = InputMethodManager.getInstance();
                        IWindowManager windowManager = getWindowManagerService();
                        sWindowSession = windowManager.openSession(
                                new IWindowSessionCallback.Stub() {
                                    @Override
                                    public void onAnimatorScaleChanged(float scale) {
                                        ValueAnimator.setDurationScale(scale);
                                    }
                                },
                                imm.getClient(), imm.getInputContext());
                    } catch (RemoteException e) {
                        Log.e(TAG, "Failed to open window session", e);
                    }
                }
                return sWindowSession;
            }
        }

    可以看到,是windowmanager提供的一个session

    当启动一个activity的时候,AMS会把记录放到activityRecord。同时WMS会对activity进行记录,就用WindowState

    2.窗口属性

    2.1窗口的层级和类型

    窗口的类型很多,不过,可以统一划分为3类,Application Window,System Window,Sub Window.

    它们全部定义在WindowManager.java

    2.1.1 普通窗口

    2.1.2 Sub Window

    这一类主要就是Dialog 之类的。

    2.1.3 系统窗口

    系统窗口非常多,主要由系统状态栏,来电,输入法等。

    具体的取值:

    Application Window:1-99

    SubWindow:100-1999

    SystemWindow:2000-2999

    当某个进程向WMS申请一个Window的时候,需要告诉系统窗口的类型。如果有3个app在运行中,则前台有3个窗口,这个时候,需要能调整它们的优先级。

    对于Window的显示,层级越高,显示越前面。这个显示的动作,由SurfaceFlinger来处理。

     if ((mAttrs.type >= FIRST_SUB_WINDOW &&
                    mAttrs.type <= LAST_SUB_WINDOW)) {
                // The multiplier here is to reserve space for multiple
                // windows in the same type layer.
                mBaseLayer = mPolicy.windowTypeToLayerLw(
                        attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER
                        + WindowManagerService.TYPE_LAYER_OFFSET;
                mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
                mAttachedWindow = attachedWindow;
    ......

    所有窗口的mBaseLayer可以分几步获得:

    @Step1:windowTypeToLayerLw

    这个根据不同的窗口类型做了简单的映射。

    @Override
        public int windowTypeToLayerLw(int type) {
            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_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_SYSTEM_ERROR:
                // system-level error dialogs
                return 23;
            case TYPE_MAGNIFICATION_OVERLAY:
                // used to highlight the magnified portion of a display
                return 24;
            case TYPE_DISPLAY_OVERLAY:
                // used to simulate secondary display devices
                return 25;
            case TYPE_DRAG:
                // the drag layer: input for drag-and-drop is associated with this window,
                // which sits above all other focusable windows
                return 26;
            case TYPE_ACCESSIBILITY_OVERLAY:
                // overlay put by accessibility services to intercept user interaction
                return 27;
            case TYPE_SECURE_SYSTEM_OVERLAY:
                return 28;
            case TYPE_BOOT_PROGRESS:
                return 29;
            case TYPE_POINTER:
                // the (mouse) pointer layer
                return 30;
            }
            Log.e(TAG, "Unknown window type: " + type);
            return 2;
        }
    windowTypeToLayerLw

    对于sub window而言,窗口类型取决于父窗口类型。

    @Step2. 上一步获得的值*TYPE_LAYER_MULTIPLIER(10000)+TYPE_LAYER_OFFSET(1000)

    同一类型的窗口可能由很多。1000.是为了移动一组window而设计的。

    @Step3.subWindowTypeToLayerLw 计算子窗口的layer。偏移量在1,或者-2都有可能。所以子窗口现在在父窗口的上面。或者下面,都可能。

    2.2窗口属性

    windowmanagerprolicy。android显示的同一的规则。手机有StatusBar,而平板有CombinedBar。类似,但是功能不一样。

    /**
     * WindowManagerPolicy implementation for the Android phone UI.  This
     * introduces a new method suffix, Lp, for an internal lock of the
     * PhoneWindowManager.  This is used to protect some internal state, and
     * can be acquired with either the Lw and Li lock held, so has the restrictions
     * of both of those when held.
     */
    public class PhoneWindowManager implements WindowManagerPolicy

    PhoneWindowManager 和call没有关系,它表述andorid phone的UI显示规则。

    2.3 layoutParams

    1)Type

    窗口类型,不再说明。

    2)Flags

    最典型的就是,保持屏幕常亮。这个可以使用FLAG_KEEP_SCREEN_ON。

    在activity下使用这个方法就可以:

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    FLAG_ALLOW_LOCK_WHILE_SCREEN_ON:只要此窗口可见,即使屏幕点亮,也允许锁屏。 从现实来讲,有这个需求吗? 测验后,实际效果,会半暗屏,但不会上锁。

    FLAG_DIM_BEHIND:在窗口后面的东西,都将变暗。 dialog之类的比较常用。一个非常有用的flag,尤其是需要做蒙层的时候。

    public class DimDialog extends Dialog {
        private static final float DIMDIALOG_TRANTANT = 0.3f;
        private static final float DIMDIALOG_BG_TRANTANT = 0.8f;
        public DimDialog(Context context) {
            super(context);
            setAttributes();
        }
    
        private void setAttributes() {
            WindowManager.LayoutParams lp=getWindow().getAttributes();
            lp.alpha=DIMDIALOG_TRANTANT;
            lp.dimAmount = DIMDIALOG_BG_TRANTANT;
            getWindow().setAttributes(lp);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        }
    
        public DimDialog(Context context, int themeResId) {
            super(context, themeResId);
            setAttributes();
        }
    
        protected DimDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
            super(context, cancelable, cancelListener);
            setAttributes();
        }
    }
    DimDialog

    FLAG_BLUR_BEHIND:高斯模糊,目前已经废弃,对性能的影响巨大,不建议使用。

    FLAG_NOT_FOCUSABLE:窗口不处理事件,将会传递到后面的其他窗口。同时FLAG_NOT_TOUCH_MODAL也会被设置。

    FLAG_NOT_TOUCHABLE:touch 事件传递到后面的窗口使用。

            getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
            |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

    FLAG_KEEP_SCREEN_ON:最常用,最经典的模式,屏幕常量

    FLAG_FULLSCREEN:全屏,没有状态栏。

    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

    动态调整全屏状态:

        private void full(boolean enable) {
            if (enable) {
                WindowManager.LayoutParams lp = getWindow().getAttributes();
                lp.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
                getWindow().setAttributes(lp);
                getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
            } else {
                WindowManager.LayoutParams attr = getWindow().getAttributes();
                attr.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
                getWindow().setAttributes(attr);
                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
            }
        }
    full

    FLAG_FORCE_NOT_FULLSCREEN:同FLAG_FULLSCREEN相反

    FLAG_SECURE:窗口无法被截屏。不安全的应用也无法显示等。

    FLAG_SCALED:按用户的要求调整窗口

    FLAG_IGNORE_CHEEK_PRESSES: 当屏幕有可能贴着脸时,这一选项可防止面颊对屏幕造成误操作。 

    FLAG_LAYOUT_INSET_DECOR:只能和FLAG_LAYOUT_IN_SCREEN一起使用,充分考虑各种情况

    FLAG_SHOW_WHEN_LOCKED:在锁屏的时候,可以显示该页面,也是非常重要的flag。关于锁屏的问题可以参考 锁屏上显示Activity 这篇博客,此处不再叙述。

    FLAG_SHOW_WALLPAPER:当前activity为透明或者半透明的时候,让壁纸作为背景。

            WindowManager.LayoutParams lp=getWindow().getAttributes();
            lp.alpha = 0.5f;
            getWindow().setAttributes(lp);//设置透明度
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);//设置壁纸

    FLAG_TURN_SCREEN_ON:把屏幕点亮

    FLAG_DISMISS_KEYGUARD:解锁。是指普通锁屏,但是安全锁(图案或者密码锁屏界面)是无效的。 在电话界面,可以直接解锁,而不需进入锁屏界面。

    FLAG_HARDWARE_ACCELERATED:硬件加速,具体取决于硬件条件。

    3)systemUiVisibilty

    这个flag,定义在View中,

    这里先明确,这些flag起作用,首先这个view必须是可见的。而window的flag是全局的。

    View.SYSTEM_UI_FLAG_VISIBLE:显示状态栏 View.INVISIBLE 对应属性,隐藏状态栏。

    View.SYSTEM_UI_FLAG_FULLSCREEN 和上节讲到的FLAG_FULLSCREEN具有相同的效果,具体的细微差距,请参考http://www.360doc.com/content/15/0204/18/20385871_446270224.shtml 这篇文章。此处不做详细讨论。

    根据经验,View可以是临时的,而FLAG_FULLSCREEN 可以是长期的。

    View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 可以是navigationbar隐藏。

    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN activity全屏显示,但是statusbar不会隐藏,会把activity上面的部分,覆盖。

    View.SYSTEM_UI_FLAG_IMMERSIVE ,在5.1上测试的结果同SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 类似,activity全屏,但statusbar仍然存在。半透明的状态,但是状态栏点击会有反映。

    View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 在statusbar隐藏后,过几秒会自动出现。

    这里还要注意getWindow().getDecorView().setSystemUiVisibility();同setContentView(layout.activity_wall_layout);的顺序问题。

  • 相关阅读:
    Openssl和PKCS#11的故事
    SSL连接建立过程分析(5)
    SSL连接建立过程分析(1)
    关于OpenSSL支持USBKEY证书的尝试
    install the CLEARCASE with eclipse 3.4,duplicate location
    10种技巧可提升Android应用运行效果
    专访实战专家 揭秘iOS神奇开发之路
    win objc codeblocks
    redeclared as different kind of symbol ,undefined reference to `__objc_class_name_Rectangle12'
    201203NEWS
  • 原文地址:https://www.cnblogs.com/deman/p/5641765.html
Copyright © 2011-2022 走看看