WMS相关学习-添加窗口(2)

前言

上文说到调用了WMS中的addWindow来添加窗口
其中各参数意义参考:
session: 即为Client端ViewRootImpl持有的mWindowSession。 这个mWindowSession为WindowManagerGlobal创建,针对当前App而不是单个activity的WMS的代理。
client: 为ViewRootImpl持有的mWindow, 也就是WMS向activity发送消息的aidl接口。同时在WMS端也起到索引窗口的作用。
attrs:为该窗口的layout属性设置。
viewVisibility:是否可见,对于刚加入的activity window, 一般都是invisible的。 frameworks/base/core/java/android/view/View.java中定义
displayId:显示在哪个屏幕上
outContentInsets:看名字,前面有个out, 代表是由WMS返回给activity的参数,说明窗口内容区域边衬大小。如图所示:
outStableInsets: 算上status bar 或者navigation bar 的边衬区域。通常fullscreen的界面会用到这个值。
outOutsets: chin跟content 区域的offset, 所谓的chin, 比如,某个区域并不实际显示在屏幕上,但是希望它像显示在屏幕上一样。一般情况下,只都为0。可以在系统的resource中设置该区域的值。Resource为config_windowOutsetBottom。
outInputChannel:在WMS中建立一对inputChannel, 这两个inputChannel,监听管道的消息,但是方向相反,一个用于input manager service 转送消息给activity, 并接受来自activity的消息。 另一个用于activity发送消息给inputManagerservice, 并监听input manager service发送的消息,这个会传送回activity

WMS addWindow的相关逻辑

WindowManagerService#addWindow

构造system_server端对应的WindowState

创造对应的WindowState

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
        WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
        int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
        PowerManagerWrapper powerManagerWrapper) {
    super(service);
    mSession = s;
    mClient = c; //mClient可以用来回调客户端的ViewRootImpl
    mAppOp = appOp;
    mToken = token;
    mAppToken = mToken.asAppWindowToken();
    mOwnerUid = ownerId;
    mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
    mWindowId = new WindowId(this);
    mAttrs.copyFrom(a);
    mLastSurfaceInsets.set(mAttrs.surfaceInsets);
    mViewVisibility = viewVisibility;
    mPolicy = mService.mPolicy;
    mContext = mService.mContext;
    DeathRecipient deathRecipient = new DeathRecipient();
    mSeq = seq;
    mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
    mPowerManagerWrapper = powerManagerWrapper;
    if (localLOGV) Slog.v(
        TAG, "Window " + this + " client=" + c.asBinder()
        + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
    try {
        c.asBinder().linkToDeath(deathRecipient, 0); //为mClient注册死亡回调
    } catch (RemoteException e) {
        mDeathRecipient = null;
        mIsChildWindow = false;
        mLayoutAttached = false;
        mIsImWindow = false;
        mIsWallpaper = false;
        mIsFloatingLayer = false;
        mBaseLayer = 0;
        mSubLayer = 0;
        mInputWindowHandle = null;
        mWinAnimator = null;
        return;
    }
    mDeathRecipient = deathRecipient;

    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.getWindowLayerLw(parentWindow)
                * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
        mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
        mIsChildWindow = true;

        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + parentWindow);
        parentWindow.addChild(this, sWindowSubLayerComparator);

        mLayoutAttached = mAttrs.type !=
                WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
        mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD
                || parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
        mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER;
    } else {
        // The multiplier here is to reserve space for multiple
        // windows in the same type layer.
        mBaseLayer = mPolicy.getWindowLayerLw(this)
                * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
        mSubLayer = 0;
        mIsChildWindow = false;
        mLayoutAttached = false;
        mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
                || mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
        mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
    }
    mIsFloatingLayer = mIsImWindow || mIsWallpaper;

    if (mAppToken != null && mAppToken.mShowForAllUsers) {
        // Windows for apps that can show for all users should also show when the device is
        // locked.
        mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
    }

    mWinAnimator = new WindowStateAnimator(this);
   //每个WindowState有一个WindowStateAnimator,用于管理surface和动画相关
    mWinAnimator.mAlpha = a.alpha;

    mRequestedWidth = 0;
    mRequestedHeight = 0;
    mLastRequestedWidth = 0;
    mLastRequestedHeight = 0;
    mLayer = 0;
    mInputWindowHandle = new InputWindowHandle(
            mAppToken != null ? mAppToken.mInputApplicationHandle : null, this, c,
                getDisplayId());
}

注册的客户端ViewRootImpl的死亡回调

private class DeathRecipient implements IBinder.DeathRecipient {
    @Override
    public void binderDied() {
        try {
            boolean resetSplitScreenResizing = false;
            synchronized(mService.mWindowMap) {
                final WindowState win = mService.windowForClientLocked(mSession, mClient, false);
                Slog.i(TAG, "WIN DEATH: " + win); //打印WIN DEATH
                if (win != null) {
                    final DisplayContent dc = getDisplayContent();
                    if (win.mAppToken != null && win.mAppToken.findMainWindow() == win) {
                        mService.mTaskSnapshotController.onAppDied(win.mAppToken);
                    }
                    win.removeIfPossible(shouldKeepVisibleDeadAppWindow());
                    if (win.mAttrs.type == TYPE_DOCK_DIVIDER) {
                        // The owner of the docked divider died :( We reset the docked stack,
                        // just in case they have the divider at an unstable position. Better
                        // also reset drag resizing state, because the owner can't do it
                        // anymore.
                        final TaskStack stack =
                                dc.getSplitScreenPrimaryStackIgnoringVisibility();
                        if (stack != null) {
                            stack.resetDockedStackToMiddle();
                        }
                        resetSplitScreenResizing = true;
                    }
                } else if (mHasSurface) {
                    Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid.");
                    WindowState.this.removeIfPossible();
                }
            }
            if (resetSplitScreenResizing) {
                try {
                    // Note: this calls into ActivityManager, so we must *not* hold the window
                    // manager lock while calling this.
                    mService.mActivityManager.setSplitScreenResizing(false);
                } catch (RemoteException e) {
                    // Local call, shouldn't return RemoteException.
                    throw e.rethrowAsRuntimeException();
                }
            }
        } catch (IllegalArgumentException ex) {
            // This will happen if the window has already been removed.
        }
    }
}

PhoneWindowManager#adjustWindowParamsLw

调整window的相关参数

@Override
public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
        boolean hasStatusBarServicePermission) {

    final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
    if (mScreenDecorWindows.contains(win)) {
        if (!isScreenDecor) {
            // No longer has the flag set, so remove from the set.
            mScreenDecorWindows.remove(win);
        }
    } else if (isScreenDecor && hasStatusBarServicePermission) {
        mScreenDecorWindows.add(win);
    }

    switch (attrs.type) {
        case TYPE_SYSTEM_OVERLAY:
        case TYPE_SECURE_SYSTEM_OVERLAY:
            // These types of windows can't receive input events.
            attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
            attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
            break;
        case TYPE_DREAM:
        case TYPE_WALLPAPER:
            // Dreams and wallpapers don't have an app window token and can thus not be
            // letterboxed. Hence always let them extend under the cutout.
            attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
            break;
        case TYPE_STATUS_BAR:

            // If the Keyguard is in a hidden state (occluded by another window), we force to
            // remove the wallpaper and keyguard flag so that any change in-flight after setting
            // the keyguard as occluded wouldn't set these flags again.
            // See {@link #processKeyguardSetHiddenResultLw}.
            if (mKeyguardOccluded) {
                attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
                attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
            }
            break;

        case TYPE_SCREENSHOT:
            attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
            break;

        case TYPE_TOAST:
            // While apps should use the dedicated toast APIs to add such windows
            // it possible legacy apps to add the window directly. Therefore, we
            // make windows added directly by the app behave as a toast as much
            // as possible in terms of timeout and animation.
            if (attrs.hideTimeoutMilliseconds < 0
                    || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
                attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
            }
            attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
            break;
    }

    if (attrs.type != TYPE_STATUS_BAR) { //只有status bar类型的窗口可以在锁屏上展示?
        // The status bar is the only window allowed to exhibit keyguard behavior.
        attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
    }
}

PhoneWindowManager#prepareAddWindowLw

做add window to system前的准备检查工作

/**
 * Preflight adding a window to the system.
 *
 * Currently enforces that three window types are singletons:
 * 
    *
  • STATUS_BAR_TYPE
  • *
  • KEYGUARD_TYPE
  • *
* * @param win The window to be added * @param attrs Information about the window to be added * * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, * WindowManagerImpl.ADD_MULTIPLE_SINGLETON */ @Override public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) { if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.STATUS_BAR_SERVICE, "PhoneWindowManager"); mScreenDecorWindows.add(win); } switch (attrs.type) { case TYPE_STATUS_BAR: mContext.enforceCallingOrSelfPermission( android.Manifest.permission.STATUS_BAR_SERVICE, "PhoneWindowManager"); if (mStatusBar != null) { if (mStatusBar.isAlive()) { return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; } } mStatusBar = win; mStatusBarController.setWindow(win); setKeyguardOccludedLw(mKeyguardOccluded, true /* force */); break; case TYPE_NAVIGATION_BAR: mContext.enforceCallingOrSelfPermission( android.Manifest.permission.STATUS_BAR_SERVICE, "PhoneWindowManager"); if (mNavigationBar != null) { if (mNavigationBar.isAlive()) { return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; } } mNavigationBar = win; mNavigationBarController.setWindow(win); mNavigationBarController.setOnBarVisibilityChangedListener( mNavBarVisibilityListener, true); if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar); break; case TYPE_NAVIGATION_BAR_PANEL: case TYPE_STATUS_BAR_PANEL: case TYPE_STATUS_BAR_SUB_PANEL: case TYPE_VOICE_INTERACTION_STARTING: mContext.enforceCallingOrSelfPermission( android.Manifest.permission.STATUS_BAR_SERVICE, "PhoneWindowManager"); break; } return ADD_OKAY; //准备完成后返回ADD_OKAY }

WindowState#attach

void attach() {
    if (localLOGV) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
    mSession.windowAddedLocked(mAttrs.packageName);
}

Session#windowAddedLocked

那么看起来每个应用进程对应一个Session,也对应一个mSurfaceSession

void windowAddedLocked(String packageName) {
    mPackageName = packageName; 
    mRelayoutTag = "relayoutWindow: " + mPackageName; //属性赋值
    if (mSurfaceSession == null) {
        if (WindowManagerService.localLOGV) Slog.v(
            TAG_WM, "First window added to " + this + ", creating SurfaceSession");
        mSurfaceSession = new SurfaceSession();
        if (SHOW_TRANSACTIONS) Slog.i(
                TAG_WM, "  NEW SURFACE SESSION " + mSurfaceSession);
        mService.mSessions.add(this); //WMS中的mSessions保存所有的Session
        if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
            mService.dispatchNewAnimatorScaleLocked(this);
        }
    }
    mNumWindow++;//Session中的窗口数量+1
}

然后win.mToken.addWindow(win);调用AppWindowToken.addWindow(WindowState) ,针对WindowToken形成一个WindowList List

AppWindowToken#addWindow

@Override
void addWindow(WindowState w) {
    super.addWindow(w);

    boolean gotReplacementWindow = false;
    for (int i = mChildren.size() - 1; i >= 0; i--) {
        final WindowState candidate = mChildren.get(i);
        gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);
    }

    // if we got a replacement window, reset the timeout to give drawing more time
    if (gotReplacementWindow) {
        mService.scheduleWindowReplacementTimeouts(this);
    }
    checkKeyguardFlagsChanged();
}

WindowToken#addWindow

void addWindow(final WindowState win) {
    if (DEBUG_FOCUS) Slog.d(TAG_WM,
            "addWindow: win=" + win + " Callers=" + Debug.getCallers(5));

    if (win.isChildWindow()) {
        // Child windows are added to their parent windows. //子窗口,WindowToken的mChildren不添加,直接return;而是会添加到父窗口WindowState的mChildren属性中
        return;
    }
    if (!mChildren.contains(win)) {
        if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
        addChild(win, mWindowComparator); //调用WindowContainer的addChild
        mService.mWindowsChanged = true;
        // TODO: Should we also be setting layout needed here and other places?
    }
}

注意WindowToken和WindowState均继承WindowContainer

43/**
44 * Container of a set of related windows in the window manager. Often this is an AppWindowToken,
45 * which is the handle for an Activity that it uses to display windows. For nested windows, there is
46 * a WindowToken created for the parent window to manage its children.
47 */
48class WindowToken extends WindowContainer {
class WindowState extends WindowContainer implements WindowManagerPolicy.WindowState

WindowContainer#addChild

/**
 * Adds the input window container has a child of this container in order based on the input
 * comparator.
 * @param child The window container to add as a child of this window container.
 * @param comparator Comparator to use in determining the position the child should be added to.
 *                   If null, the child will be added to the top.
 */
@CallSuper
protected void addChild(E child, Comparator comparator) {
    if (child.getParent() != null) {
        throw new IllegalArgumentException("addChild: container=" + child.getName()
                + " is already a child of container=" + child.getParent().getName()
                + " can't add to container=" + getName());
    }

    int positionToAdd = -1;
    if (comparator != null) {
        final int count = mChildren.size();
        for (int i = 0; i < count; i++) {
            if (comparator.compare(child, mChildren.get(i)) < 0) { 
                //通过传入的comparator对mChildren进行排序
                positionToAdd = i;
                break;
            }
        }
    }

    if (positionToAdd == -1) {
        mChildren.add(child);
    } else {
        mChildren.add(positionToAdd, child);
    }
    onChildAdded(child);

    // Set the parent after we've actually added a child in case a subclass depends on this.
    child.setParent(this); //为WindowState的mParent赋值 (那么一般来说WindowState.getParent()的mParent都是自己,对子窗口来说mParent为其父窗口)
}
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
protected final WindowList mChildren = new WindowList();

WindowManagerService#updateFocusedWindowLocked

调整窗口的focus,在WMS中的addView中会调用

// TODO: Move to DisplayContent
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
    WindowState newFocus = mRoot.computeFocusedWindow();
    if (mCurrentFocus != newFocus) {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
        // This check makes sure that we don't already have the focus
        // change message pending.
        mH.removeMessages(H.REPORT_FOCUS_CHANGE);
        mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
        // TODO(multidisplay): Focused windows on default display only.
        final DisplayContent displayContent = getDefaultDisplayContentLocked();
        boolean imWindowChanged = false;
        if (mInputMethodWindow != null) {
            final WindowState prevTarget = mInputMethodTarget;
            final WindowState newTarget =
                    displayContent.computeImeTarget(true /* updateImeTarget*/);

            imWindowChanged = prevTarget != newTarget;

            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
                    && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) {
                final int prevImeAnimLayer = mInputMethodWindow.mWinAnimator.mAnimLayer;
                displayContent.assignWindowLayers(false /* setLayoutNeeded */);
                imWindowChanged |=
                        prevImeAnimLayer != mInputMethodWindow.mWinAnimator.mAnimLayer;
            }
        }

        if (imWindowChanged) {
            mWindowsChanged = true;
            displayContent.setLayoutNeeded();
            newFocus = mRoot.computeFocusedWindow();
        }

        if (DEBUG_FOCUS_LIGHT || localLOGV) Slog.v(TAG_WM, "Changing focus from " +
                mCurrentFocus + " to " + newFocus + " Callers=" + Debug.getCallers(4));
        final WindowState oldFocus = mCurrentFocus;
        mCurrentFocus = newFocus;
        mLosingFocus.remove(newFocus);

        if (mCurrentFocus != null) {
            mWinAddedSinceNullFocus.clear();
            mWinRemovedSinceNullFocus.clear();
        }

        int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);

        if (imWindowChanged && oldFocus != mInputMethodWindow) {
            // Focus of the input method window changed. Perform layout if needed.
            if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                displayContent.performLayout(true /*initial*/,  updateInputWindows);
                focusChanged &= ~FINISH_LAYOUT_REDO_LAYOUT;
            } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
                // Client will do the layout, but we need to assign layers
                // for handleNewWindowLocked() below.
                displayContent.assignWindowLayers(false /* setLayoutNeeded */);
            }
        }

        if ((focusChanged & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
            // The change in focus caused us to need to do a layout.  Okay.
            displayContent.setLayoutNeeded();
            if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                displayContent.performLayout(true /*initial*/, updateInputWindows);
            }
        }

        if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
            // If we defer assigning layers, then the caller is responsible for
            // doing this part.
            mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
        }

        displayContent.adjustForImeIfNeeded();

        // We may need to schedule some toast windows to be removed. The toasts for an app that
        // does not have input focus are removed within a timeout to prevent apps to redress
        // other apps' UI.
        displayContent.scheduleToastWindowsTimeoutIfNeededLocked(oldFocus, newFocus);

        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        return true;
    }
    return false;
}

示例-添加一个Dialog和添加一个PopupMenu的区别

添加一个Dialog

adb shell dumpsys window w

  Window #5 Window{7425a59 u0 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA}:
    mDisplayId=0 stackId=3 mSession=Session{f547a5 6170:u0a10159} mClient=android.os.BinderProxy@ae5fea0
    mOwnerUid=10159 mShowToOwnerOnly=true package=com.test.weijuncheng.testactivity appop=NONE
    mAttrs={(0,0)(wrapxwrap) gr=CENTER sim={adjust=pan forwardNavigation} blurRatio=1.0 blurMode=0 ty=APPLICATION fmt=TRANSLUCENT wanim=0x10302f9 surfaceInsets=Rect(88, 88 - 88, 88)
      fl=DIM_BEHIND ALT_FOCUSABLE_IM SPLIT_TOUCH HARDWARE_ACCELERATED}
    Requested w=1024 h=537 mLayoutSeq=101
    mBaseLayer=21000 mSubLayer=0 mAnimLayer=0+=0 mLastLayer=0
    mToken=AppWindowToken{171b00d token=Token{a530aa4 ActivityRecord{2836537 u0 com.test.weijuncheng.testactivity/.ActivityA t110}}}
    mAppToken=AppWindowToken{171b00d token=Token{a530aa4 ActivityRecord{2836537 u0 com.test.weijuncheng.testactivity/.ActivityA t110}}}
     isAnimatingWithSavedSurface()= mAppDied=false    drawnStateEvaluated=true    mightAffectAllDrawn=true
    mViewVisibility=0x0 mHaveFrame=true mObscured=false
    mSeq=0 mSystemUiVisibility=0x0
    mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
    mFullConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
    mLastReportedConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
    mHasSurface=true isReadyForDisplay()=true mWindowRemovalAllowed=false
    mFrame=[28,884][1052,1421] last=[28,884][1052,1421]
    Frames: containing=[0,96][1080,2210] parent=[0,96][1080,2210]
        display=[0,96][1080,2210] overscan=[0,96][1080,2210]
        content=[28,884][1052,1421] visible=[28,884][1052,1421]
        decor=[0,96][1080,2210]
        outset=[0,0][0,0]
    Cur insets: overscan=[0,0][0,0] content=[0,0][0,0] visible=[0,0][0,0] stable=[0,0][0,0] surface=[88,88][88,88] outsets=[0,0][0,0] cutout=DisplayCutout{insets=Rect(0, 0 - 0, 0) boundingRect=Rect(422, -884 - 602, -804)}
    Lst insets: overscan=[0,0][0,0] content=[0,0][0,0] visible=[0,0][0,0] stable=[0,0][0,0] physical=[0,0][0,0] outset=[0,0][0,0] cutout=com.android.server.wm.utils.WmDisplayCutout@19b15ef2
    WindowStateAnimator{673d0cb com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA}:
       mAnimationIsEntrance=true      mSurface=Surface(name=com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA)/@0x89dc61e
      Surface: shown=true layer=0 alpha=1.0 rect=(0.0,0.0) 1200 x 713 transform=(1.0, 0.0, 1.0, 0.0)
      mDrawState=HAS_DRAWN       mLastHidden=false
      mSystemDecorRect=[0,0][1024,537] mLastClipRect=[0,0][1200,713]
      mHandleByGesture=false
    isOnScreen=true
    isVisible=true
  Window #6 Window{13922b1 u0 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA}:
    mDisplayId=0 stackId=3 mSession=Session{f547a5 6170:u0a10159} mClient=android.os.BinderProxy@ac3d158
    mOwnerUid=10159 mShowToOwnerOnly=true package=com.test.weijuncheng.testactivity appop=NONE
    mAttrs={(0,0)(fillxfill) sim={adjust=pan forwardNavigation} blurRatio=1.0 blurMode=0 ty=BASE_APPLICATION wanim=0x10302f8
      fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
      pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}
    Requested w=1080 h=2340 mLayoutSeq=101
    mBaseLayer=21000 mSubLayer=0 mAnimLayer=0+=0 mLastLayer=0
    mToken=AppWindowToken{171b00d token=Token{a530aa4 ActivityRecord{2836537 u0 com.test.weijuncheng.testactivity/.ActivityA t110}}}
    mAppToken=AppWindowToken{171b00d token=Token{a530aa4 ActivityRecord{2836537 u0 com.test.weijuncheng.testactivity/.ActivityA t110}}}
     isAnimatingWithSavedSurface()= mAppDied=false    drawnStateEvaluated=true    mightAffectAllDrawn=true
    mViewVisibility=0x0 mHaveFrame=true mObscured=false
    mSeq=0 mSystemUiVisibility=0x0
    mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
    mFullConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
    mLastReportedConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
    mHasSurface=true isReadyForDisplay()=true mWindowRemovalAllowed=false
    mFrame=[0,0][1080,2340] last=[0,0][1080,2340]
    Frames: containing=[0,0][1080,2340] parent=[0,0][1080,2340]
        display=[0,0][1080,2340] overscan=[0,0][1080,2340]
        content=[0,96][1080,2210] visible=[0,96][1080,2210]
        decor=[0,0][1080,2340]
        outset=[0,0][0,0]
    Cur insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] surface=[0,0][0,0] outsets=[0,0][0,0] cutout=DisplayCutout{insets=Rect(0, 80 - 0, 0) boundingRect=Rect(450, 0 - 630, 80)}
    Lst insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] physical=[0,0][0,0] outset=[0,0][0,0] cutout=com.android.server.wm.utils.WmDisplayCutout@216dfc9d
    WindowStateAnimator{eff0a8 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA}:
      mSurface=Surface(name=com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.ActivityA)/@0x3cbe396
      Surface: shown=true layer=0 alpha=1.0 rect=(0.0,0.0) 1080 x 2340 transform=(1.0, 0.0, 1.0, 0.0)
      mDrawState=HAS_DRAWN       mLastHidden=false
      mSystemDecorRect=[0,0][1080,2340] mLastClipRect=[0,0][1080,2340]
      mHandleByGesture=false
    isOnScreen=true
    isVisible=true
  Window #7 Window{9dfb88 u0 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity}:
    mDisplayId=0 stackId=2 mSession=Session{f547a5 6170:u0a10159} mClient=android.os.BinderProxy@5f9bb2b
    mOwnerUid=10159 mShowToOwnerOnly=true package=com.test.weijuncheng.testactivity appop=NONE
    mAttrs={(0,0)(fillxfill) sim={adjust=pan forwardNavigation} blurRatio=1.0 blurMode=0 ty=BASE_APPLICATION wanim=0x10302f8
      fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
      pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}
    Requested w=1080 h=2340 mLayoutSeq=68
    mBaseLayer=21000 mSubLayer=0 mAnimLayer=0+=0 mLastLayer=0
    mToken=AppWindowToken{79c7276 token=Token{5892111 ActivityRecord{354d38 u0 com.test.weijuncheng.testactivity/.MainActivity t109}}}
    mAppToken=AppWindowToken{79c7276 token=Token{5892111 ActivityRecord{354d38 u0 com.test.weijuncheng.testactivity/.MainActivity t109}}}
     isAnimatingWithSavedSurface()= mAppDied=false    drawnStateEvaluated=true    mightAffectAllDrawn=true
    mViewVisibility=0x8 mHaveFrame=true mObscured=true
    mSeq=0 mSystemUiVisibility=0x0
    mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
    mFullConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
    mLastReportedConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
    mHasSurface=false isReadyForDisplay()=false mWindowRemovalAllowed=false
    mFrame=[0,0][1080,2340] last=[0,0][1080,2340]
    Frames: containing=[0,0][1080,2340] parent=[0,0][1080,2340]
        display=[0,0][1080,2340] overscan=[0,0][1080,2340]
        content=[0,96][1080,2210] visible=[0,96][1080,2210]
        decor=[0,0][1080,2340]
        outset=[0,0][0,0]
    Cur insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] surface=[0,0][0,0] outsets=[0,0][0,0] cutout=DisplayCutout{insets=Rect(0, 80 - 0, 0) boundingRect=Rect(450, 0 - 630, 80)}
    Lst insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] physical=[0,0][0,0] outset=[0,0][0,0] cutout=com.android.server.wm.utils.WmDisplayCutout@216dfc9d
    WindowStateAnimator{b6cd7c1 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity}:
      mDrawState=NO_SURFACE       mLastHidden=true
      mSystemDecorRect=[0,0][1080,2340] mLastClipRect=[0,0][1080,2340]
      mHandleByGesture=false
    isOnScreen=false
    isVisible=false

注意Session,token,mAttrs.ty


Dialog_1.png

Dialog_2.png

Dialog也有自己对应的Window,DecorView,ViewRootImpl

Dialog#show

/**
 * Start the dialog and display it on screen.  The window is placed in the
 * application layer and opaque.  Note that you should not override this
 * method to do initialization when the dialog is shown, instead implement
 * that in {@link #onStart}.
 */
public void show() {
    if (mShowing) {
        if (mDecor != null) {
            if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
            }
            mDecor.setVisibility(View.VISIBLE);
        }
        return;
    }

    mCanceled = false;

    if (!mCreated) {
        dispatchOnCreate(null);
    } else {
        // Fill the DecorView in on any configuration changes that
        // may have occured while it was removed from the WindowManager.
        final Configuration config = mContext.getResources().getConfiguration();
        mWindow.getDecorView().dispatchConfigurationChanged(config);
    }

    onStart();
    mDecor = mWindow.getDecorView();

    if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
        final ApplicationInfo info = mContext.getApplicationInfo();
        mWindow.setDefaultIcon(info.icon);
        mWindow.setDefaultLogo(info.logo);
        mActionBar = new WindowDecorActionBar(this);
    }

    WindowManager.LayoutParams l = mWindow.getAttributes();
    boolean restoreSoftInputMode = false;
    if ((l.softInputMode
            & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
        l.softInputMode |=
                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
        restoreSoftInputMode = true;
    }

    mWindowManager.addView(mDecor, l); //添加Dialog对应window
    if (restoreSoftInputMode) {
        l.softInputMode &=
                ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
    }

    mShowing = true;

    sendShowMessage();  //使Dialog显示出来
}

popupMenu的添加

PopupMenu_1.png

调用PopupWindow的showAsDropDow

PopupWindow#showAsDropDow

/**
 * Displays the content view in a popup window anchored to the corner of
 * another view. The window is positioned according to the specified
 * gravity and offset by the specified x and y coordinates.
 * 

* If there is not enough room on screen to show the popup in its entirety, * this method tries to find a parent scroll view to scroll. If no parent * view can be scrolled, the specified vertical gravity will be ignored and * the popup will anchor itself such that it is visible. *

* If the view later scrolls to move anchor to a different * location, the popup will be moved correspondingly. * * @param anchor the view on which to pin the popup window * @param xoff A horizontal offset from the anchor in pixels * @param yoff A vertical offset from the anchor in pixels * @param gravity Alignment of the popup relative to the anchor * * @see #dismiss() */ public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) { if (isShowing() || !hasContentView()) { return; } TransitionManager.endTransitions(mDecorView); attachToAnchor(anchor, xoff, yoff, gravity); mIsShowing = true; mIsDropdown = true; final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getApplicationWindowToken()); preparePopup(p); final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff, p.width, p.height, gravity, mAllowScrollingAnchorParent); updateAboveAnchor(aboveAnchor); p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1; invokePopup(p); }

PopupWindow#invokePopup

/**
 * 

Invoke the popup window by adding the content view to the window * manager.

* *

The content view must be non-null when this method is invoked.

* * @param p the layout parameters of the popup's content view */ private void invokePopup(WindowManager.LayoutParams p) { if (mContext != null) { p.packageName = mContext.getPackageName(); } final PopupDecorView decorView = mDecorView; decorView.setFitsSystemWindows(mLayoutInsetDecor); setLayoutDirectionFromAnchor(); mWindowManager.addView(decorView, p); //WindowManagerImpl的addView,将decorView添加到window中 if (mEnterTransition != null) { decorView.requestEnterTransition(mEnterTransition); } }

一个Window对应一个WindowManagerImpl
WindowManagerImpl#addView->WindowManagerGlobal#addView -> 其中设置panelParentView(为MainActivity对应的decorView),创建decorView对应的ViewRootImpl,添加mViews,mRoots,mParams->ViewRootImpl#setView->WindowManagerService#addWindow

addWindow子窗口查找相应父窗口

if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
    parentWindow = windowForClientLocked(null, attrs.token, false); //得到的parentWindow为MainActivity对应的PhoneWindow
    if (parentWindow == null) {
        Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
              + attrs.token + ".  Aborting.");
        return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
    }
    if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
            && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
        Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
                + attrs.token + ".  Aborting.");
        return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
    }
}

addWindow创建子窗口WindowState

final WindowState win = new WindowState(this, session, client, token, parentWindow,
        appOp[0], seq, attrs, viewVisibility, session.mUid,
        session.mCanAddInternalSystemWindow);

根据(WindowToken)token和parentWindow等创建popupWindow对应的WindowState parentWindow用于计算mBaseLayer的值


PopupMenu_2.png
WindowState构造函数中
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.getWindowLayerLw(parentWindow)
            * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
    mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
    mIsChildWindow = true;

    if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + parentWindow);
    parentWindow.addChild(this, sWindowSubLayerComparator); //Activity父窗口addChild添加子窗口

    mLayoutAttached = mAttrs.type !=
            WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
    mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD
            || parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
    mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER;
} 
WindowContanier#addChild

此时this为Activity对应 WindowState

/**
 * Adds the input window container has a child of this container in order based on the input
 * comparator.
 * @param child The window container to add as a child of this window container.
 * @param comparator Comparator to use in determining the position the child should be added to.
 *                   If null, the child will be added to the top.
 */
@CallSuper
protected void addChild(E child, Comparator comparator) {
    if (child.getParent() != null) {
        throw new IllegalArgumentException("addChild: container=" + child.getName()
                + " is already a child of container=" + child.getParent().getName()
                + " can't add to container=" + getName());
    }

    int positionToAdd = -1;
    if (comparator != null) {
        final int count = mChildren.size();
        for (int i = 0; i < count; i++) {
            if (comparator.compare(child, mChildren.get(i)) < 0) {
                positionToAdd = i;
                break;
            }
        }
    }

    if (positionToAdd == -1) {
        mChildren.add(child);
    } else {
        mChildren.add(positionToAdd, child); //对子窗口,在父窗口对应的WindowState中的mChildren中添加子窗口对应的WindowState
    }
    onChildAdded(child);

    // Set the parent after we've actually added a child in case a subclass depends on this.
    child.setParent(this);
}

WindowContainer#setParent
final protected void setParent(WindowContainer parent) {
    mParent = parent; //设置popupWindow的 mParent属性
    // Removing parent usually means that we've detached this entity to destroy it or to attach
    // to another parent. In both cases we don't need to update the configuration now.
    if (mParent != null) {
        // Update full configuration of this container and all its children.
        onConfigurationChanged(mParent.getConfiguration());
        // Update merged override configuration of this container and all its children.
        onMergedOverrideConfigurationChanged();
    }

    onParentSet();
}

调用到WindowToken中的addWindow

此时this为popupWindow对应 WindowState(对于PopupMenu,子窗口直接返回)

void addWindow(final WindowState win) {
    if (DEBUG_FOCUS) Slog.d(TAG_WM,
            "addWindow: win=" + win + " Callers=" + Debug.getCallers(5));

    if (win.isChildWindow()) {
        // Child windows are added to their parent windows.
        return; //因为popupMenu是子窗口,直接return
    }
    if (!mChildren.contains(win)) {
        if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
        addChild(win, mWindowComparator);
        mService.mWindowsChanged = true;
        // TODO: Should we also be setting layout needed here and other places?
    }
}
WindowState#onParentSet
@Override
void onParentSet() {
    super.onParentSet();
    setDrawnStateEvaluated(false /*evaluated*/);

    getDisplayContent().reapplyMagnificationSpec();
}
WindowContainer#onParentSet
/**
 * Callback that is triggered when @link WindowContainer#setParent(WindowContainer)} was called.
 * Supposed to be overridden and contain actions that should be executed after parent was set.
 */
void onParentSet() {
    if (mParent == null) {
        return;
    }

    if (mSurfaceControl == null) {
        // If we don't yet have a surface, but we now have a parent, we should
        // build a surface.
        mSurfaceControl = makeSurface().build();
        getPendingTransaction().show(mSurfaceControl);
        updateSurfacePosition();
    } else {
        // If we have a surface but a new parent, we just need to perform a reparent. Go through
        // surface animator such that hierarchy is preserved when animating, i.e.
        // mSurfaceControl stays attached to the leash and we just reparent the leash to the
        // new parent.
        reparentSurfaceControl(getPendingTransaction(), mParent.mSurfaceControl); //reparent Surface
    }

    // Either way we need to ask the parent to assign us a Z-order.
    mParent.assignChildLayers(); //assign Z-order
    scheduleAnimation();
}
WindowContainer#assignChildLayers

用于决定相关连的窗口间的z-order的

void assignChildLayers() {
    assignChildLayers(getPendingTransaction());
    scheduleAnimation();
}
void assignChildLayers(Transaction t) {
    int layer = 0;

    // We use two passes as a way to promote children which
    // need Z-boosting to the end of the list.
    for (int j = 0; j < mChildren.size(); ++j) {
        final WindowContainer wc = mChildren.get(j);
        wc.assignChildLayers(t);
        if (!wc.needsZBoost()) {
            wc.assignLayer(t, layer++);
        }
    }
    for (int j = 0; j < mChildren.size(); ++j) {
        final WindowContainer wc = mChildren.get(j);
        if (wc.needsZBoost()) {
            wc.assignLayer(t, layer++);
        }
    }
}

WindowState#assignChildLayers
// then we can drop all negative layering on the windowing side and simply inherit
// the default implementation here.
public void assignChildLayers(Transaction t) {
    int layer = 1;
    for (int i = 0; i < mChildren.size(); i++) {
        final WindowState w = mChildren.get(i);

        // APPLICATION_MEDIA_OVERLAY needs to go above APPLICATION_MEDIA
        // while they both need to go below the main window. However the
        // relative layering of multiple APPLICATION_MEDIA/OVERLAY has never
        // been defined and so we can use static layers and leave it that way.
        if (w.mAttrs.type == TYPE_APPLICATION_MEDIA) {
            w.assignLayer(t, -2);
        } else if (w.mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) {
            w.assignLayer(t, -1);
        } else {
            w.assignLayer(t, layer);
        }
        w.assignChildLayers(t);
        layer++;
    }
}

WindowState#assignLayer
@Override
void assignLayer(Transaction t, int layer) {
    // See comment in assignRelativeLayerForImeTargetChild
    if (needsRelativeLayeringToIme()) {
        getDisplayContent().assignRelativeLayerForImeTargetChild(t, this);
        return;
    }
    super.assignLayer(t, layer);
}
WindowContainer#assignLayer
void assignLayer(Transaction t, int layer) {
    final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
    if (mSurfaceControl != null && changed) {
        setLayer(t, layer);
        mLastLayer = layer;
        mLastRelativeToLayer = null;
    }
}
SurfaceAnimator#setLayer
/**
 * Sets the layer of the surface.
 * 

* When the layer of the surface needs to be adjusted, we need to set it on the leash if the * surface is reparented to the leash. This method takes care of that. */ void setLayer(Transaction t, int layer) { t.setLayer(mLeash != null ? mLeash : mAnimatable.getSurfaceControl(), layer); }

SurfaceControl#setLayer
public Transaction setLayer(SurfaceControl sc, int z) {
    sc.checkNotReleased();
    nativeSetLayer(mNativeObject, sc.mNativeObject, z);
    return this;
}

SurfaceControl后续再看,但是应该是由layer的值来决定,本质上是由mChildren的顺序再决定,也就是addChild时的comparator来决定

对于子窗口,由mSubLayer决定
/**
 * Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
 * of z-order and 1 otherwise.
 */
private static final Comparator sWindowSubLayerComparator =
        new Comparator() {
            @Override
            public int compare(WindowState w1, WindowState w2) {
                final int layer1 = w1.mSubLayer;
                final int layer2 = w2.mSubLayer;
                if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) {
                    // We insert the child window into the list ordered by
                    // the sub-layer.  For same sub-layers, the negative one
                    // should go below others; the positive one should go
                    // above others.
                    return -1;
                }
                return 1;
            };
        };
对于Dialog的情况(Dialog不是子窗口)
90    /**
91     * Compares two child window of this token and returns -1 if the first is lesser than the
92     * second in terms of z-order and 1 otherwise.
93     */
94    private final Comparator mWindowComparator =
95            (WindowState newWindow, WindowState existingWindow) -> {
96        final WindowToken token = WindowToken.this;
97        if (newWindow.mToken != token) {
98            throw new IllegalArgumentException("newWindow=" + newWindow
99                    + " is not a child of token=" + token);
100        }
101
102        if (existingWindow.mToken != token) {
103            throw new IllegalArgumentException("existingWindow=" + existingWindow
104                    + " is not a child of token=" + token);
105        }
106
107        return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1;
108    };
183    /**
184     * Returns true if the new window is considered greater than the existing window in terms of
185     * z-order.
186     */
187    protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
188            WindowState existingWindow) {
189        // New window is considered greater if it has a higher or equal base layer.
190        return newWindow.mBaseLayer >= existingWindow.mBaseLayer;
191    }

针对Dialog这种情况,其WindowState的mParent为AppWindowToken,和普通Activity一样

popupMenu属于子窗口

  Window #5 Window{a45a614 u0 PopupWindow:6a36032}:
    mDisplayId=0 stackId=1 mSession=Session{552cc8e 5068:u0a10160} mClient=android.os.BinderProxy@5da8867
    mOwnerUid=10160 mShowToOwnerOnly=true package=com.test.weijuncheng.testactivity appop=NONE
    mAttrs={(0,382)(539x396) gr=TOP START CENTER DISPLAY_CLIP_VERTICAL sim={state=unchanged adjust=resize} blurRatio=1.0 blurMode=0 ty=APPLICATION_SUB_PANEL fmt=TRANSLUCENT surfaceInsets=Rect(88, 88 - 88, 88) (manual)
      fl=LAYOUT_NO_LIMITS ALT_FOCUSABLE_IM WATCH_OUTSIDE_TOUCH SPLIT_TOUCH HARDWARE_ACCELERATED FLAG_LAYOUT_ATTACHED_IN_DECOR
      pfl=WILL_NOT_REPLACE_ON_RELAUNCH LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME}
    Requested w=539 h=396 mLayoutSeq=290
    mParentWindow=Window{a1d1045 u0 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity} mLayoutAttached=true
    mBaseLayer=21000 mSubLayer=2 mAnimLayer=0+=0 mLastLayer=0
    mToken=AppWindowToken{8275ffc token=Token{e38d8ef ActivityRecord{ebfa1ce u0 com.test.weijuncheng.testactivity/.MainActivity t38}}}
    mAppToken=AppWindowToken{8275ffc token=Token{e38d8ef ActivityRecord{ebfa1ce u0 com.test.weijuncheng.testactivity/.MainActivity t38}}}
     isAnimatingWithSavedSurface()= mAppDied=false    drawnStateEvaluated=true    mightAffectAllDrawn=true
    mViewVisibility=0x0 mHaveFrame=true mObscured=false
    mSeq=0 mSystemUiVisibility=0x0
    mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
    mFullConfiguration={1.0 ?mcc?mnc [en_GB] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActiv
ityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
    mLastReportedConfiguration={1.0 ?mcc?mnc [en_GB] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscree
n mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
    mHasSurface=true isReadyForDisplay()=true mWindowRemovalAllowed=false
    mFrame=[0,382][539,778] last=[0,382][539,778]
    Frames: containing=[0,0][1080,2340] parent=[0,0][1080,2340]
        display=[-10000,-10000][10000,10000] overscan=[-10000,-10000][10000,10000]
        content=[0,382][539,778] visible=[0,382][539,778]
        decor=[0,0][1080,2340]
        outset=[0,0][0,0]
    Cur insets: overscan=[0,0][0,0] content=[0,0][0,0] visible=[0,0][0,0] stable=[0,0][0,0] surface=[88,88][88,88] outsets=[0,0][0,0] cutout=DisplayCutout{insets=Rect(0, 0 - 0, 0) boundingRect=Rect(450, -382 - 630, -302)}
    Lst insets: overscan=[0,0][0,0] content=[0,0][0,0] visible=[0,0][0,0] stable=[0,0][0,0] physical=[0,0][0,0] outset=[0,0][0,0] cutout=com.android.server.wm.utils.WmDisplayCutout@1a3bc8b1
    WindowStateAnimator{c9986d4 PopupWindow:6a36032}:
      mSurface=Surface(name=PopupWindow:6a36032)/@0x58cc9b9
      Surface: shown=true layer=0 alpha=1.0 rect=(0.0,0.0) 715 x 572 transform=(1.0, 0.0, 1.0, 0.0)
      mDrawState=HAS_DRAWN       mLastHidden=false
      mSystemDecorRect=[0,0][539,396] mLastClipRect=[0,0][715,572]
      mHandleByGesture=false
    isOnScreen=true
    isVisible=true
  Window #6 Window{a1d1045 u0 com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity}:
    mDisplayId=0 stackId=1 mSession=Session{552cc8e 5068:u0a10160} mClient=android.os.BinderProxy@fbb68bc
    mOwnerUid=10160 mShowToOwnerOnly=true package=com.test.weijuncheng.testactivity appop=NONE
    mAttrs={(0,0)(fillxfill) sim={adjust=pan forwardNavigation} blurRatio=1.0 blurMode=0 ty=BASE_APPLICATION wanim=0x10302f8
      fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
      pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}
    Requested w=1080 h=2340 mLayoutSeq=290
    mBaseLayer=21000 mSubLayer=0 mAnimLayer=0+=0 mLastLayer=0
    mToken=AppWindowToken{8275ffc token=Token{e38d8ef ActivityRecord{ebfa1ce u0 com.test.weijuncheng.testactivity/.MainActivity t38}}}
    mAppToken=AppWindowToken{8275ffc token=Token{e38d8ef ActivityRecord{ebfa1ce u0 com.test.weijuncheng.testactivity/.MainActivity t38}}}
     isAnimatingWithSavedSurface()= mAppDied=false    drawnStateEvaluated=true    mightAffectAllDrawn=true
    mViewVisibility=0x0 mHaveFrame=true mObscured=false
    mSeq=0 mSystemUiVisibility=0x0
    mGivenContentInsets=[0,0][0,0] mGivenVisibleInsets=[0,0][0,0]
    mFullConfiguration={1.0 ?mcc?mnc [en_GB] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
    mLastReportedConfiguration={1.0 ?mcc?mnc [en_GB] ldltr sw392dp w392dp h768dp 440dpi nrml long port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2340) mAppBounds=Rect(0, 80 - 1080, 2210) mWindowingMode=fullscreen mActivityType=standard} s.8 themeChanged=0 themeChangedFlags=0}
    mHasSurface=true isReadyForDisplay()=true mWindowRemovalAllowed=false
    mFrame=[0,0][1080,2340] last=[0,0][1080,2340]
    Frames: containing=[0,0][1080,2340] parent=[0,0][1080,2340]
        display=[0,0][1080,2340] overscan=[0,0][1080,2340]
        content=[0,96][1080,2210] visible=[0,96][1080,2210]
        decor=[0,0][1080,2340]
        outset=[0,0][0,0]
    Cur insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] surface=[0,0][0,0] outsets=[0,0][0,0] cutout=DisplayCutout{insets=Rect(0, 80 - 0, 0) boundingRect=Rect(450, 0 - 630, 80)}
    Lst insets: overscan=[0,0][0,0] content=[0,96][0,130] visible=[0,96][0,130] stable=[0,96][0,130] physical=[0,0][0,0] outset=[0,0][0,0] cutout=com.android.server.wm.utils.WmDisplayCutout@216dfc9d
    WindowStateAnimator{ae602ee com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity}:
      mSurface=Surface(name=com.test.weijuncheng.testactivity/com.test.weijuncheng.testactivity.MainActivity)/@0x6b307d
      Surface: shown=true layer=0 alpha=1.0 rect=(0.0,0.0) 1080 x 2340 transform=(1.0, 0.0, 1.0, 0.0)
      mDrawState=HAS_DRAWN       mLastHidden=false
      mSystemDecorRect=[0,0][1080,2340] mLastClipRect=[0,0][1080,2340]
      mHandleByGesture=false
    isOnScreen=true
    isVisible=true

注意token,mSubLayer,mFrame=[0,382]539,778等属性

总结

那么目前看起来,AppWindowToken和WindowState 都可能有多个mChildren (list of WindowState)
AppWindowToken可能包含多个WindowState;每个WindowState也可能包含除自己以外的WindowState

第一种情况:
AppWindowToken可能包含多个WindowState
Activity页面起一个Dialog (AppWindowToken包含两个WindowState,分别代表Activity和Dialog的WindowState,其mChildren.size()==0)

第二种情况:
每个WindowState也可能包含除自己以外的WindowState
Activity中起一个PopupMenu(AppWindowToken的mChildren只包含一个WindowState(代表Activity),这个WindowState的mChildren.size()==1,其值为PopupWindow的WindowState)


WMS窗口层级组织.png

总结

z-order看起来由mBaseLayer mSubLayer stack WindowList (mChildren)的顺序等共同决定的


addWindow.png

ViewRootImpl是ViewRoot的实现类,ViewRoot不是view,而是整个ViewTree的管理者。
DecorView是整个ViewTree的根布局视图

Activity有个PhoneWinodw; 然后再Activity resume的过程中,通过addView将DecorView安装到PhoneWinodw的下,并创建对应的ViewRootImpl来管理;并在此过程中创建WMS端对应的WindowState

你可能感兴趣的:(WMS相关学习-添加窗口(2))