Fix bugs with takeSurface and preserveWindows.

When reusing a ViewRoot and DecorView as we do with preserveWindows
there are two issues with SurfaceHolders.  First, we update the
SurfaceHolder callbacks when we call ViewRootImpl.setView. In the
case of preserved window relaunch, the DecorView is reused and there is
no call to setView. We need the ActivityThread to notify the ViewRoot
that something has changed. Secondly, we were assuming the only time
a new surface would be created for the purposes of SurfaceHolder
notification was when we previously did not have a valid surface.
Instead we need to check if the native Surface object has changed each time we
get a result from relayout.

Bug: 28331264
Change-Id: If1b4aab9b2ba579fa040e2a3ab4471842476d82f
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1da21b0..0764ff4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3474,6 +3474,12 @@
                 if (r.mPreserveWindow) {
                     a.mWindowAdded = true;
                     r.mPreserveWindow = false;
+                    // Normally the ViewRoot sets up callbacks with the Activity
+                    // in addView->ViewRootImpl#setView. If we are instead reusing
+                    // the decor view we have to notify the view root that the
+                    // callbacks may have changed.
+                    ViewRootImpl impl = decor.getViewRootImpl();
+                    impl.notifyChildRebuilt();
                 }
                 if (a.mVisibleFromClient && !a.mWindowAdded) {
                     a.mWindowAdded = true;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9e4f26f..a0384f2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -514,6 +514,34 @@
     }
 
     /**
+     * Notifies us that our child has been rebuilt, following
+     * a window preservation operation. In these cases we
+     * keep the same DecorView, but the activity controlling it
+     * is a different instance, and we need to update our
+     * callbacks.
+     *
+     * @hide
+     */
+    public void notifyChildRebuilt() {
+        if (mView instanceof RootViewSurfaceTaker) {
+            mSurfaceHolderCallback =
+                ((RootViewSurfaceTaker)mView).willYouTakeTheSurface();
+            if (mSurfaceHolderCallback != null) {
+                mSurfaceHolder = new TakenSurfaceHolder();
+                mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
+            } else {
+                mSurfaceHolder = null;
+            }
+
+            mInputQueueCallback =
+                ((RootViewSurfaceTaker)mView).willYouTakeTheInputQueue();
+            if (mInputQueueCallback != null) {
+                mInputQueueCallback.onInputQueueCreated(mInputQueue);
+            }
+        }
+    }
+
+    /**
      * We have one child
      */
     public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
@@ -1645,6 +1673,8 @@
         boolean insetsPending = false;
         int relayoutResult = 0;
 
+        final int surfaceGenerationId = mSurface.getGenerationId();
+
         final boolean isViewVisible = viewVisibility == View.VISIBLE;
         if (mFirst || windowShouldResize || insetsChanged ||
                 viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
@@ -1689,7 +1719,6 @@
                     }
                     mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
                 }
-                final int surfaceGenerationId = mSurface.getGenerationId();
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
 
                 if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
@@ -1883,7 +1912,7 @@
                 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
                 mSurfaceHolder.mSurfaceLock.unlock();
                 if (mSurface.isValid()) {
-                    if (!hadSurface) {
+                    if (!hadSurface || surfaceGenerationId != mSurface.getGenerationId()) {
                         mSurfaceHolder.ungetCallbacks();
 
                         mIsCreating = true;