Store decor rects per window for transition cropping.

Instead of keeping a single global system decor rect around
in WindowManagerService, calculate and store policy-defined
system-decor frame for each window.

The per-window decor rect is useful for smooth transitions, since it
determines window cropping during transition animations.

Bug:10938001
Change-Id: Ice6652aa5946027c45c0b7ab4e46473a0f8e3f90
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 79c0b3c..5ac23ad 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -165,9 +165,11 @@
          * 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.
          */
         public void computeFrameLw(Rect parentFrame, Rect displayFrame,
-                Rect overlayFrame, Rect contentFrame, Rect visibleFrame);
+                Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame);
 
         /**
          * Retrieve the current frame of the window that has been assigned by
@@ -815,19 +817,10 @@
                               int displayRotation);
 
     /**
-     * Return the rectangle of the screen currently covered by system decorations.
-     * This will be called immediately after {@link #layoutWindowLw}.  It can
-     * fill in the rectangle to indicate any part of the screen that it knows
-     * for sure is covered by system decor such as the status bar.  The rectangle
-     * is initially set to the actual size of the screen, indicating nothing is
-     * covered.
-     *
-     * @param systemRect The rectangle of the screen that is not covered by
-     * system decoration.
-     * @return Returns the layer above which the system rectangle should
-     * not be applied.
+     * Returns the bottom-most layer of the system decor, above which no policy decor should
+     * be applied.
      */
-    public int getSystemDecorRectLw(Rect systemRect);
+    public int getSystemDecorLayerLw();
 
     /**
      * Return the rectangle of the screen that is available for applications to run in.
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 7f93c28..0f1f12e 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -374,6 +374,7 @@
     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 mTmpNavigationFrame = new Rect();
 
     WindowState mTopFullscreenOpaqueWindowState;
@@ -2680,10 +2681,12 @@
         final Rect df = mTmpDisplayFrame;
         final Rect of = mTmpOverscanFrame;
         final Rect vf = mTmpVisibleFrame;
+        final Rect dcf = mTmpDecorFrame;
         pf.left = df.left = of.left = vf.left = mDockLeft;
         pf.top = df.top = of.top = vf.top = mDockTop;
         pf.right = df.right = of.right = vf.right = mDockRight;
         pf.bottom = df.bottom = of.bottom = vf.bottom = mDockBottom;
+        dcf.setEmpty();  // Decor frame N/A for system bars.
 
         if (isDefaultDisplay) {
             // For purposes of putting out fake window up to steal focus, we will
@@ -2781,7 +2784,7 @@
                 mStatusBarLayer = mNavigationBar.getSurfaceLayer();
                 // And compute the final frame.
                 mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
-                        mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame);
+                        mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf);
                 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
                 if (mNavigationBarController.checkHiddenLw()) {
                     updateSysUiVisibility = true;
@@ -2806,7 +2809,7 @@
                 mStatusBarLayer = mStatusBar.getSurfaceLayer();
 
                 // Let the status bar determine its size.
-                mStatusBar.computeFrameLw(pf, df, vf, vf, vf);
+                mStatusBar.computeFrameLw(pf, df, vf, vf, vf, dcf);
 
                 // For layout, the status bar is always at the top with our fixed height.
                 mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
@@ -2854,11 +2857,7 @@
 
     /** {@inheritDoc} */
     @Override
-    public int getSystemDecorRectLw(Rect systemRect) {
-        systemRect.left = mSystemLeft;
-        systemRect.top = mSystemTop;
-        systemRect.right = mSystemRight;
-        systemRect.bottom = mSystemBottom;
+    public int getSystemDecorLayerLw() {
         if (mStatusBar != null) return mStatusBar.getSurfaceLayer();
         if (mNavigationBar != null) return mNavigationBar.getSurfaceLayer();
         return 0;
@@ -2961,6 +2960,8 @@
         final Rect of = mTmpOverscanFrame;
         final Rect cf = mTmpContentFrame;
         final Rect vf = mTmpVisibleFrame;
+        final Rect dcf = mTmpDecorFrame;
+        dcf.setEmpty();
 
         final boolean hasNavBar = (isDefaultDisplay && mHasNavigationBar
                 && mNavigationBar != null && mNavigationBar.isVisibleLw());
@@ -2991,6 +2992,27 @@
             attrs.gravity = Gravity.BOTTOM;
             mDockLayer = win.getSurfaceLayer();
         } else {
+
+            // Default policy decor for the default display
+            dcf.left = mSystemLeft;
+            dcf.top = mSystemTop;
+            dcf.right = mSystemRight;
+            dcf.bottom = mSystemBottom;
+            if (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
+                    && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW) {
+                if ((attrs.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0
+                        && (sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
+                        && (sysUiFl & View.SYSTEM_UI_FLAG_TRANSPARENT_STATUS) == 0) {
+                    // Ensure policy decor includes status bar
+                    dcf.top = mStableTop;
+                }
+                if ((sysUiFl & View.SYSTEM_UI_FLAG_TRANSPARENT_NAVIGATION) == 0) {
+                    // Ensure policy decor includes navigation bar
+                    dcf.bottom = mStableBottom;
+                    dcf.right = mStableRight;
+                }
+            }
+
             if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
                     == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() 
@@ -3026,7 +3048,7 @@
                         if (DEBUG_LAYOUT) Slog.v(TAG, String.format(
                                         "Laying out status bar window: (%d,%d - %d,%d)",
                                         pf.left, pf.top, pf.right, pf.bottom));
-                    } else if ((attrs.flags&FLAG_LAYOUT_IN_OVERSCAN) != 0
+                    } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
                             && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                             && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                         // Asking to layout into the overscan region, so give it that pure
@@ -3071,7 +3093,7 @@
                         of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
                     }
 
-                    if ((attrs.flags&FLAG_FULLSCREEN) == 0) {
+                    if ((fl & FLAG_FULLSCREEN) == 0) {
                         if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
                             cf.left = mDockLeft;
                             cf.top = mDockTop;
@@ -3093,7 +3115,6 @@
                         cf.right = mRestrictedScreenLeft + mRestrictedScreenWidth;
                         cf.bottom = mRestrictedScreenTop + mRestrictedScreenHeight;
                     }
-
                     applyStableConstraints(sysUiFl, fl, cf);
                     if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
                         vf.left = mCurLeft;
@@ -3164,7 +3185,7 @@
                             = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
                     pf.bottom = df.bottom = of.bottom = cf.bottom
                             = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
-                } else if ((attrs.flags & FLAG_LAYOUT_IN_OVERSCAN) != 0
+                } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
                         && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                         && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                     // Asking to layout into the overscan region, so give it that pure
@@ -3275,9 +3296,10 @@
                 + String.format(" flags=0x%08x", fl)
                 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
                 + " of=" + of.toShortString()
-                + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
+                + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
+                + " dcf=" + dcf.toShortString());
 
-        win.computeFrameLw(pf, df, of, cf, vf);
+        win.computeFrameLw(pf, df, of, cf, vf, dcf);
 
         // Dock windows carve out the bottom of the screen, so normal windows
         // can't appear underneath them.
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 713aeee..38bed22 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -440,7 +440,6 @@
             = new ArrayList<IRotationWatcher>();
     int mDeferredRotationPauseCount;
 
-    final Rect mSystemDecorRect = new Rect();
     int mSystemDecorLayer = 0;
     final Rect mScreenRect = new Rect();
 
@@ -8202,7 +8201,7 @@
         mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);
         if (isDefaultDisplay) {
             // Not needed on non-default displays.
-            mSystemDecorLayer = mPolicy.getSystemDecorRectLw(mSystemDecorRect);
+            mSystemDecorLayer = mPolicy.getSystemDecorLayerLw();
             mScreenRect.set(0, 0, dw, dh);
         }
 
@@ -10410,8 +10409,7 @@
                 }
                 pw.println();
         if (dumpAll) {
-            pw.print("  mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
-                    pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
+            pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
                     pw.print(" mScreenRect="); pw.println(mScreenRect.toShortString());
             if (mLastStatusBarVisibility != 0) {
                 pw.print("  mLastStatusBarVisibility=0x");
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index d56e225..894dca5 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -218,6 +218,7 @@
     final Rect mContentFrame = new Rect();
     final Rect mParentFrame = new Rect();
     final Rect mVisibleFrame = new Rect();
+    final Rect mDecorFrame = new Rect();
 
     boolean mContentChanged;
 
@@ -458,7 +459,7 @@
     }
 
     @Override
-    public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf) {
+    public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf, Rect dcf) {
         mHaveFrame = true;
 
         TaskStack stack = mAppToken != null ? getStack() : null;
@@ -524,6 +525,7 @@
         mOverscanFrame.set(of);
         mContentFrame.set(cf);
         mVisibleFrame.set(vf);
+        mDecorFrame.set(dcf);
 
         final int fw = mFrame.width();
         final int fh = mFrame.height();
@@ -1404,6 +1406,8 @@
             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("Cur insets: overscan=");
                     mOverscanInsets.printShortString(pw);
                     pw.print(" content="); mContentInsets.printShortString(pw);
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 533f626..e2fae89 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1100,12 +1100,14 @@
             } else {
                 applyDecorRect(mService.mScreenRect);
             }
-        } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND) {
-            // The universe background isn't cropped.
+        } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND
+                || w.mDecorFrame.isEmpty()) {
+            // The universe background isn't cropped, nor windows without policy decor.
             w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(),
                     w.mCompatFrame.height());
         } else {
-            applyDecorRect(mService.mSystemDecorRect);
+            // Crop to the system decor specified by policy.
+            applyDecorRect(w.mDecorFrame);
         }
 
         if (!w.mSystemDecorRect.equals(w.mLastSystemDecorRect)) {