Android WMS分析(一) WindowManager

1.WindowManager ,WMS,Window三者关系

WindowManager是一个接口类,继承自接口ViewManager,负责管理Window,他的实现类是WindowManagerImpl。如果我们相对Window进行添加,更新,删除,就需要通过WindowManager,其会将具体的工作交给WindowManagerService(WMS)处理

而Window是一个抽象类,具体实现类是PhoneWindow。Window包含了view并对view进行管理。Window是一个抽象概念,用来描述一个窗口,并不是真实存在的,Window的实体其实也是View。

2.一些重要的类介绍

2.1 ViewManager.java

WindowManager是一个接口类,继承自接口ViewManager

public interface ViewManager {

    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

从名称可以看出三个方法分别对应了View的添加,更新,删除

WindowManager在继承ViewManager的同时,也加入了很多功能。其中有两个方法是根据Window的特性加入的

public Display getDefaultDisplay();
public void removeViewImmediate(View view);

getDefaultDisplay()方法能够知道这个WindowManager实例将Window添加到哪个屏幕上,换句话说就是得到WindowManager所管理的屏幕(Display )。

removeViewImmediate()方法则贵的再这个方法返回前要立即执行View.onDetachedFromWindow(),来完成传入的View相关的销毁工作

2.2 Window和PhoneWindow

Window是一个抽象类,具体实现类是PhoneWindow

下面我们看下PhoneWindow是何时创建的

在Activity启动过程中会调用ActivityThread的preformLaunchActivity()方法,preformLaunchActivity()中会调用Activity.java的attach()方法,PhoneWindow就是在attach()中new出来的

    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 window, ActivityConfigCallback activityConfigCallback) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);

        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        ......
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        ......
    }

无论是Dialog还是Activity都是通过Window对象的setWindowManager方法将WindowManagerWindow关联。该函数是在Window中,看看实现:

    /**
     * Set the window manager for use by this Window to, for example,
     * display panels.  This is <em>not</em> used for displaying the
     * Window itself -- that must be done by the client.
     *
     * @param wm The window manager for adding new windows.
     */
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
        setWindowManager(wm, appToken, appName, false);
    }

    /**
     * Set the window manager for use by this Window to, for example,
     * display panels.  This is <em>not</em> used for displaying the
     * Window itself -- that must be done by the client.
     *
     * @param wm The window manager for adding new windows.
     */
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

WindowManagerImpl.java-->createLocalWindowManager()

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
    }

可以看到就是创建了WindowManager的实例WindowManagerImpl,同时将Window作为参数传了进来,这样WindowManagerImpl就持有了Window的引用,可以对Window进行操作,比如在Window中添加View

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

可以看出WindowManagerImpl虽然是WindowManager的实现类,但是没有实现什么功能,而是将功能实现委托给了WindowManagerGlobal,这就是典型的桥接模式

3.Window的属性

Window的类型有很多种,必然要应用程序窗口,输入法窗口,PopupWindow,Toast,Dialog......。总的来说Window分为三大类型,分别是Application Window(应用程序窗口),Sub Window(子窗口),System Window(系统窗口),每个大类型中又包含了很多种类型,它们都定义在WindowManager的静态内部类LayoutParams中,接下来分别对着三大类型进行分析。

3.1应用程序窗口

Activity就是典型的应用程序窗口,应用程序窗口包含以下类型:

        /**
         * Start of window types that represent normal application windows.
         *开始表示正常应用程序窗口的窗口类型。
         */
        public static final int FIRST_APPLICATION_WINDOW = 1;//应用程序窗口的初始值

        /**
         * Window type: an application window that serves as the "base" window
         * of the overall application; all other application windows will
         * appear on top of it.
         * In multiuser systems shows only on the owning user's window.
         *一个应用程序窗口,用作整个应用程序的“基础”窗口; 所有其他应用程序窗口将显示在它上面。
         */
        public static final int TYPE_BASE_APPLICATION   = 1;

        /**
         * Window type: a normal application window.  The {@link #token} must be
         * an Activity token identifying who the window belongs to.
         * In multiuser systems shows only on the owning user's window.
         *普通的应用程序窗口类型
         */
        public static final int TYPE_APPLICATION        = 2;

        /**
         * Window type: special application window that is displayed while the
         * application is starting.  Not for use by applications themselves;
         * this is used by the system to display something until the
         * application can show its own windows.
         * In multiuser systems shows on all users' windows.
         *用于再应用程序窗口启动前显示的窗口
         */
        public static final int TYPE_APPLICATION_STARTING = 3;

        /**
         * Window type: a variation on TYPE_APPLICATION that ensures the window
         * manager will wait for this window to be drawn before the app is shown.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_DRAWN_APPLICATION = 4;
        /**
         * End of types of application windows.
         */
        public static final int LAST_APPLICATION_WINDOW = 99;//应用程序窗口的结束值

3.2 子窗口

子窗口,不能独立存在,需依附其他窗口才可以,PopupWindow就属于子窗口。子窗口包含以下类型:

/**
         * Start of types of sub-windows.  The {@link #token} of these windows
         * must be set to the window they are attached to.  These types of
         * windows are kept next to their attached window in Z-order, and their
         * coordinate space is relative to their attached window.
         */
        public static final int FIRST_SUB_WINDOW = 1000;

        /**
         * Window type: a panel on top of an application window.  These windows
         * appear on top of their attached window.
         */
        public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;

        /**
         * Window type: window for showing media (such as video).  These windows
         * are displayed behind their attached window.
         */
        public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;

        /**
         * Window type: a sub-panel on top of an application window.  These
         * windows are displayed on top their attached window and any
         * {@link #TYPE_APPLICATION_PANEL} panels.
         */
        public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;

        /** Window type: like {@link #TYPE_APPLICATION_PANEL}, but layout
         * of the window happens as that of a top-level window, <em>not</em>
         * as a child of its container.
         */
        public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;

        /**
         * Window type: window for showing overlays on top of media windows.
         * These windows are displayed between TYPE_APPLICATION_MEDIA and the
         * application window.  They should be translucent to be useful.  This
         * is a big ugly hack so:
         * @hide
         */
        public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4;

        /**
         * Window type: a above sub-panel on top of an application window and it's
         * sub-panel windows. These windows are displayed on top of their attached window
         * and any {@link #TYPE_APPLICATION_SUB_PANEL} panels.
         * @hide
         */
        public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;

        /**
         * End of types of sub-windows.
         */
        public static final int LAST_SUB_WINDOW = 1999;

可以看出子窗口的Tpye值范围是1000~1999

3.3系统窗口

系统窗口包括Toast,输入法窗口,系统音量条窗口。。。


public static final int FIRST_SYSTEM_WINDOW     = 2000;
public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
......
public static final int LAST_SYSTEM_WINDOW      = 2999;

可以看出系统窗口的Tpye值范围是2000~2999

4. Window的标志

Window的标志也就是Flag,用于控制Window的显示,同样被定义在WindowManager的内部类LayoutParams

int FLAGS_CHANGED 用于表示flags发生了变化,关于此的详细内容请看后文。
int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON Window flag: as long as this window is visible to the user, allow the lock screen to activate while the screen is on.
当该window对用户可见的时候,允许锁屏。
int FLAG_ALT_FOCUSABLE_IM Window flag: invert the state of FLAG_NOT_FOCUSABLE with respect to how this window interacts with the current method.
int FLAG_BLUR_BEHIND Window flag: blur everything behind this window.
让该window后所有东西都模糊(blur)
int FLAG_DIM_BEHIND Window flag: everything behind this window will be dimmed.
让该window后所有的东西都成暗淡(dim)
int FLAG_DISMISS_KEYGUARD Window flag: when set the window will cause the keyguard to be dismissed, 
only if it is not a secure lock keyguard.
int FLAG_DITHER Window flag: turn on dithering when compositing this window to the screen.
开启抖动(dithering)
int FLAG_FORCE_NOT_FULLSCREEN Window flag: Override {@link #FLAG_FULLSCREEN and force the screen decorations (such as status bar) to be shown.
恢复window非全屏显示
int FLAG_FULLSCREEN Window flag: Hide all screen decorations (e.g.
让window进行全屏显示
int FLAG_HARDWARE_ACCELERATED

Indicates whether this window should be hardware accelerated.

对该window进行硬件加速.

该flag必须在设置你的Activity或Dialog的Content View之前进行设置,

而且如果你在mainfest文件中用Android:hardwareAccelerated开启了该属性的话,那么你在程序中就不能再改变它。mainfest文件中android:hardwareAccelerated属性默认是开启的("true")。

int FLAG_IGNORE_CHEEK_PRESSES Window flag: intended for windows that will often be used when the user is holding the screen against their face, it will aggressively filter the event stream to prevent unintended presses in this situation that may not be desired for a particular window, when such an event stream is detected, the application will receive a CANCEL motion event to indicate this so applications can handle this accordingly by taking no action on the event until the finger is released.
int FLAG_KEEP_SCREEN_ON Window flag: as long as this window is visible to the user, keep the device's screen turned on and bright.
当该window对用户可见时,让设备屏幕处于高亮(bright)状态。
int FLAG_LAYOUT_INSET_DECOR Window flag: a special option only for use in combination with FLAG_LAYOUT_IN_SCREEN.
int FLAG_LAYOUT_IN_SCREEN Window flag: place the window within the entire screen, ignoring decorations around the border (a.k.a.
让window占满整个手机屏幕,不留任何边界(border)
int FLAG_LAYOUT_NO_LIMITS Window flag: allow window to extend outside of the screen.
window大小不再不受手机屏幕大小限制,即window可能超出屏幕之外,这时部分内容在屏幕之外。
int FLAG_NOT_FOCUSABLE Window flag: this window won't ever get key input focus, so the user can not send key or other button events to it.
让window不能获得焦点,这样用户快就不能向该window发送按键事件及按钮事件
int FLAG_NOT_TOUCHABLE Window flag: this window can never receive touch events.
让该window不接受触摸屏事件
int FLAG_NOT_TOUCH_MODAL Window flag: Even when this window is focusable (its {@link #FLAG_NOT_FOCUSABLE is not set), 
allow any pointer events outside of the window to be sent to the windows behind it.
即使在该window在可获得焦点情况下,仍然把该window之外的任何event发送到该window之后的其他window.
int FLAG_SCALED Window flag: a special mode where the layout parameters are used to perform scaling of the surface when it is composited to the screen.
int FLAG_SECURE Window flag: don't allow screen shots while this window is displayed.
当该window在进行显示的时候,不允许截屏。
int FLAG_SHOW_WALLPAPER Window flag: ask that the system wallpaper be shown behind your window.
在该window后显示系统的墙纸(wallpaper)
int FLAG_SHOW_WHEN_LOCKED Window flag: special flag to let windows be shown when the screen is locked.
当锁屏的时候,显示该window.
int FLAG_SPLIT_TOUCH Window flag: when set the window will accept for touch events outside of its bounds to be sent to other windows that also support split touch. When this flag is not set, the first pointer that goes down determines the window to which all subsequent touches go until all pointers go up. When this flag is set, each pointer (not necessarily the first) that goes down determines the window to which all subsequent touches of that pointer will go until that pointer goes up thereby enabling touches with multiple pointers to be split across multiple windows
当该window在可以接受触摸屏情况下,让因在该window之外,而发送到后面的window的触摸屏可以支持split touch.
int FLAG_TOUCHABLE_WHEN_WAKING Window flag: When set, if the device is asleep when the touch screen is pressed, you will receive this first touch event.
当手机处于睡眠状态时,如果屏幕被按下,那么该window将第一个收到到事件
int FLAG_TURN_SCREEN_ON Window flag: when set as a window is being added or made visible, once the window has been shown then the system will poke the power manager's user activity (as if the user had woken up the device) to turn the screen on.
当然window被显示的时候,系统将把它当做一个用户活动事件,以点亮手机屏幕。
int FLAG_WATCH_OUTSIDE_TOUCH Window flag: if you have set FLAG_NOT_TOUCH_MODAL, you can set this flag to receive a single special MotionEvent with the action MotionEvent.ACTION_OUTSIDE 
for touches that occur outside of your window.
如果你设置了该flag,那么在你FLAG_NOT_TOUNCH_MODAL的情况下,即使触摸屏事件发送在该window之外,其事件被发送到了后面的window,那么该window仍然将以MotionEvent.ACTION_OUTSIDE形式收到该触摸屏事件

设置Window的Flag有三种方法,

第一种addFlags:

Window mWindow = getWindow()
mWindow.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    public void addFlags(int flags) {
        setFlags(flags, flags);
    }

第二种setFlags:

Window mWindow = getWindow()
mWindow.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
    public void setFlags(int flags, int mask) {
        final WindowManager.LayoutParams attrs = getAttributes();
        attrs.flags = (attrs.flags&~mask) | (flags&mask);
        mForcedWindowFlags |= mask;
        dispatchWindowAttributesChanged(attrs);
    }

第三种则是给LayoutParams设置Flag,并通过WindowManager的addView方法进行添加

LinearLayout.LayoutParams textParams = new LinearLayout.LayoutParams();
textParams.flag = LayoutParams.FLAG_FULLSCREEN;
WindowManager mWindowManager  = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
TextView mTextView  = new TextView(this);
mWindowManager.addView(mTextView ,textParams );

猜你喜欢

转载自blog.csdn.net/liu362732346/article/details/85321154