Loading core/java/android/view/ViewRootImpl.java +21 −2 Original line number Diff line number Diff line Loading @@ -57,12 +57,15 @@ import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; import static android.view.WindowLayout.UNSPECIFIED_LENGTH; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 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_SHORT_EDGES; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED; Loading @@ -72,6 +75,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_V import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; Loading @@ -90,6 +94,7 @@ import android.annotation.UiContext; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ResourcesManager; import android.app.WindowConfiguration; import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipDescription; Loading Loading @@ -515,6 +520,8 @@ public final class ViewRootImpl implements ViewParent, private final WindowLayout mWindowLayout = new WindowLayout(); private ViewRootImpl mParentViewRoot; // 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. @GuardedBy("this") Loading Loading @@ -1053,6 +1060,7 @@ public final class ViewRootImpl implements ViewParent, if (panelParentView != null) { mAttachInfo.mPanelParentWindowToken = panelParentView.getApplicationWindowToken(); mParentViewRoot = panelParentView.getViewRootImpl(); } mAdded = true; int res; /* = WindowManagerImpl.ADD_OKAY; */ Loading Loading @@ -1113,10 +1121,13 @@ public final class ViewRootImpl implements ViewParent, final InsetsState state = mInsetsController.getState(); final Rect displayCutoutSafe = mTempRect; state.getDisplayCutoutSafe(displayCutoutSafe); final WindowConfiguration winConfig = getConfiguration().windowConfiguration; mWindowLayout.computeWindowFrames(mWindowAttributes, state, displayCutoutSafe, getConfiguration().windowConfiguration.getBounds(), displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(), UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH, mInsetsController.getRequestedVisibilities(), null /* attachedWindowFrame */, mTmpFrames.frame, mTempRect2); getAttachedWindowFrame(), 1f /* compactScale */, mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame); setFrame(mTmpFrames.frame); if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow); if (res < WindowManagerGlobal.ADD_OKAY) { Loading Loading @@ -1227,6 +1238,14 @@ public final class ViewRootImpl implements ViewParent, } } private Rect getAttachedWindowFrame() { final int type = mWindowAttributes.type; final boolean layoutAttached = (mParentViewRoot != null && type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW && type != TYPE_APPLICATION_ATTACHED_DIALOG); return layoutAttached ? mParentViewRoot.mWinFrame : null; } /** * Register any kind of listeners if setView was success. */ Loading core/java/android/view/WindowLayout.java +134 −11 Original line number Diff line number Diff line Loading @@ -19,29 +19,44 @@ 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.ViewGroup.LayoutParams.MATCH_PARENT; 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_SCALED; 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.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; 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_SYSTEM_ERROR; import android.app.WindowConfiguration; import android.app.WindowConfiguration.WindowingMode; import android.graphics.Insets; import android.graphics.Rect; import android.util.Log; /** * Computes window frames. * @hide */ public class WindowLayout { private static final String TAG = WindowLayout.class.getSimpleName(); private static final boolean DEBUG = false; public static final int UNSPECIFIED_LENGTH = -1; 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) { Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode, int requestedWidth, int requestedHeight, InsetsVisibilities requestedVisibilities, Rect attachedWindowFrame, float compatScale, Rect outDisplayFrame, Rect outParentFrame, Rect outFrame) { final int type = attrs.type; final int fl = attrs.flags; final int pfl = attrs.privateFlags; Loading Loading @@ -72,18 +87,14 @@ public class WindowLayout { } // Compute bounds restricted by display cutout final int cutoutMode = attrs.layoutInDisplayCutoutMode; final DisplayCutout cutout = state.getDisplayCutout(); if (cutout.isEmpty()) { return false; } boolean clippedByDisplayCutout = false; final Rect displayCutoutSafeExceptMaybeBars = mTempDisplayCutoutSafeExceptMaybeBarsRect; displayCutoutSafeExceptMaybeBars.set(displayCutoutSafe); boolean clippedByDisplayCutout = false; if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !cutout.isEmpty()) { // 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) { Loading Loading @@ -147,6 +158,118 @@ public class WindowLayout { } outDisplayFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars); } final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0; final boolean inMultiWindowMode = WindowConfiguration.inMultiWindowMode(windowingMode); // 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. if (noLimits && type != TYPE_SYSTEM_ERROR && !inMultiWindowMode) { outDisplayFrame.left = outDisplayFrame.top = -10000; outDisplayFrame.right = outDisplayFrame.bottom = 10000; } final boolean hasCompatScale = compatScale != 1f; final int pw = outParentFrame.width(); final int ph = outParentFrame.height(); int rw = requestedWidth; int rh = requestedHeight; float x, y; int w, h; // If the view hierarchy hasn't been measured, the requested width and height would be // UNSPECIFIED_LENGTH. This can happen in the first layout of a window or in the simulated // layout. if (rw == UNSPECIFIED_LENGTH) { rw = attrs.width >= 0 ? attrs.width : pw; } if (rh == UNSPECIFIED_LENGTH) { rh = attrs.height >= 0 ? attrs.height : ph; } if ((attrs.flags & FLAG_SCALED) != 0) { if (attrs.width < 0) { w = pw; } else if (hasCompatScale) { w = (int) (attrs.width * compatScale + .5f); } else { w = attrs.width; } if (attrs.height < 0) { h = ph; } else if (hasCompatScale) { h = (int) (attrs.height * compatScale + .5f); } else { h = attrs.height; } } else { if (attrs.width == MATCH_PARENT) { w = pw; } else if (hasCompatScale) { w = (int) (rw * compatScale + .5f); } else { w = rw; } if (attrs.height == MATCH_PARENT) { h = ph; } else if (hasCompatScale) { h = (int) (rh * compatScale + .5f); } else { h = rh; } } if (hasCompatScale) { x = attrs.x * compatScale; y = attrs.y * compatScale; } else { x = attrs.x; y = attrs.y; } if (inMultiWindowMode && (attrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) == 0) { // Make sure window fits in parent frame since it is in a non-fullscreen task as // required by {@link Gravity#apply} call. w = Math.min(w, pw); h = Math.min(h, ph); } // We need to fit it to the display if either // a) The window is in a fullscreen container, or we don't have a task (we assume fullscreen // for the taskless windows) // b) If it's a secondary app window, we also need to fit it to the display unless // FLAG_LAYOUT_NO_LIMITS is set. This is so we place Popups, dialogs, and similar windows on // screen, but SurfaceViews want to be always at a specific location so we don't fit it to // the display. final boolean fitToDisplay = !inMultiWindowMode || ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits); // Set mFrame Gravity.apply(attrs.gravity, w, h, outParentFrame, (int) (x + attrs.horizontalMargin * pw), (int) (y + attrs.verticalMargin * ph), outFrame); // Now make sure the window fits in the overall display frame. if (fitToDisplay) { Gravity.applyDisplay(attrs.gravity, outDisplayFrame, outFrame); } if (DEBUG) Log.d(TAG, "computeWindowFrames " + attrs.getTitle() + " outFrame=" + outFrame.toShortString() + " outParentFrame=" + outParentFrame.toShortString() + " outDisplayFrame=" + outDisplayFrame.toShortString() + " attachedWindowFrame=" + (attachedWindowFrame != null ? attachedWindowFrame.toShortString() : "null") + " requestedWidth=" + requestedWidth + " requestedHeight=" + requestedHeight + " compatScale=" + compatScale + " windowingMode=" + WindowConfiguration.windowingModeToString(windowingMode) + " displayCutoutSafe=" + displayCutoutSafe + " attrs=" + attrs + " state=" + state + " requestedVisibilities=" + requestedVisibilities); return clippedByDisplayCutout; } } core/proto/android/server/windowmanagerservice.proto +1 −1 Original line number Diff line number Diff line Loading @@ -527,7 +527,7 @@ message ConfigurationContainerProto { message WindowFramesProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; optional .android.graphics.RectProto containing_frame = 1; optional .android.graphics.RectProto containing_frame = 1 [deprecated=true]; optional .android.graphics.RectProto content_frame = 2 [deprecated=true]; optional .android.graphics.RectProto decor_frame = 3 [deprecated=true]; optional .android.graphics.RectProto display_frame = 4; Loading services/core/java/com/android/server/wm/DisplayContent.java +28 −25 Original line number Diff line number Diff line Loading @@ -802,13 +802,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp }; private final Consumer<WindowState> mPerformLayout = w -> { if (w.mLayoutAttached || w.skipLayout()) { return; } // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid // wasting time and funky changes while a window is animating away. final boolean gone = w.isGoneForLayout(); if (DEBUG_LAYOUT && !w.mLayoutAttached) { if (DEBUG_LAYOUT) { Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame + " mLayoutAttached=" + w.mLayoutAttached + " config reported=" + w.isLastConfigReportedToClient()); final ActivityRecord activity = w.mActivityRecord; if (gone) Slog.v(TAG, " GONE: mViewVisibility=" + w.mViewVisibility Loading @@ -824,7 +827,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // If this view is GONE, then skip it -- keep the current frame, and let the caller know // so they can ignore it if they want. (We do the normal layout for INVISIBLE windows, // since that means "perform layout as normal, just don't display"). if ((!gone || !w.mHaveFrame || w.mLayoutNeeded) && !w.mLayoutAttached) { if (!gone || !w.mHaveFrame || w.mLayoutNeeded) { if (mTmpInitial) { w.resetContentChanged(); } Loading @@ -851,13 +854,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame() + " mContainingFrame=" + w.getContainingFrame() + " mParentFrame=" + w.getParentFrame() + " mDisplayFrame=" + w.getDisplayFrame()); } }; private final Consumer<WindowState> mPerformLayoutAttached = w -> { if (w.mLayoutAttached) { if (!w.mLayoutAttached || w.skipLayout()) { return; } if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame + " mViewVisibility=" + w.mViewVisibility + " mRelayoutCalled=" + w.mRelayoutCalled); Loading @@ -867,7 +872,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if ((w.mViewVisibility != GONE && w.mRelayoutCalled) || !w.mHaveFrame || w.mLayoutNeeded) { if (mTmpInitial) { //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); w.resetContentChanged(); } w.mSurfacePlacementNeeded = true; Loading @@ -876,10 +880,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames); w.mLayoutSeq = mLayoutSeq; if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame() + " mContainingFrame=" + w.getContainingFrame() + " mParentFrame=" + w.getParentFrame() + " mDisplayFrame=" + w.getDisplayFrame()); } } }; private final Predicate<WindowState> mComputeImeTargetPredicate = w -> { Loading services/core/java/com/android/server/wm/DisplayPolicy.java +30 −22 Original line number Diff line number Diff line Loading @@ -43,12 +43,12 @@ import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_B import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; import static android.view.WindowLayout.UNSPECIFIED_LENGTH; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 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_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; Loading @@ -65,7 +65,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; Loading Loading @@ -1719,10 +1718,6 @@ public class DisplayPolicy { layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR)); return; } if (win.mActivityRecord != null && win.mActivityRecord.mWaitForEnteringPinnedMode) { // Skip layout of the window when in transition to pip mode. return; } final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation); final int type = attrs.type; Loading @@ -1734,37 +1729,50 @@ public class DisplayPolicy { final Rect pf = windowFrames.mParentFrame; final Rect df = windowFrames.mDisplayFrame; final Rect f = windowFrames.mFrame; final Rect attachedWindowFrame = attached != null ? attached.getFrame() : null; sTmpLastParentFrame.set(pf); final Rect winBounds; final int requestedWidth; final int requestedHeight; if (windowFrames.mIsSimulatingDecorWindow) { // 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(); // frame set for the simulated layout. winBounds = df; // The view hierarchy has not been measured in the simulated layout. Use // UNSPECIFIED_LENGTH as the requested width and height so that WindowLayout will choose // the proper values in this case. requestedWidth = UNSPECIFIED_LENGTH; requestedHeight = UNSPECIFIED_LENGTH; } else { winBounds = win.getBounds(); requestedWidth = win.mRequestedWidth; requestedHeight = win.mRequestedHeight; } final boolean clippedByDisplayCutout = mWindowLayout.computeWindowFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe, winBounds, win.getRequestedVisibilities(), attachedWindowFrame, df, pf); win.getInsetsState(), displayFrames.mDisplayCutoutSafe, winBounds, win.getWindowingMode(), requestedWidth, requestedHeight, win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale, df, pf, f); 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. if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR && !win.inMultiWindowMode()) { df.left = df.top = -10000; df.right = df.bottom = 10000; } if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle() + ": sim=#" + Integer.toHexString(sim) + " attach=" + attached + " type=" + type + String.format(" flags=0x%08x", fl) + " pf=" + pf.toShortString() + " df=" + df.toShortString()); + " flags=" + ViewDebug.flagsToString(LayoutParams.class, "flags", fl) + " pf=" + pf.toShortString() + " df=" + df.toShortString() + " f=" + f.toShortString()); if (!sTmpLastParentFrame.equals(pf)) { windowFrames.setContentChanged(true); } win.computeFrameAndUpdateSourceFrame(displayFrames); if (!windowFrames.mIsSimulatingDecorWindow) { win.setFrame(); } } WindowState getTopFullscreenOpaqueWindow() { Loading Loading
core/java/android/view/ViewRootImpl.java +21 −2 Original line number Diff line number Diff line Loading @@ -57,12 +57,15 @@ import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; import static android.view.WindowLayout.UNSPECIFIED_LENGTH; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 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_SHORT_EDGES; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED; Loading @@ -72,6 +75,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_V import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; Loading @@ -90,6 +94,7 @@ import android.annotation.UiContext; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ResourcesManager; import android.app.WindowConfiguration; import android.compat.annotation.UnsupportedAppUsage; import android.content.ClipData; import android.content.ClipDescription; Loading Loading @@ -515,6 +520,8 @@ public final class ViewRootImpl implements ViewParent, private final WindowLayout mWindowLayout = new WindowLayout(); private ViewRootImpl mParentViewRoot; // 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. @GuardedBy("this") Loading Loading @@ -1053,6 +1060,7 @@ public final class ViewRootImpl implements ViewParent, if (panelParentView != null) { mAttachInfo.mPanelParentWindowToken = panelParentView.getApplicationWindowToken(); mParentViewRoot = panelParentView.getViewRootImpl(); } mAdded = true; int res; /* = WindowManagerImpl.ADD_OKAY; */ Loading Loading @@ -1113,10 +1121,13 @@ public final class ViewRootImpl implements ViewParent, final InsetsState state = mInsetsController.getState(); final Rect displayCutoutSafe = mTempRect; state.getDisplayCutoutSafe(displayCutoutSafe); final WindowConfiguration winConfig = getConfiguration().windowConfiguration; mWindowLayout.computeWindowFrames(mWindowAttributes, state, displayCutoutSafe, getConfiguration().windowConfiguration.getBounds(), displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(), UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH, mInsetsController.getRequestedVisibilities(), null /* attachedWindowFrame */, mTmpFrames.frame, mTempRect2); getAttachedWindowFrame(), 1f /* compactScale */, mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame); setFrame(mTmpFrames.frame); if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow); if (res < WindowManagerGlobal.ADD_OKAY) { Loading Loading @@ -1227,6 +1238,14 @@ public final class ViewRootImpl implements ViewParent, } } private Rect getAttachedWindowFrame() { final int type = mWindowAttributes.type; final boolean layoutAttached = (mParentViewRoot != null && type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW && type != TYPE_APPLICATION_ATTACHED_DIALOG); return layoutAttached ? mParentViewRoot.mWinFrame : null; } /** * Register any kind of listeners if setView was success. */ Loading
core/java/android/view/WindowLayout.java +134 −11 Original line number Diff line number Diff line Loading @@ -19,29 +19,44 @@ 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.ViewGroup.LayoutParams.MATCH_PARENT; 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_SCALED; 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.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME; 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_SYSTEM_ERROR; import android.app.WindowConfiguration; import android.app.WindowConfiguration.WindowingMode; import android.graphics.Insets; import android.graphics.Rect; import android.util.Log; /** * Computes window frames. * @hide */ public class WindowLayout { private static final String TAG = WindowLayout.class.getSimpleName(); private static final boolean DEBUG = false; public static final int UNSPECIFIED_LENGTH = -1; 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) { Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode, int requestedWidth, int requestedHeight, InsetsVisibilities requestedVisibilities, Rect attachedWindowFrame, float compatScale, Rect outDisplayFrame, Rect outParentFrame, Rect outFrame) { final int type = attrs.type; final int fl = attrs.flags; final int pfl = attrs.privateFlags; Loading Loading @@ -72,18 +87,14 @@ public class WindowLayout { } // Compute bounds restricted by display cutout final int cutoutMode = attrs.layoutInDisplayCutoutMode; final DisplayCutout cutout = state.getDisplayCutout(); if (cutout.isEmpty()) { return false; } boolean clippedByDisplayCutout = false; final Rect displayCutoutSafeExceptMaybeBars = mTempDisplayCutoutSafeExceptMaybeBarsRect; displayCutoutSafeExceptMaybeBars.set(displayCutoutSafe); boolean clippedByDisplayCutout = false; if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !cutout.isEmpty()) { // 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) { Loading Loading @@ -147,6 +158,118 @@ public class WindowLayout { } outDisplayFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars); } final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0; final boolean inMultiWindowMode = WindowConfiguration.inMultiWindowMode(windowingMode); // 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. if (noLimits && type != TYPE_SYSTEM_ERROR && !inMultiWindowMode) { outDisplayFrame.left = outDisplayFrame.top = -10000; outDisplayFrame.right = outDisplayFrame.bottom = 10000; } final boolean hasCompatScale = compatScale != 1f; final int pw = outParentFrame.width(); final int ph = outParentFrame.height(); int rw = requestedWidth; int rh = requestedHeight; float x, y; int w, h; // If the view hierarchy hasn't been measured, the requested width and height would be // UNSPECIFIED_LENGTH. This can happen in the first layout of a window or in the simulated // layout. if (rw == UNSPECIFIED_LENGTH) { rw = attrs.width >= 0 ? attrs.width : pw; } if (rh == UNSPECIFIED_LENGTH) { rh = attrs.height >= 0 ? attrs.height : ph; } if ((attrs.flags & FLAG_SCALED) != 0) { if (attrs.width < 0) { w = pw; } else if (hasCompatScale) { w = (int) (attrs.width * compatScale + .5f); } else { w = attrs.width; } if (attrs.height < 0) { h = ph; } else if (hasCompatScale) { h = (int) (attrs.height * compatScale + .5f); } else { h = attrs.height; } } else { if (attrs.width == MATCH_PARENT) { w = pw; } else if (hasCompatScale) { w = (int) (rw * compatScale + .5f); } else { w = rw; } if (attrs.height == MATCH_PARENT) { h = ph; } else if (hasCompatScale) { h = (int) (rh * compatScale + .5f); } else { h = rh; } } if (hasCompatScale) { x = attrs.x * compatScale; y = attrs.y * compatScale; } else { x = attrs.x; y = attrs.y; } if (inMultiWindowMode && (attrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) == 0) { // Make sure window fits in parent frame since it is in a non-fullscreen task as // required by {@link Gravity#apply} call. w = Math.min(w, pw); h = Math.min(h, ph); } // We need to fit it to the display if either // a) The window is in a fullscreen container, or we don't have a task (we assume fullscreen // for the taskless windows) // b) If it's a secondary app window, we also need to fit it to the display unless // FLAG_LAYOUT_NO_LIMITS is set. This is so we place Popups, dialogs, and similar windows on // screen, but SurfaceViews want to be always at a specific location so we don't fit it to // the display. final boolean fitToDisplay = !inMultiWindowMode || ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits); // Set mFrame Gravity.apply(attrs.gravity, w, h, outParentFrame, (int) (x + attrs.horizontalMargin * pw), (int) (y + attrs.verticalMargin * ph), outFrame); // Now make sure the window fits in the overall display frame. if (fitToDisplay) { Gravity.applyDisplay(attrs.gravity, outDisplayFrame, outFrame); } if (DEBUG) Log.d(TAG, "computeWindowFrames " + attrs.getTitle() + " outFrame=" + outFrame.toShortString() + " outParentFrame=" + outParentFrame.toShortString() + " outDisplayFrame=" + outDisplayFrame.toShortString() + " attachedWindowFrame=" + (attachedWindowFrame != null ? attachedWindowFrame.toShortString() : "null") + " requestedWidth=" + requestedWidth + " requestedHeight=" + requestedHeight + " compatScale=" + compatScale + " windowingMode=" + WindowConfiguration.windowingModeToString(windowingMode) + " displayCutoutSafe=" + displayCutoutSafe + " attrs=" + attrs + " state=" + state + " requestedVisibilities=" + requestedVisibilities); return clippedByDisplayCutout; } }
core/proto/android/server/windowmanagerservice.proto +1 −1 Original line number Diff line number Diff line Loading @@ -527,7 +527,7 @@ message ConfigurationContainerProto { message WindowFramesProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; optional .android.graphics.RectProto containing_frame = 1; optional .android.graphics.RectProto containing_frame = 1 [deprecated=true]; optional .android.graphics.RectProto content_frame = 2 [deprecated=true]; optional .android.graphics.RectProto decor_frame = 3 [deprecated=true]; optional .android.graphics.RectProto display_frame = 4; Loading
services/core/java/com/android/server/wm/DisplayContent.java +28 −25 Original line number Diff line number Diff line Loading @@ -802,13 +802,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp }; private final Consumer<WindowState> mPerformLayout = w -> { if (w.mLayoutAttached || w.skipLayout()) { return; } // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid // wasting time and funky changes while a window is animating away. final boolean gone = w.isGoneForLayout(); if (DEBUG_LAYOUT && !w.mLayoutAttached) { if (DEBUG_LAYOUT) { Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame + " mLayoutAttached=" + w.mLayoutAttached + " config reported=" + w.isLastConfigReportedToClient()); final ActivityRecord activity = w.mActivityRecord; if (gone) Slog.v(TAG, " GONE: mViewVisibility=" + w.mViewVisibility Loading @@ -824,7 +827,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // If this view is GONE, then skip it -- keep the current frame, and let the caller know // so they can ignore it if they want. (We do the normal layout for INVISIBLE windows, // since that means "perform layout as normal, just don't display"). if ((!gone || !w.mHaveFrame || w.mLayoutNeeded) && !w.mLayoutAttached) { if (!gone || !w.mHaveFrame || w.mLayoutNeeded) { if (mTmpInitial) { w.resetContentChanged(); } Loading @@ -851,13 +854,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame() + " mContainingFrame=" + w.getContainingFrame() + " mParentFrame=" + w.getParentFrame() + " mDisplayFrame=" + w.getDisplayFrame()); } }; private final Consumer<WindowState> mPerformLayoutAttached = w -> { if (w.mLayoutAttached) { if (!w.mLayoutAttached || w.skipLayout()) { return; } if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame + " mViewVisibility=" + w.mViewVisibility + " mRelayoutCalled=" + w.mRelayoutCalled); Loading @@ -867,7 +872,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if ((w.mViewVisibility != GONE && w.mRelayoutCalled) || !w.mHaveFrame || w.mLayoutNeeded) { if (mTmpInitial) { //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); w.resetContentChanged(); } w.mSurfacePlacementNeeded = true; Loading @@ -876,10 +880,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames); w.mLayoutSeq = mLayoutSeq; if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame() + " mContainingFrame=" + w.getContainingFrame() + " mParentFrame=" + w.getParentFrame() + " mDisplayFrame=" + w.getDisplayFrame()); } } }; private final Predicate<WindowState> mComputeImeTargetPredicate = w -> { Loading
services/core/java/com/android/server/wm/DisplayPolicy.java +30 −22 Original line number Diff line number Diff line Loading @@ -43,12 +43,12 @@ import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_B import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; import static android.view.WindowLayout.UNSPECIFIED_LENGTH; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 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_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; Loading @@ -65,7 +65,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; Loading Loading @@ -1719,10 +1718,6 @@ public class DisplayPolicy { layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR)); return; } if (win.mActivityRecord != null && win.mActivityRecord.mWaitForEnteringPinnedMode) { // Skip layout of the window when in transition to pip mode. return; } final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation); final int type = attrs.type; Loading @@ -1734,37 +1729,50 @@ public class DisplayPolicy { final Rect pf = windowFrames.mParentFrame; final Rect df = windowFrames.mDisplayFrame; final Rect f = windowFrames.mFrame; final Rect attachedWindowFrame = attached != null ? attached.getFrame() : null; sTmpLastParentFrame.set(pf); final Rect winBounds; final int requestedWidth; final int requestedHeight; if (windowFrames.mIsSimulatingDecorWindow) { // 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(); // frame set for the simulated layout. winBounds = df; // The view hierarchy has not been measured in the simulated layout. Use // UNSPECIFIED_LENGTH as the requested width and height so that WindowLayout will choose // the proper values in this case. requestedWidth = UNSPECIFIED_LENGTH; requestedHeight = UNSPECIFIED_LENGTH; } else { winBounds = win.getBounds(); requestedWidth = win.mRequestedWidth; requestedHeight = win.mRequestedHeight; } final boolean clippedByDisplayCutout = mWindowLayout.computeWindowFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe, winBounds, win.getRequestedVisibilities(), attachedWindowFrame, df, pf); win.getInsetsState(), displayFrames.mDisplayCutoutSafe, winBounds, win.getWindowingMode(), requestedWidth, requestedHeight, win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale, df, pf, f); 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. if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR && !win.inMultiWindowMode()) { df.left = df.top = -10000; df.right = df.bottom = 10000; } if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle() + ": sim=#" + Integer.toHexString(sim) + " attach=" + attached + " type=" + type + String.format(" flags=0x%08x", fl) + " pf=" + pf.toShortString() + " df=" + df.toShortString()); + " flags=" + ViewDebug.flagsToString(LayoutParams.class, "flags", fl) + " pf=" + pf.toShortString() + " df=" + df.toShortString() + " f=" + f.toShortString()); if (!sTmpLastParentFrame.equals(pf)) { windowFrames.setContentChanged(true); } win.computeFrameAndUpdateSourceFrame(displayFrames); if (!windowFrames.mIsSimulatingDecorWindow) { win.setFrame(); } } WindowState getTopFullscreenOpaqueWindow() { Loading