Use fullscreen sized buffer for drag resizing

- When drag resizing starts, set the surface size to fullscreen
  (plus any surface insets requested by win attrs), so that we don't
  reallocate buffers and the buffers don't get rejected by surfaceflinger
  due to size-mismatch.

- When drag resizing ends, restore the surface size to the original.

- Update shown frame before setSurfaceBoundariesLocked(), as the top-left
  of the window could change, we need to update the surface position. This
  fixes incorrect window positing during resizing by corners on top/left.

- When doing tap-detection, skip non-freeformed tasks. This fixes the
  bug where clicking near border of a window could dismiss it.

Change-Id: I5dc9fc34ff05685320b8fe5d491b9c066c6726e8
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 325196d..bfeddb3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -234,7 +234,7 @@
             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 final Task task = tasks.get(taskNdx);
                 task.getBounds(mTmpRect);
-                if (mTmpRect.contains(x, y)) {
+                if (task.inFreeformWorkspace() && mTmpRect.contains(x, y)) {
                     return task.mTaskId;
                 }
             }
@@ -299,7 +299,7 @@
                  * (For freeform focused task, the below logic will first remove the enlarged
                  * area, then add back the inner area.)
                  */
-                final boolean isFreeformed = win.inFreeformWorkspace();
+                final boolean isFreeformed = task.inFreeformWorkspace();
                 if (task != focusedTask || isFreeformed) {
                     mTmpRect.set(win.mVisibleFrame);
                     mTmpRect.intersect(win.mVisibleInsets);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 07a850b..cc9efdb 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -426,6 +426,10 @@
         return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
     }
 
+    boolean inFreeformWorkspace() {
+        return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+    }
+
     @Override
     public boolean isFullscreen() {
         return mFullscreen;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 17936a6..9e29925 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -85,6 +85,7 @@
 
     private int mTaskId;
     private TaskStack mStack;
+    private boolean mResizing;
     private final Rect mWindowOriginalBounds = new Rect();
     private final Rect mWindowDragBounds = new Rect();
     private float mStartDragX;
@@ -131,8 +132,8 @@
                             notifyMoveLocked(newX, newY);
                         }
                         try {
-                            mService.mActivityManager.resizeTask(mTaskId, mWindowDragBounds,
-                                    true /* resizedByUser */);
+                            mService.mActivityManager.resizeTask(
+                                    mTaskId, mWindowDragBounds, true /* resizedByUser */);
                         } catch(RemoteException e) {}
                     } break;
 
@@ -152,6 +153,11 @@
                 }
 
                 if (endDrag) {
+                    mResizing = false;
+                    try {
+                        mService.mActivityManager.resizeTask(
+                                mTaskId, mWindowDragBounds, true /* resizedByUser */);
+                    } catch(RemoteException e) {}
                     // Post back to WM to handle clean-ups. We still need the input
                     // event handler for the last finishInputEvent()!
                     mService.mH.sendEmptyMessage(H.FINISH_TASK_POSITIONING);
@@ -280,6 +286,10 @@
         mService.resumeRotationLocked();
     }
 
+    boolean isTaskResizing(final Task task) {
+        return mResizing && task != null && mTaskId == task.mTaskId;
+    }
+
     void startDragLocked(WindowState win, boolean resize, float startX, float startY) {
         if (DEBUG_TASK_POSITIONING) {
             Slog.d(TAG, "startDragLocked: win=" + win + ", resize=" + resize
@@ -300,6 +310,7 @@
             if (startY > visibleFrame.bottom) {
                 mCtrlType |= CTRL_BOTTOM;
             }
+            mResizing = true;
         }
 
         final Task task = win.getTask();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 789354d..e467b19 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -557,7 +557,7 @@
 
         final Task task = mAppToken != null ? getTask() : null;
         final boolean nonFullscreenTask = task != null && !task.isFullscreen();
-        final boolean freeformWorkspace = inFreeformWorkspace();
+        final boolean freeformWorkspace = task != null && task.inFreeformWorkspace();
         if (nonFullscreenTask) {
             task.getBounds(mContainingFrame);
             final WindowState imeWin = mService.mInputMethodWindow;
@@ -897,6 +897,11 @@
         return stack == null ? mDisplayContent : stack.getDisplayContent();
     }
 
+    public DisplayInfo getDisplayInfo() {
+        final DisplayContent displayContent = getDisplayContent();
+        return displayContent != null ? displayContent.getDisplayInfo() : null;
+    }
+
     public int getDisplayId() {
         final DisplayContent displayContent = getDisplayContent();
         if (displayContent == null) {
@@ -935,7 +940,7 @@
         if (task != null) {
             task.getBounds(bounds);
             if (forTouch == BOUNDS_FOR_TOUCH) {
-                if (inFreeformWorkspace()) {
+                if (task.inFreeformWorkspace()) {
                     final int delta = calculatePixelFromDp(RESIZE_HANDLE_WIDTH_IN_DP);
                     bounds.inset(-delta, -delta);
                 }
@@ -1668,9 +1673,13 @@
     }
 
     boolean inFreeformWorkspace() {
-        final Task task = getTask();
-        return task != null && task.mStack != null &&
-                task.mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+        final Task task = mAppToken != null ? getTask() : null;
+        return task != null && task.inFreeformWorkspace();
+    }
+
+    boolean isDragResizing() {
+        final Task task = mAppToken != null ? getTask() : null;
+        return mService.mTaskPositioner != null && mService.mTaskPositioner.isTaskResizing(task);
     }
 
     private int calculatePixelFromDp(int dp) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index bf1ab8f..7dc30bc 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -798,8 +798,17 @@
                 width = w.mRequestedWidth;
                 height = w.mRequestedHeight;
             } else {
-                width = w.mCompatFrame.width();
-                height = w.mCompatFrame.height();
+                // When we're doing a drag-resizing, request a surface that's fullscreen size,
+                // so that we don't need to reallocate during the process. This also prevents
+                // buffer drops due to size mismatch.
+                final DisplayInfo displayInfo = w.getDisplayInfo();
+                if (displayInfo != null && w.isDragResizing()) {
+                    width = displayInfo.logicalWidth;
+                    height = displayInfo.logicalHeight;
+                } else {
+                    width = w.mCompatFrame.width();
+                    height = w.mCompatFrame.height();
+                }
             }
 
             // Something is wrong and SurfaceFlinger will not like this,
@@ -1309,9 +1318,15 @@
 
         final boolean fullscreen = w.isFullscreen(displayInfo.appWidth, displayInfo.appHeight);
         final Rect clipRect = mTmpClipRect;
-        // We use the clip rect as provided by the tranformation for non-fullscreen windows to
-        // avoid premature clipping with the system decor rect.
-        clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : w.mSystemDecorRect);
+        if (w.isDragResizing()) {
+            // When we're doing a drag-resizing, the surface is set up to cover full screen.
+            // Set the clip rect to be the same size so that we don't get any scaling.
+            clipRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+        } else {
+            // We use the clip rect as provided by the tranformation for non-fullscreen windows to
+            // avoid premature clipping with the system decor rect.
+            clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : w.mSystemDecorRect);
+        }
 
         // Expand the clip rect for surface insets.
         final WindowManager.LayoutParams attrs = w.mAttrs;
@@ -1358,8 +1373,17 @@
             width  = w.mRequestedWidth;
             height = w.mRequestedHeight;
         } else {
-            width = w.mCompatFrame.width();
-            height = w.mCompatFrame.height();
+            // When we're doing a drag-resizing, request a surface that's fullscreen size,
+            // so that we don't need to reallocate during the process. This also prevents
+            // buffer drops due to size mismatch.
+            final DisplayInfo displayInfo = w.getDisplayInfo();
+            if (displayInfo != null && w.isDragResizing()) {
+                width = displayInfo.logicalWidth;
+                height = displayInfo.logicalHeight;
+            } else {
+                width = w.mCompatFrame.width();
+                height = w.mCompatFrame.height();
+            }
         }
 
         // Something is wrong and SurfaceFlinger will not like this,
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 52efa68..86da94f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -712,7 +712,12 @@
                             }
                         }
                     }
-
+                    /*
+                     * Updates the shown frame before we set up the surface. This is needed because
+                     * the resizing could change the top-left position (in addition to size) of the
+                     * window. setSurfaceBoundariesLocked uses mShownFrame to position the surface.
+                     */
+                    winAnimator.computeShownFrameLocked();
                     winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
                 }