From b2594850870ba950067962d41c481f9bbfafeaf1 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 25 Apr 2016 16:21:13 -0700 Subject: [PATCH] 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 --- core/java/android/app/ActivityThread.java | 6 +++++ core/java/android/view/ViewRootImpl.java | 33 +++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 1da21b0dc5e7c..0764ff41efaf3 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3474,6 +3474,12 @@ public final class ActivityThread { 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 9e4f26fe0aece..a0384f2601d30 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -513,6 +513,34 @@ public final class ViewRootImpl implements ViewParent, return false; } + /** + * 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 */ @@ -1645,6 +1673,8 @@ public final class ViewRootImpl implements ViewParent, 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 @@ public final class ViewRootImpl implements ViewParent, } 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 @@ public final class ViewRootImpl implements ViewParent, mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight); mSurfaceHolder.mSurfaceLock.unlock(); if (mSurface.isValid()) { - if (!hadSurface) { + if (!hadSurface || surfaceGenerationId != mSurface.getGenerationId()) { mSurfaceHolder.ungetCallbacks(); mIsCreating = true;