Preserve window during resize triggered relaunches.

This changes application code behavior when the activity relaunches due
to configuration change. It only applies to scenarios, where the
configuration change was triggered by a user generated resize of an
activity (i.e. user drags a corner of an activity and thus changes its
size).

Preserving a window means that we will keep the decor view and non
client decor view around, but remove all children views when the
activity gets destroyed. When the activity gets created again, it will
attach its new content to the preserved view hierarchy. Mind, we
actually recreate application side Window object, since some of its
features might changed, but we retain its elevation (to not trigger
relayout with new layout params).

Preserving the window also means that we don't call the window manager
service to remove and later add the window. Instead, we continue using a
single window state throughout the resize operation.

Change-Id: Ie3d2878ed09c99ff343044bfe7a29a0ba07a265e
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8ab4ae5..d3cea8d 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3045,7 +3045,7 @@
         stack.setBounds(bounds);
 
         if (r != null) {
-            final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
+            final boolean updated = stack.ensureActivityConfigurationLocked(r, 0, false);
             // And we need to make sure at this point that all other activities
             // are made visible with the correct configuration.
             ensureActivitiesVisibleLocked(r, 0);
@@ -3055,7 +3055,7 @@
         }
     }
 
-    void resizeTaskLocked(TaskRecord task, Rect bounds) {
+    void resizeTaskLocked(TaskRecord task, Rect bounds, boolean resizedByUser) {
         if (!task.mResizeable) {
             Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
             return;
@@ -3088,7 +3088,8 @@
                 && stackId != FREEFORM_WORKSPACE_STACK_ID && stackId != DOCKED_STACK_ID) {
             stackId = FREEFORM_WORKSPACE_STACK_ID;
         }
-        if (stackId != task.stack.mStackId) {
+        final boolean changedStacks = stackId != task.stack.mStackId;
+        if (changedStacks) {
             moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
         }
 
@@ -3101,20 +3102,22 @@
             ActivityRecord r = task.topRunningActivityLocked(null);
             if (r != null) {
                 final ActivityStack stack = task.stack;
-                kept = stack.ensureActivityConfigurationLocked(r, 0);
+                final boolean preserveWindow = resizedByUser && !changedStacks;
+                kept = stack.ensureActivityConfigurationLocked(r, 0, preserveWindow);
                 // All other activities must be made visible with their correct configuration.
                 ensureActivitiesVisibleLocked(r, 0);
                 if (!kept) {
                     resumeTopActivitiesLocked(stack, null, null);
-                    // We are about to relaunch the activity because its configuration changed due
-                    // to size change. The activity will first remove the old window and then add a
-                    // new one. This call will tell window manager about this, so it can preserve
-                    // the old window until the new one is drawn. This prevents having a gap between
-                    // the removal and addition, in which no window is visible. If we also changed
-                    // the stack to the fullscreen stack, i.e. maximized the window, we will animate
-                    // the transition.
-                    mWindowManager.setReplacingWindow(r.appToken,
-                            stackId == FULLSCREEN_WORKSPACE_STACK_ID /* animate */);
+                    if (changedStacks && stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+                        // We are about to relaunch the activity because its configuration changed
+                        // due to being maximized, i.e. size change. The activity will first
+                        // remove the old window and then add a new one. This call will tell window
+                        // manager about this, so it can preserve the old window until the new
+                        // one is drawn. This prevents having a gap between the removal and
+                        // addition, in which no window is visible. We also want the entrace of the
+                        // new window to be properly animated.
+                        mWindowManager.setReplacingWindow(r.appToken, true /* animate */);
+                    }
                 }
             }
         }
@@ -3240,12 +3243,12 @@
 
         // Make sure the task has the appropriate bounds/size for the stack it is in.
         if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
-            resizeTaskLocked(task, stack.mBounds);
+            resizeTaskLocked(task, stack.mBounds, false);
         } else if (stackId == FREEFORM_WORKSPACE_STACK_ID
                 && task.mBounds == null && task.mLastNonFullscreenBounds != null) {
-            resizeTaskLocked(task, task.mLastNonFullscreenBounds);
+            resizeTaskLocked(task, task.mLastNonFullscreenBounds, false);
         } else if (stackId == DOCKED_STACK_ID) {
-            resizeTaskLocked(task, stack.mBounds);
+            resizeTaskLocked(task, stack.mBounds, false);
         }
 
         // The task might have already been running and its visibility needs to be synchronized with