Loading services/core/java/com/android/server/policy/PhoneWindowManager.java +13 −8 Original line number Diff line number Diff line Loading @@ -660,6 +660,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final Rect mTmpStableFrame = new Rect(); static final Rect mTmpNavigationFrame = new Rect(); static final Rect mTmpOutsetFrame = new Rect(); private static final Rect mTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect(); private static final Rect mTmpRect = new Rect(); WindowState mTopFullscreenOpaqueWindowState; Loading Loading @@ -4636,7 +4637,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { w.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, df /* overlayFrame */, df /* contentFrame */, df /* visibleFrame */, dcf /* decorFrame */, df /* stableFrame */, df /* outsetFrame */, displayFrames.mDisplayCutout); df /* stableFrame */, df /* outsetFrame */, displayFrames.mDisplayCutout, false /* parentFrameWasClippedByDisplayCutout */); final Rect frame = w.getFrameLw(); if (frame.left <= 0 && frame.top <= 0) { Loading Loading @@ -4699,7 +4701,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */, dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */, displayFrames.mDisplayCutout); displayFrames.mDisplayCutout, false /* parentFrameWasClippedByDisplayCutout */); // For layout, the status bar is always at the top with our fixed height. displayFrames.mStable.top = displayFrames.mUnrestricted.top Loading Loading @@ -4844,7 +4846,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe, mTmpNavigationFrame, dcf, mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe, displayFrames.mDisplayCutout); displayFrames.mDisplayCutout, false /* parentFrameWasClippedByDisplayCutout */); mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw()); if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); Loading Loading @@ -5299,10 +5301,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { vf.set(cf); } } pf.intersectUnchecked(displayFrames.mDisplayCutoutSafe); } } boolean parentFrameWasClippedByDisplayCutout = false; final int cutoutMode = attrs.layoutInDisplayCutoutMode; final boolean attachedInParent = attached != null && !layoutInScreen; final boolean requestedHideNavigation = Loading @@ -5310,7 +5312,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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 Rect displayCutoutSafeExceptMaybeBars = mTmpRect; final Rect displayCutoutSafeExceptMaybeBars = mTmpDisplayCutoutSafeExceptMaybeBarsRect; displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe); if (layoutInScreen && layoutInsetDecor && !requestedFullscreen && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) { Loading Loading @@ -5339,10 +5341,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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 are already // avoidingthe cutout according to that parent and don't need to be further constrained. // 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. if (!attachedInParent) { mTmpRect.set(pf); pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars); parentFrameWasClippedByDisplayCutout |= !mTmpRect.equals(pf); } // Make sure that NO_LIMITS windows clipped to the display don't extend under the // cutout. Loading Loading @@ -5400,7 +5404,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { + " sf=" + sf.toShortString() + " osf=" + (osf == null ? "null" : osf.toShortString())); win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf, displayFrames.mDisplayCutout); win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf, displayFrames.mDisplayCutout, parentFrameWasClippedByDisplayCutout); // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. Loading services/core/java/com/android/server/policy/WindowManagerPolicy.java +4 −1 Original line number Diff line number Diff line Loading @@ -220,10 +220,13 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * @param outsetFrame The frame that includes areas that aren't part of the surface but we * want to treat them as such. * @param displayCutout the display cutout * @param parentFrameWasClippedByDisplayCutout true if the parent frame would have been * different if there was no display cutout. */ public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, @Nullable Rect outsetFrame, WmDisplayCutout displayCutout); Rect stableFrame, @Nullable Rect outsetFrame, WmDisplayCutout displayCutout, boolean parentFrameWasClippedByDisplayCutout); /** * Retrieve the current frame of the window that has been assigned by Loading services/core/java/com/android/server/wm/WindowState.java +24 −14 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static android.os.PowerManager.DRAW_WAKE_LOCK; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.SurfaceControl.Transaction; import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; Loading @@ -35,7 +34,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCRE import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; Loading @@ -46,7 +44,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; import static android.view.WindowManager.LayoutParams.FORMAT_CHANGED; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER; import static android.view.WindowManager.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; Loading Loading @@ -410,6 +407,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private final Rect mParentFrame = new Rect(); /** Whether the parent frame would have been different if there was no display cutout. */ private boolean mParentFrameWasClippedByDisplayCutout; // The entire screen area of the {@link TaskStack} this window is in. Usually equal to the // screen area of the device. final Rect mDisplayFrame = new Rect(); Loading Loading @@ -839,7 +839,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overscanFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, Rect outsetFrame, WmDisplayCutout displayCutout) { Rect outsetFrame, WmDisplayCutout displayCutout, boolean parentFrameWasClippedByDisplayCutout) { if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) { // This window is being replaced and either already got information that it's being // removed or we are still waiting for some information. Because of this we don't Loading @@ -848,6 +849,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return; } mHaveFrame = true; mParentFrameWasClippedByDisplayCutout = parentFrameWasClippedByDisplayCutout; final Task task = getTask(); final boolean inFullscreenContainer = inFullscreenContainer(); Loading Loading @@ -3055,23 +3057,31 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Only windows with an AppWindowToken are letterboxed. return false; } if (getDisplayContent().getDisplayInfo().displayCutout == null) { // No cutout, no letterbox. if (!mParentFrameWasClippedByDisplayCutout) { // Cutout didn't make a difference, no letterbox return false; } if (mAttrs.layoutInDisplayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) { // Layout in cutout, no letterbox. return false; } // TODO: handle dialogs and other non-filling windows if (mAttrs.layoutInDisplayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER) { // Never layout in cutout, always letterbox. return true; if (!mAttrs.isFullscreen()) { // Not filling the parent frame, no letterbox return false; } // Otherwise we need a letterbox if the layout was smaller than the app window token allowed // it to be. return !frameCoversEntireAppTokenBounds(); } // Letterbox if any fullscreen mode is set. final int fl = mAttrs.flags; final int sysui = mSystemUiVisibility; return (fl & FLAG_FULLSCREEN) != 0 || (sysui & (SYSTEM_UI_FLAG_FULLSCREEN)) != 0; /** * @return true if this window covers the entire bounds of its app window token * @throws NullPointerException if there is no app window token for this window */ private boolean frameCoversEntireAppTokenBounds() { mTmpRect.set(mAppToken.getBounds()); mTmpRect.intersectUnchecked(mFrame); return mAppToken.getBounds().equals(mTmpRect); } @Override Loading services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java +2 −1 Original line number Diff line number Diff line Loading @@ -63,7 +63,8 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState { @Override public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, @Nullable Rect outsetFrame, WmDisplayCutout displayCutout) { @Nullable Rect outsetFrame, WmDisplayCutout displayCutout, boolean parentFrameWasClippedByDisplayCutout) { this.parentFrame.set(parentFrame); this.displayFrame.set(displayFrame); this.overscanFrame.set(overlayFrame); Loading services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java +20 −20 Original line number Diff line number Diff line Loading @@ -160,7 +160,7 @@ public class WindowFrameTests extends WindowTestsBase { // When mFrame extends past cf, the content insets are // the difference between mFrame and ContentFrame. Visible // and stable frames work the same way. w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame,0, 0, 1000, 1000); assertRect(w.mContentInsets, 0, topContentInset, 0, bottomContentInset); assertRect(w.mVisibleInsets, 0, topVisibleInset, 0, bottomVisibleInset); Loading @@ -175,7 +175,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT w.mRequestedWidth = 100; w.mRequestedHeight = 100; w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 100, 100, 200, 200); assertRect(w.mContentInsets, 0, 0, 0, 0); // In this case the frames are shrunk to the window frame. Loading @@ -196,7 +196,7 @@ public class WindowFrameTests extends WindowTestsBase { // Here the window has FILL_PARENT, FILL_PARENT // so we expect it to fill the entire available frame. w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 1000, 1000); // It can select various widths and heights within the bounds. Loading @@ -204,14 +204,14 @@ public class WindowFrameTests extends WindowTestsBase { // and we use mRequestedWidth/mRequestedHeight w.mAttrs.width = 300; w.mAttrs.height = 300; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); // Explicit width and height without requested width/height // gets us nothing. assertRect(w.mFrame, 0, 0, 0, 0); w.mRequestedWidth = 300; w.mRequestedHeight = 300; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); // With requestedWidth/Height we can freely choose our size within the // parent bounds. assertRect(w.mFrame, 0, 0, 300, 300); Loading @@ -224,14 +224,14 @@ public class WindowFrameTests extends WindowTestsBase { w.mRequestedWidth = -1; w.mAttrs.width = 100; w.mAttrs.height = 100; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 100, 100); w.mAttrs.flags = 0; // But sizes too large will be clipped to the containing frame w.mRequestedWidth = 1200; w.mRequestedHeight = 1200; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 1000, 1000); // Before they are clipped though windows will be shifted Loading @@ -239,7 +239,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.y = 300; w.mRequestedWidth = 1000; w.mRequestedHeight = 1000; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 1000, 1000); // If there is room to move around in the parent frame the window will be shifted according Loading @@ -249,16 +249,16 @@ public class WindowFrameTests extends WindowTestsBase { w.mRequestedWidth = 300; w.mRequestedHeight = 300; w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 700, 0, 1000, 300); w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 700, 700, 1000, 1000); // Window specified x and y are interpreted as offsets in the opposite // direction of gravity w.mAttrs.x = 100; w.mAttrs.y = 100; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 600, 600, 900, 900); } Loading @@ -279,7 +279,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null, WmDisplayCutout.NO_CUTOUT, false); // For non fullscreen tasks the containing frame is based off the // task bounds not the parent frame. assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); Loading @@ -291,7 +291,7 @@ public class WindowFrameTests extends WindowTestsBase { final int cfRight = logicalWidth / 2; final int cfBottom = logicalHeight / 2; final Rect cf = new Rect(0, 0, cfRight, cfBottom); w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); int contentInsetRight = taskRight - cfRight; int contentInsetBottom = taskBottom - cfBottom; Loading @@ -308,7 +308,7 @@ public class WindowFrameTests extends WindowTestsBase { final int insetRight = insetLeft + (taskRight - taskLeft); final int insetBottom = insetTop + (taskBottom - taskTop); task.mInsetBounds.set(insetLeft, insetTop, insetRight, insetBottom); w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); contentInsetRight = insetRight - cfRight; contentInsetBottom = insetBottom - cfBottom; Loading Loading @@ -340,13 +340,13 @@ public class WindowFrameTests extends WindowTestsBase { final Rect policyCrop = new Rect(); w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); w.calculatePolicyCrop(policyCrop); assertRect(policyCrop, 0, cf.top, logicalWidth, cf.bottom); dcf.setEmpty(); // Likewise with no decor frame we would get no crop w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); w.calculatePolicyCrop(policyCrop); assertRect(policyCrop, 0, 0, logicalWidth, logicalHeight); Loading @@ -359,7 +359,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.height = logicalHeight / 2; w.mRequestedWidth = logicalWidth / 2; w.mRequestedHeight = logicalHeight / 2; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); w.calculatePolicyCrop(policyCrop); // Normally the crop is shrunk from the decor frame Loading Loading @@ -396,7 +396,7 @@ public class WindowFrameTests extends WindowTestsBase { final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */, pf /* contentFrame */, pf /* visibleFrame */, pf /* decorFrame */, pf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT); pf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT, false); // For non fullscreen tasks the containing frame is based off the // task bounds not the parent frame. assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); Loading @@ -415,7 +415,7 @@ public class WindowFrameTests extends WindowTestsBase { w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */, cf /* contentFrame */, cf /* visibleFrame */, pf /* decorFrame */, cf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT); cf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT, false); assertEquals(cf, w.mFrame); assertEquals(cf, w.getContentFrameLw()); assertRect(w.mContentInsets, 0, 0, 0, 0); Loading @@ -433,7 +433,7 @@ public class WindowFrameTests extends WindowTestsBase { final WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( fromBoundingRect(500, 0, 550, 50), pf.width(), pf.height()); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, cutout); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, cutout, false); assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetTop(), 50); assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetBottom(), 0); Loading Loading
services/core/java/com/android/server/policy/PhoneWindowManager.java +13 −8 Original line number Diff line number Diff line Loading @@ -660,6 +660,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final Rect mTmpStableFrame = new Rect(); static final Rect mTmpNavigationFrame = new Rect(); static final Rect mTmpOutsetFrame = new Rect(); private static final Rect mTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect(); private static final Rect mTmpRect = new Rect(); WindowState mTopFullscreenOpaqueWindowState; Loading Loading @@ -4636,7 +4637,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { w.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, df /* overlayFrame */, df /* contentFrame */, df /* visibleFrame */, dcf /* decorFrame */, df /* stableFrame */, df /* outsetFrame */, displayFrames.mDisplayCutout); df /* stableFrame */, df /* outsetFrame */, displayFrames.mDisplayCutout, false /* parentFrameWasClippedByDisplayCutout */); final Rect frame = w.getFrameLw(); if (frame.left <= 0 && frame.top <= 0) { Loading Loading @@ -4699,7 +4701,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */, dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */, displayFrames.mDisplayCutout); displayFrames.mDisplayCutout, false /* parentFrameWasClippedByDisplayCutout */); // For layout, the status bar is always at the top with our fixed height. displayFrames.mStable.top = displayFrames.mUnrestricted.top Loading Loading @@ -4844,7 +4846,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe, mTmpNavigationFrame, dcf, mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe, displayFrames.mDisplayCutout); displayFrames.mDisplayCutout, false /* parentFrameWasClippedByDisplayCutout */); mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw()); if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); Loading Loading @@ -5299,10 +5301,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { vf.set(cf); } } pf.intersectUnchecked(displayFrames.mDisplayCutoutSafe); } } boolean parentFrameWasClippedByDisplayCutout = false; final int cutoutMode = attrs.layoutInDisplayCutoutMode; final boolean attachedInParent = attached != null && !layoutInScreen; final boolean requestedHideNavigation = Loading @@ -5310,7 +5312,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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 Rect displayCutoutSafeExceptMaybeBars = mTmpRect; final Rect displayCutoutSafeExceptMaybeBars = mTmpDisplayCutoutSafeExceptMaybeBarsRect; displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe); if (layoutInScreen && layoutInsetDecor && !requestedFullscreen && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) { Loading Loading @@ -5339,10 +5341,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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 are already // avoidingthe cutout according to that parent and don't need to be further constrained. // 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. if (!attachedInParent) { mTmpRect.set(pf); pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars); parentFrameWasClippedByDisplayCutout |= !mTmpRect.equals(pf); } // Make sure that NO_LIMITS windows clipped to the display don't extend under the // cutout. Loading Loading @@ -5400,7 +5404,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { + " sf=" + sf.toShortString() + " osf=" + (osf == null ? "null" : osf.toShortString())); win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf, displayFrames.mDisplayCutout); win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf, displayFrames.mDisplayCutout, parentFrameWasClippedByDisplayCutout); // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. Loading
services/core/java/com/android/server/policy/WindowManagerPolicy.java +4 −1 Original line number Diff line number Diff line Loading @@ -220,10 +220,13 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * @param outsetFrame The frame that includes areas that aren't part of the surface but we * want to treat them as such. * @param displayCutout the display cutout * @param parentFrameWasClippedByDisplayCutout true if the parent frame would have been * different if there was no display cutout. */ public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, @Nullable Rect outsetFrame, WmDisplayCutout displayCutout); Rect stableFrame, @Nullable Rect outsetFrame, WmDisplayCutout displayCutout, boolean parentFrameWasClippedByDisplayCutout); /** * Retrieve the current frame of the window that has been assigned by Loading
services/core/java/com/android/server/wm/WindowState.java +24 −14 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static android.os.PowerManager.DRAW_WAKE_LOCK; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.SurfaceControl.Transaction; import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; Loading @@ -35,7 +34,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCRE import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; Loading @@ -46,7 +44,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; import static android.view.WindowManager.LayoutParams.FORMAT_CHANGED; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER; import static android.view.WindowManager.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; Loading Loading @@ -410,6 +407,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private final Rect mParentFrame = new Rect(); /** Whether the parent frame would have been different if there was no display cutout. */ private boolean mParentFrameWasClippedByDisplayCutout; // The entire screen area of the {@link TaskStack} this window is in. Usually equal to the // screen area of the device. final Rect mDisplayFrame = new Rect(); Loading Loading @@ -839,7 +839,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overscanFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, Rect outsetFrame, WmDisplayCutout displayCutout) { Rect outsetFrame, WmDisplayCutout displayCutout, boolean parentFrameWasClippedByDisplayCutout) { if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) { // This window is being replaced and either already got information that it's being // removed or we are still waiting for some information. Because of this we don't Loading @@ -848,6 +849,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return; } mHaveFrame = true; mParentFrameWasClippedByDisplayCutout = parentFrameWasClippedByDisplayCutout; final Task task = getTask(); final boolean inFullscreenContainer = inFullscreenContainer(); Loading Loading @@ -3055,23 +3057,31 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Only windows with an AppWindowToken are letterboxed. return false; } if (getDisplayContent().getDisplayInfo().displayCutout == null) { // No cutout, no letterbox. if (!mParentFrameWasClippedByDisplayCutout) { // Cutout didn't make a difference, no letterbox return false; } if (mAttrs.layoutInDisplayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) { // Layout in cutout, no letterbox. return false; } // TODO: handle dialogs and other non-filling windows if (mAttrs.layoutInDisplayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER) { // Never layout in cutout, always letterbox. return true; if (!mAttrs.isFullscreen()) { // Not filling the parent frame, no letterbox return false; } // Otherwise we need a letterbox if the layout was smaller than the app window token allowed // it to be. return !frameCoversEntireAppTokenBounds(); } // Letterbox if any fullscreen mode is set. final int fl = mAttrs.flags; final int sysui = mSystemUiVisibility; return (fl & FLAG_FULLSCREEN) != 0 || (sysui & (SYSTEM_UI_FLAG_FULLSCREEN)) != 0; /** * @return true if this window covers the entire bounds of its app window token * @throws NullPointerException if there is no app window token for this window */ private boolean frameCoversEntireAppTokenBounds() { mTmpRect.set(mAppToken.getBounds()); mTmpRect.intersectUnchecked(mFrame); return mAppToken.getBounds().equals(mTmpRect); } @Override Loading
services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java +2 −1 Original line number Diff line number Diff line Loading @@ -63,7 +63,8 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState { @Override public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame, @Nullable Rect outsetFrame, WmDisplayCutout displayCutout) { @Nullable Rect outsetFrame, WmDisplayCutout displayCutout, boolean parentFrameWasClippedByDisplayCutout) { this.parentFrame.set(parentFrame); this.displayFrame.set(displayFrame); this.overscanFrame.set(overlayFrame); Loading
services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java +20 −20 Original line number Diff line number Diff line Loading @@ -160,7 +160,7 @@ public class WindowFrameTests extends WindowTestsBase { // When mFrame extends past cf, the content insets are // the difference between mFrame and ContentFrame. Visible // and stable frames work the same way. w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame,0, 0, 1000, 1000); assertRect(w.mContentInsets, 0, topContentInset, 0, bottomContentInset); assertRect(w.mVisibleInsets, 0, topVisibleInset, 0, bottomVisibleInset); Loading @@ -175,7 +175,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT w.mRequestedWidth = 100; w.mRequestedHeight = 100; w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 100, 100, 200, 200); assertRect(w.mContentInsets, 0, 0, 0, 0); // In this case the frames are shrunk to the window frame. Loading @@ -196,7 +196,7 @@ public class WindowFrameTests extends WindowTestsBase { // Here the window has FILL_PARENT, FILL_PARENT // so we expect it to fill the entire available frame. w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 1000, 1000); // It can select various widths and heights within the bounds. Loading @@ -204,14 +204,14 @@ public class WindowFrameTests extends WindowTestsBase { // and we use mRequestedWidth/mRequestedHeight w.mAttrs.width = 300; w.mAttrs.height = 300; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); // Explicit width and height without requested width/height // gets us nothing. assertRect(w.mFrame, 0, 0, 0, 0); w.mRequestedWidth = 300; w.mRequestedHeight = 300; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); // With requestedWidth/Height we can freely choose our size within the // parent bounds. assertRect(w.mFrame, 0, 0, 300, 300); Loading @@ -224,14 +224,14 @@ public class WindowFrameTests extends WindowTestsBase { w.mRequestedWidth = -1; w.mAttrs.width = 100; w.mAttrs.height = 100; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 100, 100); w.mAttrs.flags = 0; // But sizes too large will be clipped to the containing frame w.mRequestedWidth = 1200; w.mRequestedHeight = 1200; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 1000, 1000); // Before they are clipped though windows will be shifted Loading @@ -239,7 +239,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.y = 300; w.mRequestedWidth = 1000; w.mRequestedHeight = 1000; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 0, 0, 1000, 1000); // If there is room to move around in the parent frame the window will be shifted according Loading @@ -249,16 +249,16 @@ public class WindowFrameTests extends WindowTestsBase { w.mRequestedWidth = 300; w.mRequestedHeight = 300; w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 700, 0, 1000, 300); w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 700, 700, 1000, 1000); // Window specified x and y are interpreted as offsets in the opposite // direction of gravity w.mAttrs.x = 100; w.mAttrs.y = 100; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, 600, 600, 900, 900); } Loading @@ -279,7 +279,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null, WmDisplayCutout.NO_CUTOUT, false); // For non fullscreen tasks the containing frame is based off the // task bounds not the parent frame. assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); Loading @@ -291,7 +291,7 @@ public class WindowFrameTests extends WindowTestsBase { final int cfRight = logicalWidth / 2; final int cfBottom = logicalHeight / 2; final Rect cf = new Rect(0, 0, cfRight, cfBottom); w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); int contentInsetRight = taskRight - cfRight; int contentInsetBottom = taskBottom - cfBottom; Loading @@ -308,7 +308,7 @@ public class WindowFrameTests extends WindowTestsBase { final int insetRight = insetLeft + (taskRight - taskLeft); final int insetBottom = insetTop + (taskBottom - taskTop); task.mInsetBounds.set(insetLeft, insetTop, insetRight, insetBottom); w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null, WmDisplayCutout.NO_CUTOUT, false); assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); contentInsetRight = insetRight - cfRight; contentInsetBottom = insetBottom - cfBottom; Loading Loading @@ -340,13 +340,13 @@ public class WindowFrameTests extends WindowTestsBase { final Rect policyCrop = new Rect(); w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); w.calculatePolicyCrop(policyCrop); assertRect(policyCrop, 0, cf.top, logicalWidth, cf.bottom); dcf.setEmpty(); // Likewise with no decor frame we would get no crop w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null, WmDisplayCutout.NO_CUTOUT, false); w.calculatePolicyCrop(policyCrop); assertRect(policyCrop, 0, 0, logicalWidth, logicalHeight); Loading @@ -359,7 +359,7 @@ public class WindowFrameTests extends WindowTestsBase { w.mAttrs.height = logicalHeight / 2; w.mRequestedWidth = logicalWidth / 2; w.mRequestedHeight = logicalHeight / 2; w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, WmDisplayCutout.NO_CUTOUT, false); w.calculatePolicyCrop(policyCrop); // Normally the crop is shrunk from the decor frame Loading Loading @@ -396,7 +396,7 @@ public class WindowFrameTests extends WindowTestsBase { final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight); w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */, pf /* contentFrame */, pf /* visibleFrame */, pf /* decorFrame */, pf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT); pf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT, false); // For non fullscreen tasks the containing frame is based off the // task bounds not the parent frame. assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom); Loading @@ -415,7 +415,7 @@ public class WindowFrameTests extends WindowTestsBase { w.computeFrameLw(pf /* parentFrame */, pf /* displayFrame */, pf /* overscanFrame */, cf /* contentFrame */, cf /* visibleFrame */, pf /* decorFrame */, cf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT); cf /* stableFrame */, null /* outsetFrame */, WmDisplayCutout.NO_CUTOUT, false); assertEquals(cf, w.mFrame); assertEquals(cf, w.getContentFrameLw()); assertRect(w.mContentInsets, 0, 0, 0, 0); Loading @@ -433,7 +433,7 @@ public class WindowFrameTests extends WindowTestsBase { final WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets( fromBoundingRect(500, 0, 550, 50), pf.width(), pf.height()); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, cutout); w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf, cutout, false); assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetTop(), 50); assertEquals(w.mDisplayCutout.getDisplayCutout().getSafeInsetBottom(), 0); Loading