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