Destroy docked divider surface when it's hidden.

Also includes bunch of small refactorings:
* destroying surfaces is now fully contained within
WindowManagerServices and mDestroySurface can be privatized;
* WMS.isDockedStackResizingLocked can be removed;
* mScreenCaptureDisabled changes from being SparseArray<Boolean> to
SparseBooleanArray, which not only avoids boxing but also makes code
simpler (no need to check for null)

Bug: 25844096
Change-Id: I0e5462760ffbc947ce6dc52ef429fa270ffc6786
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c7fccc3..685ec49 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -110,6 +110,7 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.util.TypedValue;
@@ -405,7 +406,7 @@
     /**
      * Windows whose surface should be destroyed.
      */
-    final ArrayList<WindowState> mDestroySurface = new ArrayList<>();
+    private final ArrayList<WindowState> mDestroySurface = new ArrayList<>();
 
     /**
      * Windows with a preserved surface waiting to be destroyed. These windows
@@ -442,11 +443,11 @@
     WindowState[] mRebuildTmp = new WindowState[20];
 
     /**
-     * Stores for each user whether screencapture is disabled
+     * Stores for each user whether screencapture is disabled for all their windows.
      * This array is essentially a cache for all userId for
      * {@link android.app.admin.DevicePolicyManager#getScreenCaptureDisabled}
      */
-    SparseArray<Boolean> mScreenCaptureDisabled = new SparseArray<>();
+    private SparseBooleanArray mScreenCaptureDisabled = new SparseBooleanArray();
 
     IInputMethodManager mInputMethodManager;
 
@@ -2107,25 +2108,11 @@
         executeAppTransition();
     }
 
-    /**
-     * Returns whether screen capture is disabled for all windows of a specific user.
-     */
-    boolean isScreenCaptureDisabledLocked(int userId) {
-        Boolean disabled = mScreenCaptureDisabled.get(userId);
-        if (disabled == null) {
-            return false;
-        }
-        return disabled;
-    }
-
     boolean isSecureLocked(WindowState w) {
-        if ((w.mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
+        if ((w.mAttrs.flags & FLAG_SECURE) != 0) {
             return true;
         }
-        if (isScreenCaptureDisabledLocked(UserHandle.getUserId(w.mOwnerUid))) {
-            return true;
-        }
-        return false;
+        return mScreenCaptureDisabled.get(UserHandle.getUserId(w.mOwnerUid));
     }
 
     /**
@@ -2649,8 +2636,10 @@
                 Slog.i(TAG, "Relayout " + win + ": oldVis=" + oldVisibility
                         + " newVis=" + viewVisibility, stack);
             }
-            if (viewVisibility == View.VISIBLE &&
-                    (win.mAppToken == null || !win.mAppToken.clientHidden)) {
+            final AppWindowToken appToken = win.mAppToken;
+            final boolean visible = viewVisibility == View.VISIBLE
+                    && (appToken == null ? win.mPolicyVisibility : !appToken.clientHidden);
+            if (visible) {
                 result = relayoutVisibleWindow(outConfig, result, win, winAnimator, attrChanges,
                         oldVisibility);
                 try {
@@ -2736,8 +2725,8 @@
                 mWallpaperControllerLocked.updateWallpaperOffset(
                         win, displayInfo.logicalWidth, displayInfo.logicalHeight, false);
             }
-            if (win.mAppToken != null) {
-                win.mAppToken.updateReportedVisibilityLocked();
+            if (appToken != null) {
+                appToken.updateReportedVisibilityLocked();
             }
             if (winAnimator.mReportSurfaceResized) {
                 winAnimator.mReportSurfaceResized = false;
@@ -2864,7 +2853,7 @@
             win.setDragResizing();
             // We can only change top level windows to the full-screen surface when
             // resizing (as we only have one full-screen surface). So there is no need
-            // to preserve and destroy windows which are attached to another, they 
+            // to preserve and destroy windows which are attached to another, they
             // will keep their surface and its size may change over time.
             if (win.mHasSurface && win.mAttachedWindow == null) {
                 winAnimator.preserveSurfaceLocked();
@@ -10150,14 +10139,33 @@
         }
     }
 
-    boolean isDockedStackResizingLocked() {
-        return getDefaultDisplayContentLocked().getDockedDividerController().isResizing();
-    }
-
     static int dipToPixel(int dip, DisplayMetrics displayMetrics) {
         return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
     }
 
+    void scheduleSurfaceDestroy(WindowState win) {
+        mDestroySurface.add(win);
+    }
+
+    boolean destroySurfacesLocked() {
+        boolean wallpaperDestroyed = false;
+        for (int i = mDestroySurface.size() - 1; i >= 0; i--) {
+            WindowState win = mDestroySurface.get(i);
+            win.mDestroying = false;
+            if (mInputMethodWindow == win) {
+                mInputMethodWindow = null;
+            }
+            if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
+                wallpaperDestroyed = true;
+            }
+            if (!win.shouldSaveSurface()) {
+                win.mWinAnimator.destroySurfaceLocked();
+            }
+        }
+        mDestroySurface.clear();
+        return wallpaperDestroyed;
+    }
+
     private final class LocalService extends WindowManagerInternal {
         @Override
         public void requestTraversalFromDisplayManager() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 01db707..3aa088d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -411,6 +411,10 @@
 
     final private Rect mTmpRect = new Rect();
 
+    // This window often remains added but hidden, so we want to destroy its surface when it's not
+    // visible.
+    private final boolean mDestroySurfaceWhenHidden;
+
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
            int viewVisibility, final DisplayContent displayContent) {
@@ -458,6 +462,7 @@
             mSubLayer = 0;
             mInputWindowHandle = null;
             mWinAnimator = null;
+            mDestroySurfaceWhenHidden = false;
             return;
         }
         mDeathRecipient = deathRecipient;
@@ -556,6 +561,7 @@
         mInputWindowHandle = new InputWindowHandle(
                 mAppToken != null ? mAppToken.mInputApplicationHandle : null, this,
                 displayContent.getDisplayId());
+        mDestroySurfaceWhenHidden = mAttrs.type == TYPE_DOCK_DIVIDER;
     }
 
     void attach() {
@@ -1313,6 +1319,10 @@
         mHasSurface = hasSurface;
     }
 
+    boolean shouldDestroySurfaceWhenAnimationFinishes() {
+        return mExiting || (mDestroySurfaceWhenHidden && !mPolicyVisibilityAfterAnim);
+    }
+
     private final class DeadWindowEventReceiver extends InputEventReceiver {
         DeadWindowEventReceiver(InputChannel inputChannel) {
             super(inputChannel, mService.mH.getLooper());
@@ -1589,6 +1599,10 @@
             // Already showing.
             return false;
         }
+        if (!mHasSurface) {
+            mDestroying = false;
+            mWinAnimator.createSurfaceLocked();
+        }
         if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this);
         if (doAnimation) {
             if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
@@ -1624,8 +1638,7 @@
                 doAnimation = false;
             }
         }
-        boolean current = doAnimation ? mPolicyVisibilityAfterAnim
-                : mPolicyVisibility;
+        final boolean current = doAnimation ? mPolicyVisibilityAfterAnim : mPolicyVisibility;
         if (!current) {
             // Already hiding.
             return false;
@@ -1636,11 +1649,9 @@
                 doAnimation = false;
             }
         }
-        if (doAnimation) {
-            mPolicyVisibilityAfterAnim = false;
-        } else {
+        mPolicyVisibilityAfterAnim = false;
+        if (!doAnimation) {
             if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility false: " + this);
-            mPolicyVisibilityAfterAnim = false;
             mPolicyVisibility = false;
             // Window is no longer visible -- make sure if we were waiting
             // for it to be displayed before enabling the display, that
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 93c2ff6..9726034 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -446,7 +446,7 @@
             }
         }
 
-        if (!mWin.mExiting) {
+        if (!mWin.shouldDestroySurfaceWhenAnimationFinishes()) {
             return;
         }
 
@@ -454,12 +454,13 @@
             return;
         }
 
-        if (WindowManagerService.localLOGV) Slog.v(
-                TAG, "Exit animation finished in " + this
-                + ": remove=" + mWin.mRemoveOnExit);
+        if (localLOGV) Slog.v(TAG, "Exit animation finished in " + this + ": remove="
+                + mWin.mRemoveOnExit);
         if (mSurfaceController != null && mSurfaceController.hasSurface()) {
-            mService.mDestroySurface.add(mWin);
-            mWin.mDestroying = true;
+            mService.scheduleSurfaceDestroy(mWin);
+            if (mWin.mExiting) {
+                mWin.mDestroying = true;
+            }
             hide("finishExit");
         }
         mWin.mExiting = false;
@@ -645,7 +646,7 @@
                 return null;
             }
 
-            if (WindowManagerService.localLOGV) {
+            if (localLOGV) {
                 Slog.v(TAG, "Got surface: " + mSurfaceController
                         + ", set left=" + w.mFrame.left + " top=" + w.mFrame.top
                         + ", animLayer=" + mAnimLayer);
@@ -666,7 +667,7 @@
                     mAnimLayer);
             mLastHidden = true;
 
-            if (WindowManagerService.localLOGV) Slog.v(
+            if (localLOGV) Slog.v(
                     TAG, "Created surface " + this);
         }
         return mSurfaceController;
@@ -973,7 +974,7 @@
                 //Slog.i(TAG, "Not applying alpha transform");
             }
 
-            if ((DEBUG_SURFACE_TRACE || WindowManagerService.localLOGV)
+            if ((DEBUG_SURFACE_TRACE || localLOGV)
                     && (mShownAlpha == 1.0 || mShownAlpha == 0.0)) Slog.v(
                     TAG, "computeShownFrameLocked: Animating " + this + " mAlpha=" + mAlpha
                     + " self=" + (selfTransformation ? mTransformation.getAlpha() : "null")
@@ -994,7 +995,7 @@
             return;
         }
 
-        if (WindowManagerService.localLOGV) Slog.v(
+        if (localLOGV) Slog.v(
                 TAG, "computeShownFrameLocked: " + this +
                 " not attached, mAlpha=" + mAlpha);
 
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index f8b8d6c..b3c23d1 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -296,10 +296,8 @@
     }
 
     boolean showRobustlyInTransaction() {
-        if (SHOW_TRANSACTIONS) logSurface(
-                "SHOW (performLayout)", null);
-        if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this
-                + " during relayout");
+        if (SHOW_TRANSACTIONS) logSurface("SHOW (performLayout)", null);
+        if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this + " during relayout");
 
         if (mHiddenForCrop) {
             return false;
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 6292c21..da7f45e 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -381,25 +381,7 @@
         }
 
         // Destroy the surface of any windows that are no longer visible.
-        boolean wallpaperDestroyed = false;
-        i = mService.mDestroySurface.size();
-        if (i > 0) {
-            do {
-                i--;
-                WindowState win = mService.mDestroySurface.get(i);
-                win.mDestroying = false;
-                if (mService.mInputMethodWindow == win) {
-                    mService.mInputMethodWindow = null;
-                }
-                if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
-                    wallpaperDestroyed = true;
-                }
-                if (!win.shouldSaveSurface()) {
-                    win.mWinAnimator.destroySurfaceLocked();
-                }
-            } while (i > 0);
-            mService.mDestroySurface.clear();
-        }
+        final boolean wallpaperDestroyed = mService.destroySurfacesLocked();
 
         // Time to remove any exiting tokens?
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {