Merge "Move logic about computing window frames to the client side"

This commit is contained in:
Tiger Huang
2021-10-19 18:20:41 +00:00
committed by Android (Google) Code Review
5 changed files with 222 additions and 163 deletions

View File

@@ -317,6 +317,26 @@ public class InsetsState implements Parcelable {
return insets;
}
public Insets calculateInsets(Rect frame, @InsetsType int types,
InsetsVisibilities overrideVisibilities) {
Insets insets = Insets.NONE;
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
InsetsSource source = mSources[type];
if (source == null) {
continue;
}
int publicType = InsetsState.toPublicType(type);
if ((publicType & types) == 0) {
continue;
}
if (!overrideVisibilities.getVisibility(type)) {
continue;
}
insets = Insets.max(source.calculateInsets(frame, true), insets);
}
return insets;
}
public Insets calculateVisibleInsets(Rect frame, @SoftInputModeFlags int softInputMode) {
Insets insets = Insets.NONE;
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
@@ -482,6 +502,26 @@ public class InsetsState implements Parcelable {
return mDisplayCutout.get();
}
public void getDisplayCutoutSafe(Rect outBounds) {
outBounds.set(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
final DisplayCutout cutout = mDisplayCutout.get();
final Rect displayFrame = mDisplayFrame;
if (!cutout.isEmpty()) {
if (cutout.getSafeInsetLeft() > 0) {
outBounds.left = displayFrame.left + cutout.getSafeInsetLeft();
}
if (cutout.getSafeInsetTop() > 0) {
outBounds.top = displayFrame.top + cutout.getSafeInsetTop();
}
if (cutout.getSafeInsetRight() > 0) {
outBounds.right = displayFrame.right - cutout.getSafeInsetRight();
}
if (cutout.getSafeInsetBottom() > 0) {
outBounds.bottom = displayFrame.bottom - cutout.getSafeInsetBottom();
}
}
}
public void setRoundedCorners(RoundedCorners roundedCorners) {
mRoundedCorners = roundedCorners;
}

View File

@@ -140,7 +140,6 @@ import android.os.Trace;
import android.os.UserHandle;
import android.sysprop.DisplayProperties;
import android.util.AndroidRuntimeException;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.IndentingPrintWriter;
@@ -160,7 +159,6 @@ import android.view.View.AttachInfo;
import android.view.View.FocusDirection;
import android.view.View.MeasureSpec;
import android.view.Window.OnContentApplyWindowInsetsListener;
import android.view.WindowInsets.Side.InsetsSide;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
@@ -511,9 +509,11 @@ public final class ViewRootImpl implements ViewParent,
private final Point mSurfaceSize = new Point();
private final Point mLastSurfaceSize = new Point();
final Rect mTempRect; // used in the transaction to not thrash the heap.
final Rect mVisRect; // used to retrieve visible rect of focused view.
private final Rect mTempBoundsRect = new Rect(); // used to set the size of the bounds surface.
private final Rect mVisRect = new Rect(); // used to retrieve visible rect of focused view.
private final Rect mTempRect = new Rect();
private final Rect mTempRect2 = new Rect();
private final WindowLayout mWindowLayout = new WindowLayout();
// This is used to reduce the race between window focus changes being dispatched from
// the window manager and input events coming through the input system.
@@ -809,8 +809,6 @@ public final class ViewRootImpl implements ViewParent,
mWidth = -1;
mHeight = -1;
mDirty = new Rect();
mTempRect = new Rect();
mVisRect = new Rect();
mWinFrame = new Rect();
mWindow = new W(this);
mLeashToken = new Binder();
@@ -985,29 +983,6 @@ public final class ViewRootImpl implements ViewParent,
}
}
// TODO(b/161810301): Make this private after window layout is moved to the client side.
public static void computeWindowBounds(WindowManager.LayoutParams attrs, InsetsState state,
Rect displayFrame, Rect outBounds) {
final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
final Rect df = displayFrame;
Insets insets = Insets.of(0, 0, 0, 0);
for (int i = types.size() - 1; i >= 0; i--) {
final InsetsSource source = state.peekSource(types.valueAt(i));
if (source == null) {
continue;
}
insets = Insets.max(insets, source.calculateInsets(
df, attrs.isFitInsetsIgnoringVisibility()));
}
final int left = (sidesToFit & WindowInsets.Side.LEFT) != 0 ? insets.left : 0;
final int top = (sidesToFit & WindowInsets.Side.TOP) != 0 ? insets.top : 0;
final int right = (sidesToFit & WindowInsets.Side.RIGHT) != 0 ? insets.right : 0;
final int bottom = (sidesToFit & WindowInsets.Side.BOTTOM) != 0 ? insets.bottom : 0;
outBounds.set(df.left + left, df.top + top, df.right - right, df.bottom - bottom);
}
private Configuration getConfiguration() {
return mContext.getResources().getConfiguration();
}
@@ -1168,8 +1143,13 @@ public final class ViewRootImpl implements ViewParent,
mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars;
mInsetsController.onStateChanged(mTempInsets);
mInsetsController.onControlsChanged(mTempControls);
computeWindowBounds(mWindowAttributes, mInsetsController.getState(),
getConfiguration().windowConfiguration.getBounds(), mTmpFrames.frame);
final InsetsState state = mInsetsController.getState();
final Rect displayCutoutSafe = mTempRect;
state.getDisplayCutoutSafe(displayCutoutSafe);
mWindowLayout.computeWindowFrames(mWindowAttributes, state,
displayCutoutSafe, getConfiguration().windowConfiguration.getBounds(),
mInsetsController.getRequestedVisibilities(),
null /* attachedWindowFrame */, mTmpFrames.frame, mTempRect2);
setFrame(mTmpFrames.frame);
if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
@@ -1966,11 +1946,11 @@ public final class ViewRootImpl implements ViewParent,
private void setBoundsLayerCrop(Transaction t) {
// Adjust of insets and update the bounds layer so child surfaces do not draw into
// the surface inset region.
mTempBoundsRect.set(0, 0, mSurfaceSize.x, mSurfaceSize.y);
mTempBoundsRect.inset(mWindowAttributes.surfaceInsets.left,
mTempRect.set(0, 0, mSurfaceSize.x, mSurfaceSize.y);
mTempRect.inset(mWindowAttributes.surfaceInsets.left,
mWindowAttributes.surfaceInsets.top,
mWindowAttributes.surfaceInsets.right, mWindowAttributes.surfaceInsets.bottom);
t.setWindowCrop(mBoundsLayer, mTempBoundsRect);
t.setWindowCrop(mBoundsLayer, mTempRect);
}
/**

View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import android.graphics.Insets;
import android.graphics.Rect;
/**
* Computes window frames.
* @hide
*/
public class WindowLayout {
private final Rect mTempDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
private final Rect mTempRect = new Rect();
public boolean computeWindowFrames(WindowManager.LayoutParams attrs, InsetsState state,
Rect displayCutoutSafe, Rect windowBounds, InsetsVisibilities requestedVisibilities,
Rect attachedWindowFrame, Rect outDisplayFrame, Rect outParentFrame) {
final int type = attrs.type;
final int fl = attrs.flags;
final int pfl = attrs.privateFlags;
final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
// Compute bounds restricted by insets
final Insets insets = state.calculateInsets(windowBounds, attrs.getFitInsetsTypes(),
attrs.isFitInsetsIgnoringVisibility());
final @WindowInsets.Side.InsetsSide int sides = attrs.getFitInsetsSides();
final int left = (sides & WindowInsets.Side.LEFT) != 0 ? insets.left : 0;
final int top = (sides & WindowInsets.Side.TOP) != 0 ? insets.top : 0;
final int right = (sides & WindowInsets.Side.RIGHT) != 0 ? insets.right : 0;
final int bottom = (sides & WindowInsets.Side.BOTTOM) != 0 ? insets.bottom : 0;
outDisplayFrame.set(windowBounds.left + left, windowBounds.top + top,
windowBounds.right - right, windowBounds.bottom - bottom);
if (attachedWindowFrame == null) {
outParentFrame.set(outDisplayFrame);
if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) {
final InsetsSource source = state.peekSource(ITYPE_IME);
if (source != null) {
outParentFrame.inset(source.calculateInsets(
outParentFrame, false /* ignoreVisibility */));
}
}
} else {
outParentFrame.set(!layoutInScreen ? attachedWindowFrame : outDisplayFrame);
}
// Compute bounds restricted by display cutout
final DisplayCutout cutout = state.getDisplayCutout();
if (cutout.isEmpty()) {
return false;
}
boolean clippedByDisplayCutout = false;
final Rect displayCutoutSafeExceptMaybeBars = mTempDisplayCutoutSafeExceptMaybeBarsRect;
displayCutoutSafeExceptMaybeBars.set(displayCutoutSafe);
// Ensure that windows with a non-ALWAYS display cutout mode are laid out in
// the cutout safe zone.
final int cutoutMode = attrs.layoutInDisplayCutoutMode;
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
final Rect displayFrame = state.getDisplayFrame();
final InsetsSource statusBarSource = state.peekSource(ITYPE_STATUS_BAR);
if (statusBarSource != null && displayCutoutSafe.top > displayFrame.top) {
// Make sure that the zone we're avoiding for the cutout is at least as tall as the
// status bar; otherwise fullscreen apps will end up cutting halfway into the status
// bar.
displayCutoutSafeExceptMaybeBars.top =
Math.max(statusBarSource.getFrame().bottom, displayCutoutSafe.top);
}
if (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
if (displayFrame.width() < displayFrame.height()) {
displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
} else {
displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
}
}
final boolean layoutInsetDecor = (attrs.flags & FLAG_LAYOUT_INSET_DECOR) != 0;
if (layoutInScreen && layoutInsetDecor
&& (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
|| cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)) {
final Insets systemBarsInsets = state.calculateInsets(
displayFrame, WindowInsets.Type.systemBars(), requestedVisibilities);
if (systemBarsInsets.left > 0) {
displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
}
if (systemBarsInsets.top > 0) {
displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
}
if (systemBarsInsets.right > 0) {
displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
}
if (systemBarsInsets.bottom > 0) {
displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
}
}
if (type == TYPE_INPUT_METHOD) {
final InsetsSource navSource = state.peekSource(ITYPE_NAVIGATION_BAR);
if (navSource != null && navSource.calculateInsets(displayFrame, true).bottom > 0) {
// The IME can always extend under the bottom cutout if the navbar is there.
displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
}
}
final boolean attachedInParent = attachedWindowFrame != null && !layoutInScreen;
// TYPE_BASE_APPLICATION windows are never considered floating here because they don't
// get cropped / shifted to the displayFrame in WindowState.
final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
&& type != TYPE_BASE_APPLICATION;
// Windows that are attached to a parent and laid out in said parent already avoid
// the cutout according to that parent and don't need to be further constrained.
// Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
// They will later be cropped or shifted using the displayFrame in WindowState,
// which prevents overlap with the DisplayCutout.
if (!attachedInParent && !floatingInScreenWindow) {
mTempRect.set(outParentFrame);
outParentFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
clippedByDisplayCutout = !mTempRect.equals(outParentFrame);
}
outDisplayFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
}
return clippedByDisplayCutout;
}
}

View File

@@ -84,7 +84,7 @@ public class DisplayFrames {
final Rect safe = mDisplayCutoutSafe;
final DisplayCutout cutout = displayCutout.getDisplayCutout();
if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight
&& state.getDisplayCutout().equals(cutout)
&& state.getDisplayCutout().equals(cutout)
&& state.getRoundedCorners().equals(roundedCorners)
&& state.getPrivacyIndicatorBounds().equals(indicatorBounds)) {
return false;
@@ -93,24 +93,12 @@ public class DisplayFrames {
mDisplayHeight = info.logicalHeight;
final Rect unrestricted = mUnrestricted;
unrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
safe.set(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
state.setDisplayFrame(unrestricted);
state.setDisplayCutout(cutout);
state.setRoundedCorners(roundedCorners);
state.setPrivacyIndicatorBounds(indicatorBounds);
state.getDisplayCutoutSafe(safe);
if (!cutout.isEmpty()) {
if (cutout.getSafeInsetLeft() > 0) {
safe.left = unrestricted.left + cutout.getSafeInsetLeft();
}
if (cutout.getSafeInsetTop() > 0) {
safe.top = unrestricted.top + cutout.getSafeInsetTop();
}
if (cutout.getSafeInsetRight() > 0) {
safe.right = unrestricted.right - cutout.getSafeInsetRight();
}
if (cutout.getSafeInsetBottom() > 0) {
safe.bottom = unrestricted.bottom - cutout.getSafeInsetBottom();
}
state.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(
unrestricted.left, unrestricted.top, safe.left, unrestricted.bottom);
state.getSource(ITYPE_TOP_DISPLAY_CUTOUT).setFrame(

View File

@@ -29,7 +29,6 @@ import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
@@ -37,7 +36,6 @@ import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
import static android.view.ViewRootImpl.INSETS_LAYOUT_GENERALIZATION;
import static android.view.ViewRootImpl.computeWindowBounds;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -50,21 +48,15 @@ import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
@@ -147,6 +139,7 @@ import android.view.View;
import android.view.ViewDebug;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowLayout;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
@@ -356,15 +349,15 @@ public class DisplayPolicy {
// If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
private long mPendingPanicGestureUptime;
private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
private static final Rect sTmpRect = new Rect();
private static final Rect sTmpNavFrame = new Rect();
private static final Rect sTmpStatusFrame = new Rect();
private static final Rect sTmpDecorFrame = new Rect();
private static final Rect sTmpScreenDecorFrame = new Rect();
private static final Rect sTmpLastParentFrame = new Rect();
private static final Rect sTmpDisplayFrameBounds = new Rect();
private final WindowLayout mWindowLayout = new WindowLayout();
private WindowState mTopFullscreenOpaqueWindowState;
private boolean mTopIsFullscreen;
private boolean mForceStatusBar;
@@ -1484,7 +1477,7 @@ public class DisplayPolicy {
* @param outInsetsState The insets state of this display from the client's perspective.
* @param localClient Whether the client is from the our process.
* @return Whether to always consume the system bars.
* See {@link #areSystemBarsForcedShownLw(WindowState)}.
* See {@link #areSystemBarsForcedShownLw()}.
*/
boolean getLayoutHint(LayoutParams attrs, WindowToken windowToken, InsetsState outInsetsState,
boolean localClient) {
@@ -1721,108 +1714,24 @@ public class DisplayPolicy {
final int type = attrs.type;
final int fl = attrs.flags;
final int pfl = attrs.privateFlags;
final int sim = attrs.softInputMode;
displayFrames = win.getDisplayFrames(displayFrames);
final WindowFrames windowFrames = win.getLayoutingWindowFrames();
sTmpLastParentFrame.set(windowFrames.mParentFrame);
final Rect pf = windowFrames.mParentFrame;
final Rect df = windowFrames.mDisplayFrame;
windowFrames.setParentFrameWasClippedByDisplayCutout(false);
final Rect attachedWindowFrame = attached != null ? attached.getFrame() : null;
sTmpLastParentFrame.set(pf);
final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
// Override the bounds in window token has many side effects. Directly use the display
// frame set for the simulated layout for this case.
final Rect winBounds = windowFrames.mIsSimulatingDecorWindow ? df : win.getBounds();
final InsetsState state = win.getInsetsState();
if (windowFrames.mIsSimulatingDecorWindow && INSETS_LAYOUT_GENERALIZATION) {
// Override the bounds in window token has many side effects. Directly use the display
// frame set for the simulated layout for this case.
computeWindowBounds(attrs, state, df, df);
} else {
computeWindowBounds(attrs, state, win.getBounds(), df);
}
if (attached == null) {
pf.set(df);
if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) {
final InsetsSource source = state.peekSource(ITYPE_IME);
if (source != null) {
pf.inset(source.calculateInsets(pf, false /* ignoreVisibility */));
}
}
} else {
pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
}
final int cutoutMode = attrs.layoutInDisplayCutoutMode;
// Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
// the cutout safe zone.
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
final boolean attachedInParent = attached != null && !layoutInScreen;
final boolean requestedFullscreen = !win.getRequestedVisibility(ITYPE_STATUS_BAR);
final boolean requestedHideNavigation =
!win.getRequestedVisibility(ITYPE_NAVIGATION_BAR);
// TYPE_BASE_APPLICATION windows are never considered floating here because they don't
// get cropped / shifted to the displayFrame in WindowState.
final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
&& type != TYPE_BASE_APPLICATION;
final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
if (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
if (displayFrames.mDisplayWidth < displayFrames.mDisplayHeight) {
displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
} else {
displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
}
}
if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
&& (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
|| cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)) {
// At the top we have the status bar, so apps that are
// LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
// already expect that there's an inset there and we don't need to exclude
// the window from that area.
displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
}
if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
&& (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
|| cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)) {
// Same for the navigation bar.
switch (mNavigationBarPosition) {
case NAV_BAR_BOTTOM:
displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
break;
case NAV_BAR_RIGHT:
displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
break;
case NAV_BAR_LEFT:
displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
break;
}
}
if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
// The IME can always extend under the bottom cutout if the navbar is there.
displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
}
// Windows that are attached to a parent and laid out in said parent already avoid
// the cutout according to that parent and don't need to be further constrained.
// Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
// They will later be cropped or shifted using the displayFrame in WindowState,
// which prevents overlap with the DisplayCutout.
if (!attachedInParent && !floatingInScreenWindow) {
sTmpRect.set(pf);
pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
}
// Make sure that NO_LIMITS windows clipped to the display don't extend under the
// cutout.
df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
}
final boolean clippedByDisplayCutout = mWindowLayout.computeWindowFrames(attrs,
win.getInsetsState(), displayFrames.mDisplayCutoutSafe, winBounds,
win.getRequestedVisibilities(), attachedWindowFrame, df, pf);
windowFrames.setParentFrameWasClippedByDisplayCutout(clippedByDisplayCutout);
// TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
// Also, we don't allow windows in multi-window mode to extend out of the screen.
@@ -1843,16 +1752,6 @@ public class DisplayPolicy {
}
win.computeFrameAndUpdateSourceFrame(displayFrames);
if (INSETS_LAYOUT_GENERALIZATION && attrs.type == TYPE_STATUS_BAR) {
if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
// Make sure that the zone we're avoiding for the cutout is at least as tall as the
// status bar; otherwise fullscreen apps will end up cutting halfway into the status
// bar.
displayFrames.mDisplayCutoutSafe.top = Math.max(
displayFrames.mDisplayCutoutSafe.top,
windowFrames.mFrame.bottom);
}
}
}
WindowState getTopFullscreenOpaqueWindow() {