Android 窗口的计算过程

本文详细介绍了Android窗口的各个区域,包括overscanScreen、RestrictedOverScanScreen等,并解析了窗口大小计算的主要流程,从Session.relayout()到PhoneWindow.finishLayoutLw()。此外,还阐述了Surface的创建过程以及窗口层级(Z轴)的计算,涉及到windowTypeToLayerLw()和subWindowTypeToLayerLw()方法。最后,讨论了Android inset的调整过程。
摘要由CSDN通过智能技术生成

Android 窗口的几个区域的介绍:

1.overscanScreen区域,这个区域包括屏幕的overscan区域,相当于整个屏幕

2.RestrictedOverScanScreen区域,包括overscan区,不包含导航栏、因此这个区域上面到屏幕的顶部,下面就到导航栏的顶部。

3.RestrictedScreen区域,这个区域不包含overscan区域不包含导航栏

4.UnRestrictedScreen区域,不包含屏幕的overscan区域、包含状态栏和导航栏

5.stableFullScreen区域,包含状态栏、输入法、不包含导航栏

6.Decor区域,不包含状态栏、不包含导航栏、包含输入法区域

7.Curren区域、不包含状态栏、不包含导航栏、不包含输入法区域

8.stable区域,不包含状态栏、不包含导航栏,与stableFullScreen的区别是后者不考虑状态栏


Android窗口大小的计算主要流程如下:

Session.relayout()--> WindowManagerService.relayoutWindow()--> WindowManagerService.performLayoutAndPlaceSurfacesLocked()--> WindowManagerService.performLayoutAndPlaceSurfacesLockedLoop()--> WindowManagerService.performLayoutAndPlaceSurfacesLockedInner()--> WindowManagerService.assignLayersLocked()--> WindowManagerService.performLayoutAndPlaceSurfacesLockedInner()--> PhoneWindow.beginLayoutLw()--> PhoneWindow.layoutWindowLw()-->PhoneWindow.finishLayoutLw()

其中assignLayersLocked主要是计算窗口的层级,beginLayoutLw(),layoutWindowLw(),finishLayoutLw()主要是计算窗口的大小


1.beginLayoutLw()函数分析

/** {@inheritDoc} */
    @Override
    public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
                              int displayRotation) {
        mDisplayRotation = displayRotation;
        final int overscanLeft, overscanTop, overscanRight, overscanBottom;
		//下面这段代码主要是依据旋转的角度初始化overscan边衬区域
        if (isDefaultDisplay) {
            switch (displayRotation) {
                case Surface.ROTATION_90:
                    overscanLeft = mOverscanTop;
                    overscanTop = mOverscanRight;
                    overscanRight = mOverscanBottom;
                    overscanBottom = mOverscanLeft;
                    break;
                case Surface.ROTATION_180:
                    overscanLeft = mOverscanRight;
                    overscanTop = mOverscanBottom;
                    overscanRight = mOverscanLeft;
                    overscanBottom = mOverscanTop;
                    break;
                case Surface.ROTATION_270:
                    overscanLeft = mOverscanBottom;
                    overscanTop = mOverscanLeft;
                    overscanRight = mOverscanTop;
                    overscanBottom = mOverscanRight;
                    break;
                default:
                    overscanLeft = mOverscanLeft;
                    overscanTop = mOverscanTop;
                    overscanRight = mOverscanRight;
                    overscanBottom = mOverscanBottom;
                    break;
            }
        } else {
            overscanLeft = 0;
            overscanTop = 0;
            overscanRight = 0;
            overscanBottom = 0;
        }
		//初始化OverscanScreen,System,UnrestrictedScreen,RestrictedScreen,Dock,Content,VoiceContent,Stable,StableFullscreen
		//这些区域,目前这些区域主要是判断是否要剔除过扫描边衬(先不考虑状态栏和导航栏)
        mOverscanScreenLeft = mRestrictedOverscanScreenLeft = 0;
        mOverscanScreenTop = mRestrictedOverscanScreenTop = 0;
        mOverscanScreenWidth = mRestrictedOverscanScreenWidth = displayWidth;
        mOverscanScreenHeight = mRestrictedOverscanScreenHeight = displayHeight;
        mSystemLeft = 0;
        mSystemTop = 0;
        mSystemRight = displayWidth;
        mSystemBottom = displayHeight;
        mUnrestrictedScreenLeft = overscanLeft;
        mUnrestrictedScreenTop = overscanTop;
        mUnrestrictedScreenWidth = displayWidth - overscanLeft - overscanRight;
        mUnrestrictedScreenHeight = displayHeight - overscanTop - overscanBottom;
        mRestrictedScreenLeft = mUnrestrictedScreenLeft;
        mRestrictedScreenTop = mUnrestrictedScreenTop;
        mRestrictedScreenWidth = mSystemGestures.screenWidth = mUnrestrictedScreenWidth;
        mRestrictedScreenHeight = mSystemGestures.screenHeight = mUnrestrictedScreenHeight;
        mDockLeft = mContentLeft = mVoiceContentLeft = mStableLeft = mStableFullscreenLeft
                = mCurLeft = mUnrestrictedScreenLeft;
        mDockTop = mContentTop = mVoiceContentTop = mStableTop = mStableFullscreenTop
                = mCurTop = mUnrestrictedScreenTop;
        mDockRight = mContentRight = mVoiceContentRight = mStableRight = mStableFullscreenRight
                = mCurRight = displayWidth - overscanRight;
        mDockBottom = mContentBottom = mVoiceContentBottom = mStableBottom = mStableFullscreenBottom
                = mCurBottom = displayHeight - overscanBottom;
        mDockLayer = 0x10000000;
        mStatusBarLayer = -1;
		
        // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
        //用当前dock区域去初始化mTmpParentFrame等6个临时区域,这几个区域是在后面layoutWindowLw是要用到的,这里是为了通过全局变量实现函数参数传递
        final Rect pf = mTmpParentFrame;
        final Rect df = mTmpDisplayFrame;
        final Rect of = mTmpOverscanFrame;
        final Rect vf = mTmpVisibleFrame;
        final Rect dcf = mTmpDecorFrame;
        final Rect osf = mTmpOutsetFrame;
        pf.left = df.left = of.left = vf.left = mDockLeft;
        pf.top = df.top = of.top = vf.top = mDockTop;
        pf.right = df.right = of.right = vf.right = mDockRight;
        pf.bottom = df.bottom = of.bottom = vf.bottom = mDockBottom;
        dcf.setEmpty();  // Decor frame N/A for system bars.
        
		//一般都是默认的,所以会进入
        if (isDefaultDisplay) {
            // For purposes of putting out fake window up to steal focus, we will
            // drive nav being hidden only by whether it is requested.
            final int sysui = mLastSystemUiFlags;
            boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
            boolean navTranslucent = (sysui
                    & (View.NAVIGATION_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
            boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
            boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
            boolean navAllowedHidden = immersive || immersiveSticky;
            navTranslucent &= !immersiveSticky;  // transient trumps translucent
            boolean isKeyguardShowing = isStatusBarKeyguard() && !mHideLockScreen;
            if (!isKeyguardShowing) {
                navTranslucent &= areTranslucentBarsAllowed();
            }

            // When the navigation bar isn't visible, we put up a fake
            // input window to catch all touch events.  This way we can
            // detect when the user presses anywhere to bring back the nav
            // bar and ensure the application doesn't see the event.
            //只有在导航栏不可见并且不是沉浸式模式时需要额外的InptConsumer
            if (navVisible || navAllowedHidden) {
                if (mInputConsumer != null) {
                    mInputConsumer.dismiss();
                    mInputConsumer = null;
                }
            } else if (mInputConsumer == null) {
                mInputConsumer = mWindowManagerFuncs.addInputConsumer(mHandler.getLooper(),
                        mHideNavInputEventReceiverFactory);
            }

            // For purposes of positioning and showing the nav bar, if we have
            // decided that it can't be hidden (because of the screen aspect ratio),
            // then take that into account.
            navVisible |= !canHideNavigationBar();

            boolean updateSysUiVisibility = false;
			//如果导航栏是存在的那现在需要调整因为导航栏区域给各个区域大小的影响了
			//Dock,RestrictedScreen,RestrictedOverscan,System等区域都可能会被影响
            if (mNavigationBar != null) {
                boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
                // Force the navigation bar to its appropriate place and
                // size.  We need to do this directly, instead of relying on
                // it to bubble up from the nav bar, because this needs to
                // change atomically with screen rotations.
                mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight);
				//导航栏在底部的时候
                if (mNavigationBarOnBottom) {
                    // It's a system nav bar or a portrait screen; nav bar goes on bottom.
                    int top = displayHeight - overscanBottom
                            - mNavigationBarHeightForRotation[displayRotation];
                    mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);
                    mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
					//临时显示不影响区域计算
                    if (transientNavBarShowing) {
                        mNavigationBarController.setBarShowingLw(true);
                    } else if (navVisible) {
                        mNavigationBarController.setBarShowingLw(true);
                        mDockBottom = mTmpNavigationFrame.top;
                        mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;
                        mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;
                    } else {
                        // We currently want to hide the navigation UI.
                        mNavigationBarController.setBarShowingLw(false);
                    }
                    if (navVisible && !navTranslucent && !navAllowedHidden
                            && !mNavigationBar.isAnimatingLw()
                            && !mNavigationBarController.wasRecentlyTranslucent()) {
                        // If the opaque nav bar is currently requested to be visible,
                        // and not in the process of animating on or off, then
                        // we can tell the app that it is covered by it.
                        mSystemBottom = mTmpNavigationFrame.top;
                    }
                } else { //导航栏在右边的情况
                    // Landscape screen; nav bar goes to the right.
                    int left = disp
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值