全面了解Window

来源:互联网 发布:linux系统api有哪些 编辑:程序博客网 时间:2024/06/15 08:53

前置知识

  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.javapublic 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@Overridepublic void setStatusBarColor(int color) {    mStatusBarColor = color;    mForcedStatusBarColor = true;    if (mDecor != null) {        // 直接调用到了DecorView.updateColorViews()        mDecor.updateColorViews(null, false /* animate */);    }}

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

// DecorView.javaprivate 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.javaprivate 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@Overridepublic 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.javapublic 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.javaprivate final ArrayList<View> mViews = new ArrayList<View>();private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();private final ArrayList<WindowManager.LayoutParams> mParams =        new ArrayList<WindowManager.LayoutParams>();

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

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

// ViewRootImpl.javavoid 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.javavoid 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

@Overridepublic 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.javapublic 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.javaprivate 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等信息。分析布局更加全面。

    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}
0 0
原创粉丝点击