Created WindowFrames class and moved data from PWM and WS

Moved frame data from PWM and WS into the WindowFrames class. Created a
WindowFrames object in both PWM and WS and converted usages of window
frame info to get data from the WindowFrames instance.

Data between PWM and WS is still separate and copied over when
requested.

Bug: 111359087
Test: go/wm-smoke
Change-Id: I95aa9f2f22557e96ad09f08b7fe6d6a2562399c4
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5bc35e7..66bd16e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -288,6 +288,7 @@
 import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.DisplayFrames;
+import com.android.server.wm.WindowFrames;
 import com.android.server.wm.WindowManagerInternal;
 import com.android.server.wm.WindowManagerInternal.AppTransitionListener;
 
@@ -662,15 +663,7 @@
 
     InputConsumer mInputConsumer = null;
 
-    static final Rect mTmpParentFrame = new Rect();
-    static final Rect mTmpDisplayFrame = new Rect();
-    static final Rect mTmpOverscanFrame = new Rect();
-    static final Rect mTmpContentFrame = new Rect();
-    static final Rect mTmpVisibleFrame = new Rect();
-    static final Rect mTmpDecorFrame = new Rect();
-    static final Rect mTmpStableFrame = new Rect();
-    static final Rect mTmpNavigationFrame = new Rect();
-    static final Rect mTmpOutsetFrame = new Rect();
+    private final WindowFrames mWindowFrames = new WindowFrames();
     private static final Rect mTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
     private static final Rect mTmpRect = new Rect();
 
@@ -4659,18 +4652,6 @@
         mDockLayer = 0x10000000;
         mStatusBarLayer = -1;
 
-        // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
-        final Rect pf = mTmpParentFrame;
-        final Rect df = mTmpDisplayFrame;
-        final Rect of = mTmpOverscanFrame;
-        final Rect vf = mTmpVisibleFrame;
-        final Rect dcf = mTmpDecorFrame;
-        vf.set(displayFrames.mDock);
-        of.set(displayFrames.mDock);
-        df.set(displayFrames.mDock);
-        pf.set(displayFrames.mDock);
-        dcf.setEmpty();  // Decor frame N/A for system bars.
-
         if (displayFrames.mDisplayId == DEFAULT_DISPLAY) {
             // For purposes of putting out fake window up to steal focus, we will
             // drive nav being hidden only by whether it is requested.
@@ -4711,16 +4692,15 @@
             // be hidden (because of the screen aspect ratio), then take that into account.
             navVisible |= !canHideNavigationBar();
 
-            boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, dcf,
-                    navVisible, navTranslucent, navAllowedHidden, statusBarExpandedNotKeyguard);
+            boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
+                    navTranslucent, navAllowedHidden, statusBarExpandedNotKeyguard);
             if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
-            updateSysUiVisibility |= layoutStatusBar(
-                    displayFrames, pf, df, of, vf, dcf, sysui, isKeyguardShowing);
+            updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
             if (updateSysUiVisibility) {
                 updateSystemUiVisibilityLw();
             }
         }
-        layoutScreenDecorWindows(displayFrames, pf, df, dcf);
+        layoutScreenDecorWindows(displayFrames);
 
         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
@@ -4731,11 +4711,18 @@
         }
     }
 
-    private void layoutScreenDecorWindows(DisplayFrames displayFrames, Rect pf, Rect df, Rect dcf) {
+    private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
         if (mScreenDecorWindows.isEmpty()) {
             return;
         }
 
+        mTmpRect.setEmpty();
+        mWindowFrames.setFrames(displayFrames.mDock /* parentFrame */,
+                displayFrames.mDock /* displayFrame */, displayFrames.mDock /* overscanFrame */,
+                displayFrames.mDock /* contentFrame */, displayFrames.mDock /* visibleFrame */,
+                mTmpRect /* decorFrame */, displayFrames.mDock /* stableFrame */,
+                displayFrames.mDock /* outsetFrame */);
+
         final int displayId = displayFrames.mDisplayId;
         final Rect dockFrame = displayFrames.mDock;
         final int displayHeight = displayFrames.mDisplayHeight;
@@ -4748,9 +4735,7 @@
                 continue;
             }
 
-            w.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, df /* overlayFrame */,
-                    df /* contentFrame */, df /* visibleFrame */, dcf /* decorFrame */,
-                    df /* stableFrame */, df /* outsetFrame */, displayFrames.mDisplayCutout,
+            w.computeFrameLw(mWindowFrames, displayFrames.mDisplayCutout,
                     false /* parentFrameWasClippedByDisplayCutout */);
             final Rect frame = w.getFrameLw();
 
@@ -4796,25 +4781,25 @@
         displayFrames.mRestrictedOverscan.set(dockFrame);
     }
 
-    private boolean layoutStatusBar(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect vf,
-            Rect dcf, int sysui, boolean isKeyguardShowing) {
+    private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
+            boolean isKeyguardShowing) {
         // decide where the status bar goes ahead of time
         if (mStatusBar == null) {
             return false;
         }
         // apply any navigation bar insets
-        of.set(displayFrames.mUnrestricted);
-        df.set(displayFrames.mUnrestricted);
-        pf.set(displayFrames.mUnrestricted);
-        vf.set(displayFrames.mStable);
+        mTmpRect.setEmpty();
+        mWindowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
+                displayFrames.mUnrestricted /* displayFrame */,
+                displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
+                displayFrames.mStable /* visibleFrame */, mTmpRect /* decorFrame */,
+                displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
 
         mStatusBarLayer = mStatusBar.getSurfaceLayer();
 
         // Let the status bar determine its size.
-        mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */,
-                vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */,
-                dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */,
-                displayFrames.mDisplayCutout, false /* parentFrameWasClippedByDisplayCutout */);
+        mStatusBar.computeFrameLw(mWindowFrames, displayFrames.mDisplayCutout,
+                false /* parentFrameWasClippedByDisplayCutout */);
 
         // For layout, the status bar is always at the top with our fixed height.
         displayFrames.mStable.top = displayFrames.mUnrestricted.top
@@ -4861,12 +4846,14 @@
         return mStatusBarController.checkHiddenLw();
     }
 
-    private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, Rect dcf,
-            boolean navVisible, boolean navTranslucent, boolean navAllowedHidden,
+    private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
+            boolean navTranslucent, boolean navAllowedHidden,
             boolean statusBarExpandedNotKeyguard) {
         if (mNavigationBar == null) {
             return false;
         }
+
+        final Rect navigationFrame = mWindowFrames.mParentFrame;
         boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
         // Force the navigation bar to its appropriate place and size. We need to do this directly,
         // instead of relying on it to bubble up from the nav bar, because this needs to change
@@ -4885,7 +4872,7 @@
             // It's a system nav bar or a portrait screen; nav bar goes on bottom.
             final int top = cutoutSafeUnrestricted.bottom
                     - getNavigationBarHeight(rotation, uiMode);
-            mTmpNavigationFrame.set(0, top, displayWidth, displayFrames.mUnrestricted.bottom);
+            navigationFrame.set(0, top, displayWidth, displayFrames.mUnrestricted.bottom);
             displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
             if (transientNavBarShowing) {
                 mNavigationBarController.setBarShowingLw(true);
@@ -4908,7 +4895,7 @@
             // Landscape screen; nav bar goes to the right.
             final int left = cutoutSafeUnrestricted.right
                     - getNavigationBarWidth(rotation, uiMode);
-            mTmpNavigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
+            navigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
             displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
             if (transientNavBarShowing) {
                 mNavigationBarController.setBarShowingLw(true);
@@ -4931,7 +4918,7 @@
             // Seascape screen; nav bar goes to the left.
             final int right = cutoutSafeUnrestricted.left
                     + getNavigationBarWidth(rotation, uiMode);
-            mTmpNavigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
+            navigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
             displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
             if (transientNavBarShowing) {
                 mNavigationBarController.setBarShowingLw(true);
@@ -4959,13 +4946,19 @@
         displayFrames.mContent.set(dockFrame);
         mStatusBarLayer = mNavigationBar.getSurfaceLayer();
         // And compute the final frame.
-        mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
-                mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe, mTmpNavigationFrame, dcf,
-                mTmpNavigationFrame, displayFrames.mDisplayCutoutSafe,
-                displayFrames.mDisplayCutout, false /* parentFrameWasClippedByDisplayCutout */);
+        mTmpRect.setEmpty();
+        mWindowFrames.setFrames(navigationFrame /* parentFrame */,
+                navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
+                displayFrames.mDisplayCutoutSafe /* contentFrame */,
+                navigationFrame /* visibleFrame */, mTmpRect /* decorFrame */,
+                navigationFrame /* stableFrame */,
+                displayFrames.mDisplayCutoutSafe /* outsetFrame */);
+
+        mNavigationBar.computeFrameLw(mWindowFrames, displayFrames.mDisplayCutout,
+                false /* parentFrameWasClippedByDisplayCutout */);
         mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
 
-        if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
+        if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
         return mNavigationBarController.checkHiddenLw();
     }
 
@@ -5093,15 +5086,15 @@
         final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
         final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
 
-        final Rect pf = mTmpParentFrame;
-        final Rect df = mTmpDisplayFrame;
-        final Rect of = mTmpOverscanFrame;
-        final Rect cf = mTmpContentFrame;
-        final Rect vf = mTmpVisibleFrame;
-        final Rect dcf = mTmpDecorFrame;
-        final Rect sf = mTmpStableFrame;
-        Rect osf = null;
+        final Rect pf = mWindowFrames.mParentFrame;
+        final Rect df = mWindowFrames.mDisplayFrame;
+        final Rect of = mWindowFrames.mOverscanFrame;
+        final Rect cf = mWindowFrames.mContentFrame;
+        final Rect vf = mWindowFrames.mVisibleFrame;
+        final Rect dcf = mWindowFrames.mDecorFrame;
+        final Rect sf = mWindowFrames.mStableFrame;
         dcf.setEmpty();
+        mWindowFrames.mOutsetFrame.setEmpty();
 
         final boolean hasNavBar = (isDefaultDisplay && mHasNavigationBar
                 && mNavigationBar != null && mNavigationBar.isVisibleLw());
@@ -5500,7 +5493,7 @@
         // apply the outsets to floating dialogs, because they wouldn't make sense there.
         final boolean useOutsets = shouldUseOutsets(attrs, fl);
         if (isDefaultDisplay && useOutsets) {
-            osf = mTmpOutsetFrame;
+            final Rect osf = mWindowFrames.mOutsetFrame;
             osf.set(cf.left, cf.top, cf.right, cf.bottom);
             int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
             if (outset > 0) {
@@ -5528,9 +5521,9 @@
                 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
                 + " dcf=" + dcf.toShortString()
                 + " sf=" + sf.toShortString()
-                + " osf=" + (osf == null ? "null" : osf.toShortString()));
+                + " osf=" + mWindowFrames.mOutsetFrame.toShortString());
 
-        win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf, displayFrames.mDisplayCutout,
+        win.computeFrameLw(mWindowFrames, displayFrames.mDisplayCutout,
                 parentFrameWasClippedByDisplayCutout);
         // Dock windows carve out the bottom of the screen, so normal windows
         // can't appear underneath them.
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 9fbe419..cc5f730 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -94,6 +94,7 @@
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.server.wm.DisplayFrames;
+import com.android.server.wm.WindowFrames;
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import java.io.PrintWriter;
@@ -198,34 +199,13 @@
          * getFrame() if so desired.  Must be called with the window manager
          * lock held.
          *
-         * @param parentFrame The frame of the parent container this window
-         * is in, used for computing its basic position.
-         * @param displayFrame The frame of the overall display in which this
-         * window can appear, used for constraining the overall dimensions
-         * of the window.
-         * @param overlayFrame The frame within the display that is inside
-         * of the overlay region.
-         * @param contentFrame The frame within the display in which we would
-         * like active content to appear.  This will cause windows behind to
-         * be resized to match the given content frame.
-         * @param visibleFrame The frame within the display that the window
-         * is actually visible, used for computing its visible insets to be
-         * given to windows behind.
-         * This can be used as a hint for scrolling (avoiding resizing)
-         * the window to make certain that parts of its content
-         * are visible.
-         * @param decorFrame The decor frame specified by policy specific to this window,
-         * to use for proper cropping during animation.
-         * @param stableFrame The frame around which stable system decoration is positioned.
-         * @param outsetFrame The frame that includes areas that aren't part of the surface but we
-         * want to treat them as such.
+         * @param windowFrames Container for all the window frames that affect how the window is
+         *                     laid out.
          * @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,
+        public void computeFrameLw(WindowFrames windowFrames, WmDisplayCutout displayCutout,
                 boolean parentFrameWasClippedByDisplayCutout);
 
         /**
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index fa6079c..7fcf17c 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1816,7 +1816,7 @@
                 // animation target (which will be different than the task bounds)
                 frame.set(getTask().getParent().getBounds());
             } else {
-                frame.set(win.mContainingFrame);
+                frame.set(win.getContainingFrame());
             }
             surfaceInsets = win.getAttrs().surfaceInsets;
             // XXX(b/72757033): These are insets relative to the window frame, but we're really
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0ca8e1a..5043214 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -579,8 +579,8 @@
                 }
 
                 if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame=" + w.mFrame
-                        + " mContainingFrame=" + w.mContainingFrame
-                        + " mDisplayFrame=" + w.mDisplayFrame);
+                        + " mContainingFrame=" + w.getContainingFrame()
+                        + " mDisplayFrame=" + w.getDisplayFrameLw());
             }
         }
     };
@@ -607,8 +607,8 @@
                 mService.mPolicy.layoutWindowLw(w, w.getParentWindow(), mDisplayFrames);
                 w.mLayoutSeq = mLayoutSeq;
                 if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.mFrame
-                        + " mContainingFrame=" + w.mContainingFrame
-                        + " mDisplayFrame=" + w.mDisplayFrame);
+                        + " mContainingFrame=" + w.getContainingFrame()
+                        + " mDisplayFrame=" + w.getDisplayFrameLw());
             }
         } else if (w.mAttrs.type == TYPE_DREAM) {
             // Don't layout windows behind a dream, so that if it does stuff like hide the
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2da77a1..71f34c9 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -409,7 +409,7 @@
      * @param out Rect containing the max visible bounds.
      * @return true if the task has some visible app windows; false otherwise.
      */
-    boolean getMaxVisibleBounds(Rect out) {
+    private boolean getMaxVisibleBounds(Rect out) {
         boolean foundTop = false;
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final AppWindowToken token = mChildren.get(i);
@@ -422,22 +422,11 @@
                 continue;
             }
             if (!foundTop) {
-                out.set(win.mVisibleFrame);
                 foundTop = true;
-                continue;
+                out.setEmpty();
             }
-            if (win.mVisibleFrame.left < out.left) {
-                out.left = win.mVisibleFrame.left;
-            }
-            if (win.mVisibleFrame.top < out.top) {
-                out.top = win.mVisibleFrame.top;
-            }
-            if (win.mVisibleFrame.right > out.right) {
-                out.right = win.mVisibleFrame.right;
-            }
-            if (win.mVisibleFrame.bottom > out.bottom) {
-                out.bottom = win.mVisibleFrame.bottom;
-            }
+
+            win.getMaxVisibleBounds(out);
         }
         return foundTop;
     }
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
new file mode 100644
index 0000000..b833051
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2018 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 com.android.server.wm;
+
+import static com.android.server.wm.WindowFramesProto.CONTAINING_FRAME;
+import static com.android.server.wm.WindowFramesProto.CONTENT_FRAME;
+import static com.android.server.wm.WindowFramesProto.DECOR_FRAME;
+import static com.android.server.wm.WindowFramesProto.DISPLAY_FRAME;
+import static com.android.server.wm.WindowFramesProto.OUTSET_FRAME;
+import static com.android.server.wm.WindowFramesProto.OVERSCAN_FRAME;
+import static com.android.server.wm.WindowFramesProto.PARENT_FRAME;
+import static com.android.server.wm.WindowFramesProto.VISIBLE_FRAME;
+
+import android.annotation.NonNull;
+import android.graphics.Rect;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.PrintWriter;
+
+/**
+ * Container class for all the window frames that affect how windows are laid out.
+ *
+ * TODO(b/111611553): Investigate which frames are still needed and which are duplicates
+ */
+public class WindowFrames {
+
+    /**
+     * In most cases, this is the area of the entire screen.
+     *
+     * TODO(b/111611553): The name is unclear and most likely should be swapped with
+     * {@link #mDisplayFrame}
+     * TODO(b/111611553): In some cases, it also includes top insets, like for IME. Determine
+     * whether this is still necessary to do.
+     */
+    public final Rect mParentFrame = new Rect();
+
+    /**
+     * The entire screen area of the {@link TaskStack} this window is in. Usually equal to the
+     * screen area of the device.
+     *
+     * TODO(b/111611553): The name is unclear and most likely should be swapped with
+     * {@link #mParentFrame}
+    */
+    public final Rect mDisplayFrame = new Rect();
+
+    /**
+     * The region of the display frame that the display type supports displaying content on. This
+     * is mostly a special case for TV where some displays don’t have the entire display usable.
+     * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag can be used to
+     * allow window display contents to extend into the overscan region.
+     */
+    public final Rect mOverscanFrame = new Rect();
+
+    /**
+     * Legacy stuff. Generally equal to the content frame expect when the IME for older apps
+     * displays hint text.
+     */
+    public final Rect mVisibleFrame = new Rect();
+
+    /**
+     * The area not occupied by the status and navigation bars. So, if both status and navigation
+     * bars are visible, the decor frame is equal to the stable frame.
+     */
+    public final Rect mDecorFrame = new Rect();
+
+    /**
+     * Equal to the decor frame if the IME (e.g. keyboard) is not present. Equal to the decor frame
+     * minus the area occupied by the IME if the IME is present.
+     */
+    public final Rect mContentFrame = new Rect();
+
+    /**
+     * The display frame minus the stable insets. This value is always constant regardless of if
+     * the status bar or navigation bar is visible.
+     */
+    public final Rect mStableFrame = new Rect();
+
+    /**
+     * Frame that includes dead area outside of the surface but where we want to pretend that it's
+     * possible to draw.
+     */
+    final public Rect mOutsetFrame = new Rect();
+
+    /**
+     * Similar to {@link #mDisplayFrame}
+     *
+     * TODO: Why is this different than mDisplayFrame
+     */
+    final Rect mContainingFrame = new Rect();
+
+    public WindowFrames() {
+    }
+
+    public WindowFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame, Rect contentFrame,
+            Rect visibleFrame, Rect decorFrame, Rect stableFrame, Rect outsetFrame) {
+        setFrames(parentFrame, displayFrame, overscanFrame, contentFrame, visibleFrame, decorFrame,
+                stableFrame, outsetFrame);
+    }
+
+    public void setFrames(Rect parentFrame, Rect displayFrame, Rect overscanFrame,
+            Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
+            Rect outsetFrame) {
+        mParentFrame.set(parentFrame);
+        mDisplayFrame.set(displayFrame);
+        mOverscanFrame.set(overscanFrame);
+        mContentFrame.set(contentFrame);
+        mVisibleFrame.set(visibleFrame);
+        mDecorFrame.set(decorFrame);
+        mStableFrame.set(stableFrame);
+        mOutsetFrame.set(outsetFrame);
+    }
+
+    public void writeToProto(@NonNull ProtoOutputStream proto, long fieldId) {
+        final long token = proto.start(fieldId);
+        mParentFrame.writeToProto(proto, PARENT_FRAME);
+        mContentFrame.writeToProto(proto, CONTENT_FRAME);
+        mDisplayFrame.writeToProto(proto, DISPLAY_FRAME);
+        mOverscanFrame.writeToProto(proto, OVERSCAN_FRAME);
+        mVisibleFrame.writeToProto(proto, VISIBLE_FRAME);
+        mDecorFrame.writeToProto(proto, DECOR_FRAME);
+        mOutsetFrame.writeToProto(proto, OUTSET_FRAME);
+        mContainingFrame.writeToProto(proto, CONTAINING_FRAME);
+        proto.end(token);
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("Frames: containing=");
+                mContainingFrame.printShortString(pw);
+                pw.print(" parent="); mParentFrame.printShortString(pw);
+                pw.println();
+        pw.print(prefix); pw.print("    display=");
+                mDisplayFrame.printShortString(pw);
+                pw.print(" overscan="); mOverscanFrame.printShortString(pw);
+                pw.println();
+        pw.print(prefix); pw.print("    content=");
+                mContentFrame.printShortString(pw);
+                pw.print(" visible="); mVisibleFrame.printShortString(pw);
+                pw.println();
+        pw.print(prefix); pw.print("    decor=");
+                mDecorFrame.printShortString(pw);
+                pw.println();
+        pw.print(prefix); pw.print("    outset=");
+                mOutsetFrame.printShortString(pw);
+                pw.println();
+    }
+
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 176bc2e..2bd1305 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1593,7 +1593,7 @@
         }
         // We use the visible frame, because we want the animation to morph the window from what
         // was visible to the user to the final destination of the new window.
-        Rect frame = replacedWindow.mVisibleFrame;
+        Rect frame = replacedWindow.getVisibleFrameLw();
         // We treat this as if this activity was opening, so we can trigger the app transition
         // animation and piggy-back on existing transition animation infrastructure.
         mOpeningApps.add(atoken);
@@ -1829,7 +1829,7 @@
                 outDisplayFrame.setEmpty();
                 return;
             }
-            outDisplayFrame.set(win.mDisplayFrame);
+            outDisplayFrame.set(win.getDisplayFrameLw());
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c8c4b58..1d443f9 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -119,13 +119,9 @@
 import static com.android.server.wm.WindowStateProto.ANIMATOR;
 import static com.android.server.wm.WindowStateProto.ATTRIBUTES;
 import static com.android.server.wm.WindowStateProto.CHILD_WINDOWS;
-import static com.android.server.wm.WindowStateProto.CONTAINING_FRAME;
-import static com.android.server.wm.WindowStateProto.CONTENT_FRAME;
 import static com.android.server.wm.WindowStateProto.CONTENT_INSETS;
 import static com.android.server.wm.WindowStateProto.CUTOUT;
-import static com.android.server.wm.WindowStateProto.DECOR_FRAME;
 import static com.android.server.wm.WindowStateProto.DESTROYING;
-import static com.android.server.wm.WindowStateProto.DISPLAY_FRAME;
 import static com.android.server.wm.WindowStateProto.DISPLAY_ID;
 import static com.android.server.wm.WindowStateProto.FRAME;
 import static com.android.server.wm.WindowStateProto.GIVEN_CONTENT_INSETS;
@@ -135,10 +131,7 @@
 import static com.android.server.wm.WindowStateProto.IS_READY_FOR_DISPLAY;
 import static com.android.server.wm.WindowStateProto.IS_VISIBLE;
 import static com.android.server.wm.WindowStateProto.OUTSETS;
-import static com.android.server.wm.WindowStateProto.OUTSET_FRAME;
-import static com.android.server.wm.WindowStateProto.OVERSCAN_FRAME;
 import static com.android.server.wm.WindowStateProto.OVERSCAN_INSETS;
-import static com.android.server.wm.WindowStateProto.PARENT_FRAME;
 import static com.android.server.wm.WindowStateProto.REMOVED;
 import static com.android.server.wm.WindowStateProto.REMOVE_ON_EXIT;
 import static com.android.server.wm.WindowStateProto.REQUESTED_HEIGHT;
@@ -149,9 +142,9 @@
 import static com.android.server.wm.WindowStateProto.SURFACE_POSITION;
 import static com.android.server.wm.WindowStateProto.SYSTEM_UI_VISIBILITY;
 import static com.android.server.wm.WindowStateProto.VIEW_VISIBILITY;
-import static com.android.server.wm.WindowStateProto.VISIBLE_FRAME;
 import static com.android.server.wm.WindowStateProto.VISIBLE_INSETS;
 import static com.android.server.wm.WindowStateProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowStateProto.WINDOW_FRAMES;
 import static com.android.server.wm.utils.CoordinateTransforms.transformRect;
 import static com.android.server.wm.utils.CoordinateTransforms.transformToRotation;
 
@@ -409,42 +402,10 @@
     // screen size compatibility mode.
     final Rect mCompatFrame = new Rect();
 
-    final Rect mContainingFrame = new Rect();
-
-    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();
-
-    // The region of the display frame that the display type supports displaying content on. This
-    // is mostly a special case for TV where some displays don’t have the entire display usable.
-    // {@link WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag can be used to allow
-    // window display contents to extend into the overscan region.
-    private final Rect mOverscanFrame = new Rect();
-
-    // The display frame minus the stable insets. This value is always constant regardless of if
-    // the status bar or navigation bar is visible.
-    private final Rect mStableFrame = new Rect();
-
-    // The area not occupied by the status and navigation bars. So, if both status and navigation
-    // bars are visible, the decor frame is equal to the stable frame.
-    final Rect mDecorFrame = new Rect();
-
-    // Equal to the decor frame if the IME (e.g. keyboard) is not present. Equal to the decor frame
-    // minus the area occupied by the IME if the IME is present.
-    private final Rect mContentFrame = new Rect();
-
-    // Legacy stuff. Generally equal to the content frame expect when the IME for older apps
-    // displays hint text.
-    final Rect mVisibleFrame = new Rect();
-
-    // Frame that includes dead area outside of the surface but where we want to pretend that it's
-    // possible to draw.
-    private final Rect mOutsetFrame = new Rect();
+    private final WindowFrames mWindowFrames = new WindowFrames();
 
     /**
      * Usually empty. Set to the task's tempInsetFrame. See
@@ -850,9 +811,7 @@
     }
 
     @Override
-    public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overscanFrame,
-            Rect contentFrame, Rect visibleFrame, Rect decorFrame, Rect stableFrame,
-            Rect outsetFrame, WmDisplayCutout displayCutout,
+    public void computeFrameLw(WindowFrames windowFrames, WmDisplayCutout displayCutout,
             boolean parentFrameWasClippedByDisplayCutout) {
         if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
             // This window is being replaced and either already got information that it's being
@@ -892,36 +851,39 @@
         final int layoutYDiff;
         if (inFullscreenContainer || layoutInParentFrame()) {
             // We use the parent frame as the containing frame for fullscreen and child windows
-            mContainingFrame.set(parentFrame);
-            mDisplayFrame.set(displayFrame);
-            layoutDisplayFrame = displayFrame;
-            layoutContainingFrame = parentFrame;
+            mWindowFrames.mContainingFrame.set(windowFrames.mParentFrame);
+            mWindowFrames.mDisplayFrame.set(windowFrames.mDisplayFrame);
+            layoutDisplayFrame = windowFrames.mDisplayFrame;
+            layoutContainingFrame = windowFrames.mParentFrame;
             layoutXDiff = 0;
             layoutYDiff = 0;
         } else {
-            getBounds(mContainingFrame);
+            getBounds(mWindowFrames.mContainingFrame);
             if (mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) {
 
                 // If the bounds are frozen, we still want to translate the window freely and only
                 // freeze the size.
                 Rect frozen = mAppToken.mFrozenBounds.peek();
-                mContainingFrame.right = mContainingFrame.left + frozen.width();
-                mContainingFrame.bottom = mContainingFrame.top + frozen.height();
+                mWindowFrames.mContainingFrame.right =
+                        mWindowFrames.mContainingFrame.left + frozen.width();
+                mWindowFrames.mContainingFrame.bottom =
+                        mWindowFrames.mContainingFrame.top + frozen.height();
             }
             final WindowState imeWin = mService.mInputMethodWindow;
             // IME is up and obscuring this window. Adjust the window position so it is visible.
             if (imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget()) {
-                if (inFreeformWindowingMode()
-                        && mContainingFrame.bottom > contentFrame.bottom) {
+                if (inFreeformWindowingMode() && mWindowFrames.mContainingFrame.bottom
+                        > windowFrames.mContentFrame.bottom) {
                     // In freeform we want to move the top up directly.
                     // TODO: Investigate why this is contentFrame not parentFrame.
-                    mContainingFrame.top -= mContainingFrame.bottom - contentFrame.bottom;
-                } else if (!inPinnedWindowingMode()
-                        && mContainingFrame.bottom > parentFrame.bottom) {
+                    mWindowFrames.mContainingFrame.top -= mWindowFrames.mContainingFrame.bottom
+                            - windowFrames.mContentFrame.bottom;
+                } else if (!inPinnedWindowingMode() && mWindowFrames.mContainingFrame.bottom
+                        > windowFrames.mParentFrame.bottom) {
                     // But in docked we want to behave like fullscreen and behave as if the task
                     // were given smaller bounds for the purposes of layout. Skip adjustments for
                     // the pinned stack, they are handled separately in the PinnedStackController.
-                    mContainingFrame.bottom = parentFrame.bottom;
+                    mWindowFrames.mContainingFrame.bottom = windowFrames.mParentFrame.bottom;
                 }
             }
 
@@ -929,8 +891,8 @@
                 // In floating modes (e.g. freeform, pinned) we have only to set the rectangle
                 // if it wasn't set already. No need to intersect it with the (visible)
                 // "content frame" since it is allowed to be outside the visible desktop.
-                if (mContainingFrame.isEmpty()) {
-                    mContainingFrame.set(contentFrame);
+                if (mWindowFrames.mContainingFrame.isEmpty()) {
+                    mWindowFrames.mContainingFrame.set(windowFrames.mContentFrame);
                 }
             }
 
@@ -940,31 +902,39 @@
                 // PIP edge case: When going from pinned to fullscreen, we apply a
                 // tempInsetFrame for the full task - but we're still at the start of the animation.
                 // To prevent a jump if there's a letterbox, restrict to the parent frame.
-                mInsetFrame.intersectUnchecked(parentFrame);
-                mContainingFrame.intersectUnchecked(parentFrame);
+                mInsetFrame.intersectUnchecked(windowFrames.mParentFrame);
+                mWindowFrames.mContainingFrame.intersectUnchecked(windowFrames.mParentFrame);
             }
 
-            mDisplayFrame.set(mContainingFrame);
-            layoutXDiff = !mInsetFrame.isEmpty() ? mInsetFrame.left - mContainingFrame.left : 0;
-            layoutYDiff = !mInsetFrame.isEmpty() ? mInsetFrame.top - mContainingFrame.top : 0;
-            layoutContainingFrame = !mInsetFrame.isEmpty() ? mInsetFrame : mContainingFrame;
+            mWindowFrames.mDisplayFrame.set(mWindowFrames.mContainingFrame);
+            layoutXDiff =
+                    !mInsetFrame.isEmpty() ? mInsetFrame.left - mWindowFrames.mContainingFrame.left
+                            : 0;
+            layoutYDiff =
+                    !mInsetFrame.isEmpty() ? mInsetFrame.top - mWindowFrames.mContainingFrame.top
+                            : 0;
+            layoutContainingFrame =
+                    !mInsetFrame.isEmpty() ? mInsetFrame : mWindowFrames.mContainingFrame;
             mTmpRect.set(0, 0, dc.getDisplayInfo().logicalWidth, dc.getDisplayInfo().logicalHeight);
-            subtractInsets(mDisplayFrame, layoutContainingFrame, displayFrame, mTmpRect);
+            subtractInsets(mWindowFrames.mDisplayFrame, layoutContainingFrame,
+                    windowFrames.mDisplayFrame, mTmpRect);
             if (!layoutInParentFrame()) {
-                subtractInsets(mContainingFrame, layoutContainingFrame, parentFrame, mTmpRect);
-                subtractInsets(mInsetFrame, layoutContainingFrame, parentFrame, mTmpRect);
+                subtractInsets(mWindowFrames.mContainingFrame, layoutContainingFrame,
+                        windowFrames.mParentFrame, mTmpRect);
+                subtractInsets(mInsetFrame, layoutContainingFrame, windowFrames.mParentFrame,
+                        mTmpRect);
             }
-            layoutDisplayFrame = displayFrame;
+            layoutDisplayFrame = windowFrames.mDisplayFrame;
             layoutDisplayFrame.intersect(layoutContainingFrame);
         }
 
-        final int pw = mContainingFrame.width();
-        final int ph = mContainingFrame.height();
+        final int pw = mWindowFrames.mContainingFrame.width();
+        final int ph = mWindowFrames.mContainingFrame.height();
 
-        if (!mParentFrame.equals(parentFrame)) {
+        if (!mWindowFrames.mParentFrame.equals(windowFrames.mParentFrame)) {
             //Slog.i(TAG_WM, "Window " + this + " content frame from " + mParentFrame
             //        + " to " + parentFrame);
-            mParentFrame.set(parentFrame);
+            mWindowFrames.mParentFrame.set(windowFrames.mParentFrame);
             mContentChanged = true;
         }
         if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) {
@@ -973,14 +943,14 @@
             mContentChanged = true;
         }
 
-        mOverscanFrame.set(overscanFrame);
-        mContentFrame.set(contentFrame);
-        mVisibleFrame.set(visibleFrame);
-        mDecorFrame.set(decorFrame);
-        mStableFrame.set(stableFrame);
-        final boolean hasOutsets = outsetFrame != null;
+        mWindowFrames.mOverscanFrame.set(windowFrames.mOverscanFrame);
+        mWindowFrames.mContentFrame.set(windowFrames.mContentFrame);
+        mWindowFrames.mVisibleFrame.set(windowFrames.mVisibleFrame);
+        mWindowFrames.mDecorFrame.set(windowFrames.mDecorFrame);
+        mWindowFrames.mStableFrame.set(windowFrames.mStableFrame);
+        final boolean hasOutsets = !windowFrames.mOutsetFrame.isEmpty();
         if (hasOutsets) {
-            mOutsetFrame.set(outsetFrame);
+            mWindowFrames.mOutsetFrame.set(windowFrames.mOutsetFrame);
         }
 
         final int fw = mFrame.width();
@@ -990,10 +960,13 @@
 
         // Calculate the outsets before the content frame gets shrinked to the window frame.
         if (hasOutsets) {
-            mOutsets.set(Math.max(mContentFrame.left - mOutsetFrame.left, 0),
-                    Math.max(mContentFrame.top - mOutsetFrame.top, 0),
-                    Math.max(mOutsetFrame.right - mContentFrame.right, 0),
-                    Math.max(mOutsetFrame.bottom - mContentFrame.bottom, 0));
+            mOutsets.set(
+                    Math.max(mWindowFrames.mContentFrame.left - mWindowFrames.mOutsetFrame.left, 0),
+                    Math.max(mWindowFrames.mContentFrame.top - mWindowFrames.mOutsetFrame.top, 0),
+                    Math.max(mWindowFrames.mOutsetFrame.right - mWindowFrames.mContentFrame.right,
+                            0),
+                    Math.max(mWindowFrames.mOutsetFrame.bottom - mWindowFrames.mContentFrame.bottom,
+                            0));
         } else {
             mOutsets.set(0, 0, 0, 0);
         }
@@ -1004,7 +977,8 @@
             // For pinned workspace the frame isn't limited in any particular
             // way since SystemUI controls the bounds. For freeform however
             // we want to keep things inside the content frame.
-            final Rect limitFrame = task.inPinnedWindowingMode() ? mFrame : mContentFrame;
+            final Rect limitFrame =
+                    task.inPinnedWindowingMode() ? mFrame : mWindowFrames.mContentFrame;
             // Keep the frame out of the blocked system area, limit it in size to the content area
             // and make sure that there is always a minimum visible so that the user can drag it
             // into a usable area..
@@ -1016,57 +990,60 @@
             final int minVisibleWidth = Math.min(width, WindowManagerService.dipToPixel(
                     MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics));
             final int top = Math.max(limitFrame.top,
-                    Math.min(mFrame.top, limitFrame.bottom - minVisibleHeight));
+                    Math.min( mFrame.top, limitFrame.bottom - minVisibleHeight));
             final int left = Math.max(limitFrame.left + minVisibleWidth - width,
-                    Math.min(mFrame.left, limitFrame.right - minVisibleWidth));
+                    Math.min( mFrame.left, limitFrame.right - minVisibleWidth));
             mFrame.set(left, top, left + width, top + height);
-            mContentFrame.set(mFrame);
-            mVisibleFrame.set(mContentFrame);
-            mStableFrame.set(mContentFrame);
+            mWindowFrames.mContentFrame.set( mFrame);
+            mWindowFrames.mVisibleFrame.set(mWindowFrames.mContentFrame);
+            mWindowFrames.mStableFrame.set(mWindowFrames.mContentFrame);
         } else if (mAttrs.type == TYPE_DOCK_DIVIDER) {
             dc.getDockedDividerController().positionDockedStackedDivider(mFrame);
-            mContentFrame.set(mFrame);
+            mWindowFrames.mContentFrame.set(mFrame);
             if (!mFrame.equals(mLastFrame)) {
                 mMovedByResize = true;
             }
         } else {
-            mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
-                    Math.max(mContentFrame.top, mFrame.top),
-                    Math.min(mContentFrame.right, mFrame.right),
-                    Math.min(mContentFrame.bottom, mFrame.bottom));
+            mWindowFrames.mContentFrame.set(Math.max(mWindowFrames.mContentFrame.left, mFrame.left),
+                    Math.max(mWindowFrames.mContentFrame.top, mFrame.top),
+                    Math.min(mWindowFrames.mContentFrame.right, mFrame.right),
+                    Math.min(mWindowFrames.mContentFrame.bottom, mFrame.bottom));
 
-            mVisibleFrame.set(Math.max(mVisibleFrame.left, mFrame.left),
-                    Math.max(mVisibleFrame.top, mFrame.top),
-                    Math.min(mVisibleFrame.right, mFrame.right),
-                    Math.min(mVisibleFrame.bottom, mFrame.bottom));
+            mWindowFrames.mVisibleFrame.set(Math.max(mWindowFrames.mVisibleFrame.left, mFrame.left),
+                    Math.max(mWindowFrames.mVisibleFrame.top, mFrame.top),
+                    Math.min(mWindowFrames.mVisibleFrame.right, mFrame.right),
+                    Math.min(mWindowFrames.mVisibleFrame.bottom, mFrame.bottom));
 
-            mStableFrame.set(Math.max(mStableFrame.left, mFrame.left),
-                    Math.max(mStableFrame.top, mFrame.top),
-                    Math.min(mStableFrame.right, mFrame.right),
-                    Math.min(mStableFrame.bottom, mFrame.bottom));
+            mWindowFrames.mStableFrame.set(Math.max(mWindowFrames.mStableFrame.left, mFrame.left),
+                    Math.max(mWindowFrames.mStableFrame.top, mFrame.top),
+                    Math.min(mWindowFrames.mStableFrame.right, mFrame.right),
+                    Math.min(mWindowFrames.mStableFrame.bottom, mFrame.bottom));
         }
 
         if (inFullscreenContainer && !windowsAreFloating) {
             // Windows that are not fullscreen can be positioned outside of the display frame,
             // but that is not a reason to provide them with overscan insets.
-            mOverscanInsets.set(Math.max(mOverscanFrame.left - layoutContainingFrame.left, 0),
-                    Math.max(mOverscanFrame.top - layoutContainingFrame.top, 0),
-                    Math.max(layoutContainingFrame.right - mOverscanFrame.right, 0),
-                    Math.max(layoutContainingFrame.bottom - mOverscanFrame.bottom, 0));
+            mOverscanInsets.set(
+                    Math.max(mWindowFrames.mOverscanFrame.left - layoutContainingFrame.left, 0),
+                    Math.max(mWindowFrames.mOverscanFrame.top - layoutContainingFrame.top, 0),
+                    Math.max(layoutContainingFrame.right - mWindowFrames.mOverscanFrame.right, 0),
+                    Math.max(layoutContainingFrame.bottom - mWindowFrames.mOverscanFrame.bottom,
+                            0));
         }
 
         if (mAttrs.type == TYPE_DOCK_DIVIDER) {
             // For the docked divider, we calculate the stable insets like a full-screen window
             // so it can use it to calculate the snap positions.
-            final WmDisplayCutout c = displayCutout.calculateRelativeTo(mDisplayFrame);
-            mTmpRect.set(mDisplayFrame);
+            final WmDisplayCutout c = displayCutout.calculateRelativeTo(
+                    mWindowFrames.mDisplayFrame);
+            mTmpRect.set(mWindowFrames.mDisplayFrame);
             mTmpRect.inset(c.getDisplayCutout().getSafeInsets());
-            mTmpRect.intersectUnchecked(mStableFrame);
+            mTmpRect.intersectUnchecked(mWindowFrames.mStableFrame);
 
-            mStableInsets.set(Math.max(mTmpRect.left - mDisplayFrame.left, 0),
-                    Math.max(mTmpRect.top - mDisplayFrame.top, 0),
-                    Math.max(mDisplayFrame.right - mTmpRect.right, 0),
-                    Math.max(mDisplayFrame.bottom - mTmpRect.bottom, 0));
+            mStableInsets.set(Math.max(mTmpRect.left - mWindowFrames.mDisplayFrame.left, 0),
+                    Math.max(mTmpRect.top - mWindowFrames.mDisplayFrame.top, 0),
+                    Math.max(mWindowFrames.mDisplayFrame.right - mTmpRect.right, 0),
+                    Math.max(mWindowFrames.mDisplayFrame.bottom - mTmpRect.bottom, 0));
 
             // The divider doesn't care about insets in any case, so set it to empty so we don't
             // trigger a relayout when moving it.
@@ -1081,26 +1058,27 @@
                     && mFrame.right > mTmpRect.right;
             boolean overrideBottomInset = !windowsAreFloating && !inFullscreenContainer
                     && mFrame.bottom > mTmpRect.bottom;
-            mContentInsets.set(mContentFrame.left - mFrame.left,
-                    mContentFrame.top - mFrame.top,
-                    overrideRightInset ? mTmpRect.right - mContentFrame.right
-                            : mFrame.right - mContentFrame.right,
-                    overrideBottomInset ? mTmpRect.bottom - mContentFrame.bottom
-                            : mFrame.bottom - mContentFrame.bottom);
+            mContentInsets.set(mWindowFrames.mContentFrame.left - mFrame.left,
+                    mWindowFrames.mContentFrame.top - mFrame.top,
+                    overrideRightInset ? mTmpRect.right - mWindowFrames.mContentFrame.right
+                            : mFrame.right - mWindowFrames.mContentFrame.right,
+                    overrideBottomInset ? mTmpRect.bottom - mWindowFrames.mContentFrame.bottom
+                            : mFrame.bottom - mWindowFrames.mContentFrame.bottom);
 
-            mVisibleInsets.set(mVisibleFrame.left - mFrame.left,
-                    mVisibleFrame.top - mFrame.top,
-                    overrideRightInset ? mTmpRect.right - mVisibleFrame.right
-                            : mFrame.right - mVisibleFrame.right,
-                    overrideBottomInset ? mTmpRect.bottom - mVisibleFrame.bottom
-                            : mFrame.bottom - mVisibleFrame.bottom);
+            mVisibleInsets.set(mWindowFrames.mVisibleFrame.left - mFrame.left,
+                    mWindowFrames.mVisibleFrame.top - mFrame.top,
+                    overrideRightInset ? mTmpRect.right - mWindowFrames.mVisibleFrame.right
+                            : mFrame.right - mWindowFrames.mVisibleFrame.right,
+                    overrideBottomInset ? mTmpRect.bottom - mWindowFrames.mVisibleFrame.bottom
+                            : mFrame.bottom - mWindowFrames.mVisibleFrame.bottom);
 
-            mStableInsets.set(Math.max(mStableFrame.left - mFrame.left, 0),
-                    Math.max(mStableFrame.top - mFrame.top, 0),
-                    overrideRightInset ? Math.max(mTmpRect.right - mStableFrame.right, 0)
-                            : Math.max(mFrame.right - mStableFrame.right, 0),
-                    overrideBottomInset ? Math.max(mTmpRect.bottom - mStableFrame.bottom, 0)
-                            :  Math.max(mFrame.bottom - mStableFrame.bottom, 0));
+            mStableInsets.set(Math.max(mWindowFrames.mStableFrame.left - mFrame.left, 0),
+                    Math.max(mWindowFrames.mStableFrame.top - mFrame.top, 0),
+                    overrideRightInset ? Math.max(mTmpRect.right - mWindowFrames.mStableFrame.right,
+                            0) : Math.max(mFrame.right - mWindowFrames.mStableFrame.right, 0),
+                    overrideBottomInset ? Math.max(
+                            mTmpRect.bottom - mWindowFrames.mStableFrame.bottom, 0)
+                            : Math.max(mFrame.bottom - mWindowFrames.mStableFrame.bottom, 0));
         }
 
         mDisplayCutout = displayCutout.calculateRelativeTo(mFrame);
@@ -1108,9 +1086,9 @@
         // Offset the actual frame by the amount layout frame is off.
         mFrame.offset(-layoutXDiff, -layoutYDiff);
         mCompatFrame.offset(-layoutXDiff, -layoutYDiff);
-        mContentFrame.offset(-layoutXDiff, -layoutYDiff);
-        mVisibleFrame.offset(-layoutXDiff, -layoutYDiff);
-        mStableFrame.offset(-layoutXDiff, -layoutYDiff);
+        mWindowFrames.mContentFrame.offset(-layoutXDiff, -layoutYDiff);
+        mWindowFrames.mVisibleFrame.offset(-layoutXDiff, -layoutYDiff);
+        mWindowFrames.mStableFrame.offset(-layoutXDiff, -layoutYDiff);
 
         mCompatFrame.set(mFrame);
         if (mEnforceSizeCompat) {
@@ -1132,8 +1110,8 @@
             final DisplayContent displayContent = getDisplayContent();
             if (displayContent != null) {
                 final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-                getDisplayContent().mWallpaperController.updateWallpaperOffset(
-                        this, displayInfo.logicalWidth, displayInfo.logicalHeight, false);
+                getDisplayContent().mWallpaperController.updateWallpaperOffset(this,
+                        displayInfo.logicalWidth, displayInfo.logicalHeight, false);
             }
         }
 
@@ -1167,26 +1145,38 @@
 
     @Override
     public Rect getDisplayFrameLw() {
-        return mDisplayFrame;
+        return mWindowFrames.mDisplayFrame;
     }
 
     @Override
     public Rect getOverscanFrameLw() {
-        return mOverscanFrame;
+        return mWindowFrames.mOverscanFrame;
     }
 
     @Override
     public Rect getContentFrameLw() {
-        return mContentFrame;
+        return mWindowFrames.mContentFrame;
     }
 
     @Override
     public Rect getVisibleFrameLw() {
-        return mVisibleFrame;
+        return mWindowFrames.mVisibleFrame;
     }
 
     Rect getStableFrameLw() {
-        return mStableFrame;
+        return mWindowFrames.mStableFrame;
+    }
+
+    Rect getDecorFrame() {
+        return mWindowFrames.mDecorFrame;
+    }
+
+    Rect getParentFrame() {
+        return mWindowFrames.mParentFrame;
+    }
+
+    Rect getContainingFrame() {
+        return mWindowFrames.mContainingFrame;
     }
 
     @Override
@@ -1442,7 +1432,7 @@
             }
         }
 
-        bounds.set(mVisibleFrame);
+        bounds.set(mWindowFrames.mVisibleFrame);
         if (intersectWithStackBounds) {
             bounds.intersect(mTmpRect);
         }
@@ -2889,10 +2879,10 @@
             // All window frames that are fullscreen extend above status bar, but some don't extend
             // below navigation bar. Thus, check for display frame for top/left and stable frame for
             // bottom right.
-            if (win.mFrame.left <= win.mDisplayFrame.left
-                    && win.mFrame.top <= win.mDisplayFrame.top
-                    && win.mFrame.right >= win.mStableFrame.right
-                    && win.mFrame.bottom >= win.mStableFrame.bottom) {
+            if (win.mFrame.left <= win.getDisplayFrameLw().left
+                    && win.mFrame.top <= win.getDisplayFrameLw().top
+                    && win.mFrame.right >= win.getStableFrameLw().right
+                    && win.mFrame.bottom >= win.getStableFrameLw().bottom) {
                 // Is a fullscreen window, like the clock alarm. Show to everyone.
                 return false;
             }
@@ -3262,9 +3252,7 @@
         mAttrs.writeToProto(proto, ATTRIBUTES);
         mGivenContentInsets.writeToProto(proto, GIVEN_CONTENT_INSETS);
         mFrame.writeToProto(proto, FRAME);
-        mContainingFrame.writeToProto(proto, CONTAINING_FRAME);
-        mParentFrame.writeToProto(proto, PARENT_FRAME);
-        mContentFrame.writeToProto(proto, CONTENT_FRAME);
+        mWindowFrames.writeToProto(proto, WINDOW_FRAMES);
         mContentInsets.writeToProto(proto, CONTENT_INSETS);
         mAttrs.surfaceInsets.writeToProto(proto, SURFACE_INSETS);
         mSurfacePosition.writeToProto(proto, SURFACE_POSITION);
@@ -3279,11 +3267,6 @@
         proto.write(SYSTEM_UI_VISIBILITY, mSystemUiVisibility);
         proto.write(HAS_SURFACE, mHasSurface);
         proto.write(IS_READY_FOR_DISPLAY, isReadyForDisplay());
-        mDisplayFrame.writeToProto(proto, DISPLAY_FRAME);
-        mOverscanFrame.writeToProto(proto, OVERSCAN_FRAME);
-        mVisibleFrame.writeToProto(proto, VISIBLE_FRAME);
-        mDecorFrame.writeToProto(proto, DECOR_FRAME);
-        mOutsetFrame.writeToProto(proto, OUTSET_FRAME);
         mOverscanInsets.writeToProto(proto, OVERSCAN_INSETS);
         mVisibleInsets.writeToProto(proto, VISIBLE_INSETS);
         mStableInsets.writeToProto(proto, STABLE_INSETS);
@@ -3415,20 +3398,7 @@
                     pw.println();
         }
         if (dumpAll) {
-            pw.print(prefix); pw.print("Frames: containing=");
-                    mContainingFrame.printShortString(pw);
-                    pw.print(" parent="); mParentFrame.printShortString(pw);
-                    pw.println();
-            pw.print(prefix); pw.print("    display="); mDisplayFrame.printShortString(pw);
-                    pw.print(" overscan="); mOverscanFrame.printShortString(pw);
-                    pw.println();
-            pw.print(prefix); pw.print("    content="); mContentFrame.printShortString(pw);
-                    pw.print(" visible="); mVisibleFrame.printShortString(pw);
-                    pw.println();
-            pw.print(prefix); pw.print("    decor="); mDecorFrame.printShortString(pw);
-                    pw.println();
-            pw.print(prefix); pw.print("    outset="); mOutsetFrame.printShortString(pw);
-                    pw.println();
+            mWindowFrames.dump(pw, prefix);
             pw.print(prefix); pw.print("Cur insets: overscan=");
                     mOverscanInsets.printShortString(pw);
                     pw.print(" content="); mContentInsets.printShortString(pw);
@@ -4303,7 +4273,7 @@
         // The decor frame is used to specify the region not covered by the system
         // decorations (nav bar, status bar). In case this is empty, for example with
         // FLAG_TRANSLUCENT_NAVIGATION, we don't need to do any cropping.
-        if (mDecorFrame.isEmpty()) {
+        if (mWindowFrames.mDecorFrame.isEmpty()) {
             return true;
         }
 
@@ -4348,7 +4318,7 @@
      * by system decorations.
      */
     private void calculateSystemDecorRect(Rect systemDecorRect) {
-        final Rect decorRect = mDecorFrame;
+        final Rect decorRect = mWindowFrames.mDecorFrame;
         final int width = mFrame.width();
         final int height = mFrame.height();
 
@@ -4886,6 +4856,26 @@
         super.seamlesslyRotate(t, oldRotation, newRotation);
     }
 
+    public void getMaxVisibleBounds(Rect out) {
+        if (out.isEmpty()) {
+            out.set(mWindowFrames.mVisibleFrame);
+            return;
+        }
+
+        if (mWindowFrames.mVisibleFrame.left < out.left) {
+            out.left = mWindowFrames.mVisibleFrame.left;
+        }
+        if (mWindowFrames.mVisibleFrame.top < out.top) {
+            out.top = mWindowFrames.mVisibleFrame.top;
+        }
+        if (mWindowFrames.mVisibleFrame.right > out.right) {
+            out.right = mWindowFrames.mVisibleFrame.right;
+        }
+        if (mWindowFrames.mVisibleFrame.bottom > out.bottom) {
+            out.bottom = mWindowFrames.mVisibleFrame.bottom;
+        }
+    }
+
     private final class MoveAnimationSpec implements AnimationSpec {
 
         private final long mDuration;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 14e0e13..39a310d 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -811,7 +811,7 @@
         w.calculatePolicyCrop(mSystemDecorRect);
 
         if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
-                + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
+                + w.getDecorFrame() + " mSystemDecorRect=" + mSystemDecorRect);
 
         final Task task = w.getTask();
         final boolean fullscreen = w.fillsDisplay() || (task != null && task.isFullscreen());
@@ -931,9 +931,9 @@
 
             // Make sure that what we're animating to and from is actually the right size in case
             // the window cannot take up the full screen.
-            mTmpStackBounds.intersectUnchecked(w.mParentFrame);
-            mTmpSourceBounds.intersectUnchecked(w.mParentFrame);
-            mTmpAnimatingBounds.intersectUnchecked(w.mParentFrame);
+            mTmpStackBounds.intersectUnchecked(w.getParentFrame());
+            mTmpSourceBounds.intersectUnchecked(w.getParentFrame());
+            mTmpAnimatingBounds.intersectUnchecked(w.getParentFrame());
 
             if (!mTmpSourceBounds.isEmpty()) {
                 // Get the final target stack bounds, if we are not animating, this is just the