Prepare to replace windows across recreate().

When the activity locally recreates itself, nothing
on the server side is able to prepare preserving windows,
or replacing windows. The activity was trying to defer
removing the old window, but it was just waiting
until the new one was created, not until it was drawn,
thus resulting in a flicker. It's easy to backpack on the
existing replacement infrastructure.

Bug: 28221875
Change-Id: I55fc4ca78e9e11809473fedd8b30b6a6350cf852
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6d805ed..8e58c38 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4208,7 +4208,7 @@
                 }
                 IBinder wtoken = v.getWindowToken();
                 if (r.activity.mWindowAdded) {
-                    if (r.onlyLocalRequest || r.mPreserveWindow) {
+                    if (r.mPreserveWindow) {
                         // Hold off on removing this until the new activity's
                         // window is being added.
                         r.mPendingRemoveWindow = r.window;
@@ -4443,15 +4443,20 @@
         // be replaced and defer requests to destroy or hide them. This way we can achieve
         // visual continuity. It's important that we do this here prior to pause and destroy
         // as that is when we may hide or remove the child views.
+        //
+        // There is another scenario, if we have decided locally to relaunch the app from a
+        // call to recreate, then none of the windows will be prepared for replacement or
+        // preserved by the server, so we want to notify it that we are preparing to replace
+        // everything
         try {
-            if (r.mPreserveWindow) {
-                WindowManagerGlobal.getWindowSession().prepareToReplaceChildren(r.token);
+            if (r.mPreserveWindow || r.onlyLocalRequest) {
+                WindowManagerGlobal.getWindowSession().prepareToReplaceWindows(
+                        r.token, !r.onlyLocalRequest);
             }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
 
-
         // Need to ensure state is saved.
         if (!r.paused) {
             performPauseActivity(r.token, false, r.isPreHoneycomb(), "handleRelaunchActivity");
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 8e1609c..1facc10 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -125,11 +125,13 @@
 
     /*
      * Notify the window manager that an application is relaunching and
-     * child windows should be prepared for replacement.
+     * windows should be prepared for replacement.
      *
      * @param appToken The application
+     * @param childrenOnly Whether to only prepare child windows for replacement
+     * (for example when main windows are being reused via preservation).
      */
-    void prepareToReplaceChildren(IBinder appToken);
+    void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly);
 
     /**
      * If a call to relayout() asked to have the surface destroy deferred,
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index daeb860..08c0a4b 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -201,8 +201,8 @@
     }
 
     @Override
-    public void prepareToReplaceChildren(IBinder appToken) {
-        mService.setReplacingChildren(appToken);
+    public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) {
+        mService.setReplacingWindows(appToken, childrenOnly);
     }
 
     public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 57f551c..a5d9bb2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -10677,12 +10677,16 @@
     }
 
     /**
-     * Hint to a token that its children will be replaced across activity relaunch.
-     * The children would otherwise be removed  shortly following this as the
+     * Hint to a token that its windows will be replaced across activity relaunch.
+     * The windows would otherwise be removed  shortly following this as the
      * activity is torn down.
      * @param token Application token for which the activity will be relaunched.
+     * @param childrenOnly Whether to mark only child windows for replacement
+     *                     (for the case where main windows are being preserved/
+     *                     reused rather than replaced).
+     *
      */
-    public void setReplacingChildren(IBinder token) {
+    public void setReplacingWindows(IBinder token, boolean childrenOnly) {
         AppWindowToken appWindowToken = null;
         synchronized (mWindowMap) {
             appWindowToken = findAppWindowToken(token);
@@ -10692,7 +10696,12 @@
                 return;
             }
 
-            appWindowToken.setReplacingChildren();
+            if (childrenOnly) {
+                appWindowToken.setReplacingChildren();
+            } else {
+                appWindowToken.setReplacingWindows(false /* animate */);
+            }
+
             scheduleClearReplacingWindowIfNeeded(token, true /* replacing */);
         }
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 5a6a00f..7582fda 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -233,7 +233,7 @@
     }
 
     @Override
-    public void prepareToReplaceChildren(IBinder appToken) {
+    public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) {
         // pass for now.
     }