全面了解Window

前置知识

  1. Window是什么?Window是一个组件,View是由Window呈现出来的。Window实际上就是管理着View,对Window的操作最终都会转化成对View的操作。
  2. 经常使用的WindowActivityDialogPopupWindowToast等。系统中常见的WindowStatusBarNavigationBarInputMethod(软键盘)等。StatusBarNavigationBar等是在单独的进程中使用的。

问题

1.WindowManager.LayoutParam(继承ViewGroup.LayoutParams)类很重要,flagstype 等等。

type,相当于Window 的类型,主要分为3大类。

  • 1-99对应应用Window(token 必须设置为Activity 的token,即Context需要设置为Activity)。Activity 中的Window 对应的type 是TYPE_BASE_APPLICATIONDialog默认的是TYPE_APPLICATIONWindowManager.LayoutParams默认构造函对应的type也是TYPE_APPLICATION
  • 1000-1999对应子Window。PopupWindow 默认是TYPE_APPLICATION_PANEL
  • 2000-2999 对应的是系统Window。Toast对应TYPE_TOAST,StatusBar对应TYPE_STATUS_BARNavigationBar对应TYPE_NAVIGATION_BAR,键盘对应着”TYPE_INPUT_METHOD”。

flags,各种不一样属性,控制Window 的一些特殊显示。

2.DialogPopupWindow的异同。

  • DialogPopupWindoow 都会在一个新的Window中展示。
  • Dialog不能使用ApplicationContext,上面就可以知道Dailog是应用Window,只能使用Activity
  • PopupWindow不能在Activity.onCreate中创建。PopupWindow默认是一个子Window,需要在Activity创建以后使用。
  • PopupWindow一定需要设置widthheight,默认是0。
  • Dialog是创建了一个PhoneWindow然后获取的DecorView,所有默认有Title,而PopupWindow没有。
  • PopupWindow默认不会响应Back键,可以设置popupWindow.setFocusable(true);
  • 通过Activity来管理Dialog的时候,Activity.mManagedDialogs,当Activity后台销毁的时候再次进入可以恢复(参考Dialog.onSaveInstanceStateDialog.onRestoreInstanceState)。而PopupWindow没有恢复机制。

至于网上很多说PopupWindow是阻塞式的而Dialog是非阻塞式的,是非常误解人的。关于坑爹的PopupWindow的“阻塞”争议问题:Android没有真正的“阻塞式”对话框

3.Toast展示以后可以将Toast点击的事件传递到下面的View,Dialog以及Popupindow都不行,跟WindowManager.LayoutParams.flags有关。

4.Activity设置windowSoftInputMode属性的时候,会对ActivityWindow有一些影响。

5.一个App 中有多少个Window?应该是某个状态下Window的个数,Activity+Dialog+PopupWindow+Toast+WindowManage.addView

基本操作

WindowManager继承ViewManager,基本的操作如下。操作的实际上是ViewWindowManagerImpl保存着一族对应的mViewsmRootsmParams。对于每一个展示的Window实际上对应着mViews[k]mRoots[k]mParams[k]。具体可以看后面的流程分析。

// ViewManager.java
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);

流程分析

Window.setStatusBarColor流程(api 21以上)。

StatusBarNavigationBar都是一个View展示在最上面和最下面??

1.Window.setStatusBarColor`。

// PhoneWindow.java
@Override
public void setStatusBarColor(int color) {
    mStatusBarColor = color;
    mForcedStatusBarColor = true;
    if (mDecor != null) {
        // 直接调用到了DecorView.updateColorViews()
        mDecor.updateColorViews(null, false /* animate */);
    }
}

2.DecorView.updateColorViews。从代码中看就是修改了mNavigationColorViewStatemStatusColorViewState里面包含的ViewbackgroundColor

// DecorView.java
private WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
    // insets null animate false
    WindowManager.LayoutParams attrs = getAttributes();
    // 获取系统状态栏的显示属性
    int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
    if (!mIsFloating && ActivityManager.isHighEndGfx()) {
        boolean disallowAnimate = !isLaidOut();
        disallowAnimate |= ((mLastWindowFlags ^ attrs.flags)
                & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
        mLastWindowFlags = attrs.flags;
        if (insets != null) {
            // 省略相关代码
        }

        // 这里相当于是横竖屏判断
        boolean navBarToRightEdge = mLastBottomInset == 0 && mLastRightInset > 0;
        int navBarSize = navBarToRightEdge ? mLastRightInset : mLastBottomInset;
        // 更新Navigation
        updateColorViewInt(mNavigationColorViewState, sysUiVisibility, mNavigationBarColor,
                navBarSize, navBarToRightEdge, 0 /* rightInset */,
                animate && !disallowAnimate);

        boolean statusBarNeedsRightInset = navBarToRightEdge
                && mNavigationColorViewState.present;
        int statusBarRightInset = statusBarNeedsRightInset ? mLastRightInset : 0;
        // 更新Status
        updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor,
                mLastTopInset, false /* matchVertical */, statusBarRightInset,
                animate && !disallowAnimate);
    }

    // 省略代码
    return insets;
}

3.DecorView.updateColorViewInt

// DecorView.java
private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
    int size, boolean verticalBar, int rightMargin, boolean animate, boolean force) {
    // animate false
    state.present = (sysUiVis & state.systemUiHideFlag) == 0
            && (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
            && ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
                || force);
    boolean show = state.present
            && (color & Color.BLACK) != 0
            && ((mWindow.getAttributes().flags & state.translucentFlag) == 0  || force);
    boolean showView = show && !isResizing() && size > 0;

    boolean visibilityChanged = false;
    View view = state.view;

    int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size;
    int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT;
    // 横屏和竖屏展示的为位置不一样,分别对应着设置的horizontalGravity和verticalGravity
    int resolvedGravity = verticalBar ? state.horizontalGravity : state.verticalGravity;

    if (view == null) {
        if (showView) {
            // 为空会创建。相当于创建了Navigation 和Status View
            // 即改变StatusBar/NavigationBar 实际上是改变了一个View 的颜色
            state.view = view = new View(mContext);
            view.setBackgroundColor(color);
            view.setTransitionName(state.transitionName);
            view.setId(state.id);
            visibilityChanged = true;
            view.setVisibility(INVISIBLE);
            state.targetVisibility = VISIBLE;

            LayoutParams lp = new LayoutParams(resolvedWidth, resolvedHeight,
                    resolvedGravity);
            lp.rightMargin = rightMargin;
            addView(view, lp);
            updateColorViewTranslations();
        }
    } else {
        int vis = showView ? VISIBLE : INVISIBLE;
        visibilityChanged = state.targetVisibility != vis;
        state.targetVisibility = vis;
        LayoutParams lp = (LayoutParams) view.getLayoutParams();
        if (lp.height != resolvedHeight || lp.width != resolvedWidth
                || lp.gravity != resolvedGravity || lp.rightMargin != rightMargin) {
            lp.height = resolvedHeight;
            lp.width = resolvedWidth;
            lp.gravity = resolvedGravity;
            lp.rightMargin = rightMargin;
            view.setLayoutParams(lp);
        }
        if (showView) {
            view.setBackgroundColor(color);
        }
    }
    // 省略颜色修改无关代码
    state.visible = show;
    state.color = color;
}

setStatusBarColor(api 21以上)这个流程可以分析出来,ActivityDecoeViewStatusBarNavigationBar对应的是一个普通的View(系统中的StatusBarNavigationBar都对应着一个WindowStatusBar中展示的电量、wifi等都是Window中的ViewNavigationBar中展示的返回键、Home键等也是Window中的View)。可以通过反射改变StatusBar颜色和大小来验证(看源码也行的)DecoeView对应着的是普通的View

/** * 利用反射来设置StatusBar(DecorView中对应的StatusBar)颜色和高度(需要api21 以上) */
public void changeStatusBarColor2(View view) {
    // reflect 改变
    try {
        Field field = getWindow().getDecorView().getClass().getDeclaredField("mStatusColorViewState");
        field.setAccessible(true);
        Object object = field.get(getWindow().getDecorView());
        Field objectField = object.getClass().getDeclaredField("view");
        objectField.setAccessible(true);
        View view1 = (View) objectField.get(object);
        Log.e("ChangeStatusBarColor", "status bar height = " + view1.getHeight());
        view1.setBackgroundColor(0xffff0000);
        ViewGroup.LayoutParams params =  view1.getLayoutParams();
        params.height = 200;
        view1.setLayoutParams(params);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

WindowManager.addView()流程。

1.执行到WindowManagerImpl.addView()WindowManagerImpl继承WindowManager)。

// WindowManagerImpl.java
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    // 在Activity 中调用的话,这里的mParentWindow 就会是Activity 中的Window。
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}

2.执行到WindowManagerGlobal.addView() 方法。

// WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    if (display == null) {
        throw new IllegalArgumentException("display must not be null");
    }
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }
    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    ... // 省略很多代码
    ViewRootImpl root;
    synchronized (mLock) {
        ... // 省略很多代码
        root = new ViewRootImpl(view.getContext(), display);
        view.setLayoutParams(wparams);
        mViews.add(view); // 在mViews中增加了需要add 的View
        mRoots.add(root); // 在mRoots 中增加新的ViewRootImpl
        mParams.add(wparams); // mParams 中增加新的WindowManager.LayoutParams
    }
    try {
        root.setView(view, wparams, panelParentView);
    } catch (RuntimeException e) {
        synchronized (mLock) {
            final int index = findViewLocked(view, false);
            if (index >= 0) {
                removeViewLocked(index, true);
            }
        }
    throw e;
    }
}

一个WindowManager中对应着一系列的mViewsmRootsmParams,也就是WindowManager管理着多个Window,每一个Window都对应着mViews[k]mRoots[k]mParams[k]如下所示。

// WindowManagerGlobal.java
private final ArrayList mViews = new ArrayList();
private final ArrayList mRoots = new ArrayList();
private final ArrayList mParams =
        new ArrayList();

3.执行到ViewRootImpl.setView()方法。ViewRootImpl相当于ViewViewManager之间的桥梁。里面的代码比较的长,会执行到ViewRootImpl.requestLayout()

4.执行到ViewRootImpl.requestLayout()方法以及mWindowSession.addToDisplay,其中ViewRootImpl.requestLayout()会接着执行到了ViewRootImpl.scheduleTraversals()

// ViewRootImpl.java
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        // 这里通过mChoreographer.postCallback,最后相当于通过Handler发送了一个消息
        //最后会执行到mTraversalRunnable的run
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

5.执行到TraversalRunnable.run(),最后执行到了ViewRootImpl.doTraversal()

// ViewRootImpl.java
void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        if (mProfile) {
            Debug.startMethodTracing("ViewAncestor");
        }
        performTraversals();
        if (mProfile) {
            Debug.stopMethodTracing();
            mProfile = false;
        }
    }
}

6.执行到ViewRootImpl.performTraversals()。计算希望的大小,
判断是否是第一次,判断视图是否修改(例如:内容区域),判断Window 是否需要调整大小,判断是否改变了View 的可见性。最后会执行到ViewRootImpl.performMeasure()ViewRootImpl.performLayout()ViewRootImpl.performDraw()

7.ViewRootImpl.performMeasure()会调用View.measure对View进行测量;ViewRootImpl.performLayout()会调用View.layout对View进行布局。ViewRootImpl.performDraw()会调用ViewRootImpl.draw,然后会调用到ViewRootImpl.drawSoftware,最后就会调用到View.draw。这一系列的操作完成以后就会相当于展示创建了一个View,大小、位置以及视图也完全处理完毕。

8.第4步中执行到ViewRootImpl.requestLayout()以后的过程已经分析完毕,相当于是对View 进行了测量、布局以及绘制。接下来执行mWindowSession.addToDisplaymWindowSession对应的是一个IWindowSession.aidl,Java 层实现的类是com.android.server.wm.Session

@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
    Rect outOutsets, InputChannel outInputChannel) {
    // mService 对应的是WindowManagerService 
    return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
            outContentInsets, outStableInsets, outOutsets, outInputChannel);
}

9.执行WindowManagerService.addWindow。这里就是Window的添加等,没有细看。

总结:通过WindowManagerWindow的操作实际上就是对里面View的操作,展示的也是里面View的信息。

WindowManager.removeView()流程。

这里有一个问题需要考虑一下,通过Activity.getWindowManager().removeView(View view),这里removeView的参数是什么?Activity中设置的View中的一个子View`吗?

addView第2步就有说明,这个View其实是一个整体的View,不是某个View中的子View而是一个Window 中展示的View。

1.直接看到WindowManagerGlobal.removeView()

// WindowManagerGlobal.java
public void removeView(View view, boolean immediate) {
    if (view == null) {
        throw new IllegalArgumentException("view must not be null");
    }
    synchronized (mLock) {
        // 获取到view 对应的index,默认是-1
        int index = findViewLocked(view, true);
        View curView = mRoots.get(index).getView();
        removeViewLocked(index, immediate);
        if (curView == view) {
            return;
        }
        throw new IllegalStateException("Calling with view " + view
                + " but the ViewAncestor is attached to " + curView);
    }
}

2.执行WindowManagerGlobal.removeViewLocked

// WindowManagerGlobal.java
private void removeViewLocked(int index, boolean immediate) {
    ViewRootImpl root = mRoots.get(index);
    View view = root.getView();
    if (view != null) {
        InputMethodManager imm = InputMethodManager.getInstance();
        // 执行remove 操作。
        if (imm != null) {
            imm.windowDismissed(mViews.get(index).getWindowToken());
        }
    }
    // 执行die 操作。
    boolean deferred = root.die(immediate);
    if (view != null) {
        view.assignParent(null);
        if (deferred) {
            // 将View 加入到mDyingViews 中。
            mDyingViews.add(view);
        }
    }
}

总结:removeView也是对View的操作。

PopupWindow显示流程

showAsDropDown(View anchor)/showAtLocation(View parent, int gravity, int x, int y)preparePopup(WindowManager.LayoutParams p),最后invokePopup(WindowManager.LayoutParams p),这里不再分析。

Dialog显示流程

show(),这里不再分析。

其它内容

1.查看当前Window的信息

Egos-MacBook-Pro:~ Egos$ adb shell dumpsys window windows | grep -E 'mCurrentFocus'
  // Activity 对应的当前Window 信息
  mCurrentFocus=Window{1cd90da2 u0 com.egos.samples/com.egos.samples.window.WindowActivity}
  Egos-MacBook-Pro:~ Egos$ adb shell dumpsys window windows | grep -E 'mCurrentFocus'
  // Activity 打开PopupWindow(使用Dialog 的时候效果也是一样的)之后对应的当前Window 信息
  mCurrentFocus=Window{1ad2aefa u0 com.egos.samples/com.egos.samples.window.WindowActivity}

2.adb shell dumpsys window 查看当前所有的Window信息,包括Window的大小、位置。下面一个例子,拿中Window #3 来展示mAttrs就展示了大小,mHasSurface展示了起始位置。WindownManage.LayoutParams.mTitle 对应了名称。

    Window #3 Window{914ba56 u0 com.egos.samples/com.egos.samples.window.WindowActivity}:
    mDisplayId=0 stackId=1 mSession=Session{b853937 2930:u0a10102} mClient=android.os.BinderProxy@4d81c71
    mOwnerUid=10102 mShowToOwnerOnly=true package=com.egos.samples appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(200x200) sim=#20 ty=2 fl=#0}
    Requested w=200 h=200 mLayoutSeq=152
    mHasSurface=true mShownPosition=[440,824] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{31dbad7 com.egos.samples/com.egos.samples.window.WindowActivity}:
      Surface: shown=true layer=21015 alpha=1.0 rect=(440.0,824.0) 200.0 x 200.0

一个详细的例子。下面总共有9个Window(0,1,..8),可以看到NavigationBarStatusBar(StatusBarWindowManager管理着StatusBar Window的)等其实都是Window。也非常好验证,将StatusBar向下滑动唤出全屏的通知栏,执行adb shell dumpsys window会发现StatusBar 变成了全屏(从mAttrs可以看出)。

PS:PhoneStatusBar.java控制着StatusBarNavigationBar。详情可以查看源码frameworks.base.packages.SystemUI包下面的代码,包含了StatusBarNavigationBar、截屏Window、锁屏Window等。

Egos-MacBook-Pro:aosp Egos$ adb shell dumpsys window
//.. 这里省略了很多信息,下面总共有9个Window(0,1,..8)
WINDOW MANAGER WINDOWS (dumpsys window windows)
  Window #8 Window{c65e61c u0 NavigationBar}:
    mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@d23238f
    mOwnerUid=10023 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#20 ty=2019 fl=#1840068 fmt=-3}
    Requested w=1080 h=144 mLayoutSeq=271
    mHasSurface=true mShownPosition=[0,1776] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{4b5dd83 NavigationBar}:
      mAnimating=false mLocalAnimating=false mAnimationIsEntrance=true mAnimation=null mStackClip=1
      Surface: shown=true layer=211000 alpha=1.0 rect=(0.0,1776.0) 1080.0 x 144.0
  Window #7 Window{6fa7c9a u0 StatusBar}:
    mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@4f62d45
    mOwnerUid=10023 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillx72) gr=#30 sim=#10 ty=2000 fl=#81840048 fmt=-3 vsysui=0x600}
    Requested w=1080 h=72 mLayoutSeq=271
    mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{83a4c32 StatusBar}:
      mAnimating=false mLocalAnimating=false mAnimationIsEntrance=true mAnimation=null mStackClip=1
      Surface: shown=true layer=161000 alpha=1.0 rect=(0.0,0.0) 1080.0 x 72.0
  Window #6 Window{7cba79f u0 KeyguardScrim}:
    mDisplayId=0 stackId=0 mSession=Session{ddf9b54 1962:1000} mClient=android.view.ViewRootImpl$W@2c300ec
    mOwnerUid=1000 mShowToOwnerOnly=false package=android appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#10 ty=2029 fl=#1110900 pfl=0x1 fmt=-3 or=5 vsysui=0x3610000}
    Requested w=1080 h=1776 mLayoutSeq=58
    mHasSurface=false mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{b8b9c3d KeyguardScrim}:
    mLastFreezeDuration=+2m59s819ms
  Window #5 Window{401d23f u0 AssistPreviewPanel}:
    mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@eb66e5e
    mOwnerUid=10023 mShowToOwnerOnly=true package=com.android.systemui appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillx750) gr=#800053 sim=#31 ty=2033 fl=#1000118 fmt=-3 vsysui=0x700}
    Requested w=0 h=0 mLayoutSeq=57
    mHasSurface=false mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{10d4994 AssistPreviewPanel}:
      mShownAlpha=0.0 mAlpha=1.0 mLastAlpha=0.0
  Window #4 Window{7af7b99 u0 DockedStackDivider}:
    mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@ab9dce0
    mOwnerUid=10023 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillx144) sim=#20 ty=2034 fl=#21840028 pfl=0x40 fmt=-3 vsysui=0x700}
    Requested w=1080 h=144 mLayoutSeq=271
    mPolicyVisibility=false mPolicyVisibilityAfterAnim=false mAppOpVisibility=true mAttachedHidden=false
    mHasSurface=false mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{d3489e7 DockedStackDivider}:
      mShownAlpha=0.0 mAlpha=1.0 mLastAlpha=0.0
  Window #3 Window{699ad0c u0 com.egos.samples/com.egos.samples.toast.ToastActivity}:
    mDisplayId=0 stackId=1 mSession=Session{153e999 3360:u0a10102} mClient=android.os.BinderProxy@e9ef03f
    mOwnerUid=10102 mShowToOwnerOnly=true package=com.egos.samples appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#120 ty=1 fl=#81810100 pfl=0x20000 wanim=0x1030465 vsysui=0x600 needsMenuKey=2}
    Requested w=1080 h=1704 mLayoutSeq=271
    mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{7b190d3 com.egos.samples/com.egos.samples.toast.ToastActivity}:
      Surface: shown=true layer=21015 alpha=1.0 rect=(0.0,0.0) 1080.0 x 1920.0
  Window #2 Window{df42f03 u0 com.android.launcher3/com.android.launcher3.Launcher}:
    mDisplayId=0 stackId=0 mSession=Session{da8c367 2497:u0a10014} mClient=android.os.BinderProxy@820f3b2
    mOwnerUid=10014 mShowToOwnerOnly=true package=com.android.launcher3 appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#120 ty=1 fl=#81910100 fmt=-2 wanim=0x1030465 vsysui=0x700 needsMenuKey=2}
    Requested w=1080 h=1920 mLayoutSeq=227
    mHasSurface=false mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{371f101 com.android.launcher3/com.android.launcher3.Launcher}:
    mLastFreezeDuration=+2m59s941ms
    mWallpaperX=0.0 mWallpaperY=0.5
  Window #1 Window{2126153 u0 com.android.systemui/com.android.systemui.recents.RecentsActivity}:
    mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@c0a3d42
    mOwnerUid=10023 mShowToOwnerOnly=true package=com.android.systemui appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#120 ty=1 fl=#81910100 pfl=0x24040 fmt=-3 vsysui=0x700 needsMenuKey=2}
    Requested w=1080 h=1920 mLayoutSeq=187
    mHasSurface=false mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{9f984a2 com.android.systemui/com.android.systemui.recents.RecentsActivity}:
      mAnimating=true mLocalAnimating=false mAnimationIsEntrance=false mAnimation=null mStackClip=1
      XForm: has=true hasLocal=false {alpha=1.0 matrix=[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
      mShownAlpha=0.0 mAlpha=1.0 mLastAlpha=0.0
      mGlobalScale=1.0 mDsDx=1.0 mDtDx=0.0 mDsDy=0.0 mDtDy=1.0
  Window #0 Window{c4fa95f u0 com.android.systemui.ImageWallpaper}:
    mDisplayId=0 stackId=0 mSession=Session{39b4687 2046:u0a10023} mClient=android.os.BinderProxy@6adfe
    mOwnerUid=10023 mShowToOwnerOnly=true package=com.android.systemui appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(1920x1920) gr=#800033 ty=2013 fl=#318 fmt=1 wanim=0x10302f2}
    Requested w=1920 h=1920 mLayoutSeq=238
    mIsImWindow=false mIsWallpaper=true mIsFloatingLayer=true mWallpaperVisible=false
    mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{860a6e8 com.android.systemui.ImageWallpaper}:
      Surface: shown=false layer=21000 alpha=1.0 rect=(0.0,0.0) 1920.0 x 1920.0
    mLastFreezeDuration=+2m58s925ms
    mWallpaperX=0.0 mWallpaperY=0.5

  mCurConfiguration={1.0 310mcc260mnc [en_US] ldltr sw360dp w360dp h568dp 480dpi nrml port finger qwerty/v/v dpad/v s.6}
  mHasPermanentDpad=false
  mCurrentFocus=Window{699ad0c u0 com.egos.samples/com.egos.samples.toast.ToastActivity}
  mFocusedApp=AppWindowToken{26954dc token=Token{2ae93ae ActivityRecord{9a6a429 u0 com.egos.samples/.toast.ToastActivity t169}}}
  mInTouchMode=true mLayoutSeq=271
  mLastDisplayFreezeDuration=0 due to Window{df42f03 u0 com.android.launcher3/com.android.launcher3.Launcher}
  mLastWakeLockHoldingWindow=null mLastWakeLockObscuringWindow=Window{699ad0c u0 com.egos.samples/com.egos.samples.toast.ToastActivity}
Egos-MacBook-Pro:aosp Egos$ 

3.PhoneWindowManager.java拦截键盘消息(比如home操作、截屏操作等)的处理类。

4.通过Android Studio查看View Hierarchy等信息。分析布局更加全面。
全面了解Window_第1张图片

    View Hierarchy:
      com.android.internal.policy.DecorView{3afab2c V.E..... ... 0,0-1080,1920}
        android.widget.LinearLayout{7fb79f5 V.E..... ... 0,0-1080,1776}
          android.view.ViewStub{db9c38a G.E..... ... 0,0-0,0 #10203e8 android:id/action_mode_bar_stub}
          android.widget.FrameLayout{8687dfb V.E..... ... 0,0-1080,1776}
            android.support.v7.widget.ActionBarOverlayLayout{6024e18 V.E..... ... 0,0-1080,1776 #7f0c0055 app:id/decor_content_parent}
              android.support.v7.widget.ContentFrameLayout{156c071 V.E..... ... 0,0-1080,1776 #1020002 android:id/content}
                android.widget.LinearLayout{8f88e56 V.E..... ... 0,0-1080,1776}
                  android.support.v7.widget.AppCompatButton{9b6fed7 VFED..C. ... 0,240-635,384}
                  android.support.v7.widget.AppCompatButton{5da33c4 VFED..C. ... 0,384-659,528}
                  android.support.v7.widget.AppCompatButton{745f2ad VFED..C. ... 0,528-653,672}
              android.support.v7.widget.ActionBarContainer{78739e2 V.ED.... ... 0,72-1080,240 #7f0c0056 app:id/action_bar_container}
                android.support.v7.widget.Toolbar{f02b173 V.E..... ... 0,0-1080,168 #7f0c0057 app:id/action_bar}
                  android.support.v7.widget.AppCompatTextView{828c830 V.ED.... ... 48,43-280,124}
                  android.support.v7.widget.ActionMenuView{b7c0ca9 V.E..... ... 1080,0-1080,168}
                android.support.v7.widget.ActionBarContextView{363122e G.E..... ... 0,0-0,0 #7f0c0058 app:id/action_context_bar}
        android.view.View{e4cf1cf V.ED.... ... 0,1776-1080,1920 #1020030 android:id/navigationBarBackground}
        android.view.View{d8a375c V.ED.... ... 0,0-1080,72 #102002f android:id/statusBarBackground}

你可能感兴趣的:(Android)