Modify SurfaceView to use SurfaceFlinger child surfaces.

Here we have SurfaceView bypass the WindowManager and speak
directly to SurfaceFlinger using child surfaces. We also
implement some logic in the WM to handle child surfaces
in various Surface replacement scenarios.

For those following along in the revert Saga, this
also includes the follow up CLs to the original CL.
- Surface inset calculation
- Animation fixes.

The error causing the revert was an incorrect JNI signature
around deferTransactionUntilSurface. I've noted it inline.

Bug: 28858420
Bug: 31518219
Bug: 34888808
Bug: 35588318
Bug: 35396882
Test: Existing tests still pass (except for the ones that don't and will be deleted).
Change-Id: Ie56b6f7ab16f32d7fc459b8eba26594337ad55de
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b718696..519c1e2 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -95,6 +95,11 @@
             IBinder displayToken, int mode);
     private static native void nativeDeferTransactionUntil(long nativeObject,
             IBinder handle, long frame);
+    private static native void nativeDeferTransactionUntilSurface(long nativeObject,
+            long surfaceObject, long frame);
+    private static native void nativeReparentChildren(long nativeObject,
+            IBinder handle);
+    private static native void nativeSeverChildren(long nativeObject);
     private static native void nativeSetOverrideScalingMode(long nativeObject,
             int scalingMode);
     private static native IBinder nativeGetHandle(long nativeObject);
@@ -418,7 +423,23 @@
     }
 
     public void deferTransactionUntil(IBinder handle, long frame) {
-        nativeDeferTransactionUntil(mNativeObject, handle, frame);
+        if (frame > 0) {
+            nativeDeferTransactionUntil(mNativeObject, handle, frame);
+        }
+    }
+
+    public void deferTransactionUntil(Surface barrier, long frame) {
+        if (frame > 0) {
+            nativeDeferTransactionUntilSurface(mNativeObject, barrier.mNativeObject, frame);
+        }
+    }
+
+    public void reparentChildren(IBinder newParentHandle) {
+        nativeReparentChildren(mNativeObject, newParentHandle);
+    }
+
+    public void detachChildren() {
+        nativeSeverChildren(mNativeObject);
     }
 
     public void setOverrideScalingMode(int scalingMode) {
diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java
index 3cf5af4..b5912bc 100644
--- a/core/java/android/view/SurfaceSession.java
+++ b/core/java/android/view/SurfaceSession.java
@@ -27,6 +27,7 @@
     private long mNativeClient; // SurfaceComposerClient*
 
     private static native long nativeCreate();
+    private static native long nativeCreateScoped(long surfacePtr);
     private static native void nativeDestroy(long ptr);
     private static native void nativeKill(long ptr);
 
@@ -35,6 +36,10 @@
         mNativeClient = nativeCreate();
     }
 
+    public SurfaceSession(Surface root) {
+        mNativeClient = nativeCreateScoped(root.mNativeObject);
+    }
+
     /* no user serviceable parts here ... */
     @Override
     protected void finalize() throws Throwable {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d2577d4..61b1247 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,6 +16,10 @@
 
 package android.view;
 
+import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
+import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
+import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER;
+
 import android.content.Context;
 import android.content.res.CompatibilityInfo.Translator;
 import android.content.res.Configuration;
@@ -26,16 +30,12 @@
 import android.graphics.Region;
 import android.os.Handler;
 import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.util.Log;
 
-import com.android.internal.view.BaseIWindow;
 import com.android.internal.view.SurfaceCallbackHelper;
 
-import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -92,8 +92,8 @@
  * positioned asynchronously.</p>
  */
 public class SurfaceView extends View {
-    static private final String TAG = "SurfaceView";
-    static private final boolean DEBUG = false;
+    private static final String TAG = "SurfaceView";
+    private static final boolean DEBUG = false;
 
     final ArrayList<SurfaceHolder.Callback> mCallbacks
             = new ArrayList<SurfaceHolder.Callback>();
@@ -102,28 +102,23 @@
 
     final ReentrantLock mSurfaceLock = new ReentrantLock();
     final Surface mSurface = new Surface();       // Current surface in use
-    final Surface mNewSurface = new Surface();    // New surface we are switching to
     boolean mDrawingStopped = true;
+    // We use this to track if the application has produced a frame
+    // in to the Surface. Up until that point, we should be careful not to punch
+    // holes.
+    boolean mDrawFinished = false;
 
-    final WindowManager.LayoutParams mLayout
-            = new WindowManager.LayoutParams();
-    IWindowSession mSession;
-    MyWindow mWindow;
-    final Rect mVisibleInsets = new Rect();
-    final Rect mWinFrame = new Rect();
-    final Rect mOverscanInsets = new Rect();
-    final Rect mContentInsets = new Rect();
-    final Rect mStableInsets = new Rect();
-    final Rect mOutsets = new Rect();
-    final Rect mBackdropFrame = new Rect();
+    final Rect mScreenRect = new Rect();
+    SurfaceSession mSurfaceSession;
+
+    SurfaceControl mSurfaceControl;
     final Rect mTmpRect = new Rect();
     final Configuration mConfiguration = new Configuration();
 
     static final int KEEP_SCREEN_ON_MSG = 1;
-    static final int GET_NEW_SURFACE_MSG = 2;
-    static final int UPDATE_WINDOW_MSG = 3;
+    static final int DRAW_FINISHED_MSG = 2;
 
-    int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+    int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
 
     boolean mIsCreating = false;
     private volatile boolean mRtHandlingPositionUpdates = false;
@@ -135,11 +130,9 @@
                 case KEEP_SCREEN_ON_MSG: {
                     setKeepScreenOn(msg.arg1 != 0);
                 } break;
-                case GET_NEW_SURFACE_MSG: {
-                    handleGetNewSurface();
-                } break;
-                case UPDATE_WINDOW_MSG: {
-                    updateWindow();
+                case DRAW_FINISHED_MSG: {
+                    mDrawFinished = true;
+                    invalidate();
                 } break;
             }
         }
@@ -149,7 +142,7 @@
             = new ViewTreeObserver.OnScrollChangedListener() {
                     @Override
                     public void onScrollChanged() {
-                        updateWindow();
+                        updateSurface();
                     }
             };
 
@@ -159,13 +152,14 @@
                 public boolean onPreDraw() {
                     // reposition ourselves where the surface is
                     mHaveFrame = getWidth() > 0 && getHeight() > 0;
-                    updateWindow();
+                    updateSurface();
                     return true;
                 }
             };
 
     boolean mRequestedVisible = false;
     boolean mWindowVisibility = false;
+    boolean mLastWindowVisibility = false;
     boolean mViewVisibility = false;
     int mRequestedWidth = -1;
     int mRequestedHeight = -1;
@@ -181,19 +175,17 @@
     boolean mVisible = false;
     int mWindowSpaceLeft = -1;
     int mWindowSpaceTop = -1;
-    int mWindowSpaceWidth = -1;
-    int mWindowSpaceHeight = -1;
+    int mSurfaceWidth = -1;
+    int mSurfaceHeight = -1;
     int mFormat = -1;
     final Rect mSurfaceFrame = new Rect();
     int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
-    boolean mUpdateWindowNeeded;
-    boolean mReportDrawNeeded;
     private Translator mTranslator;
-    private int mWindowInsetLeft;
-    private int mWindowInsetTop;
 
     private boolean mGlobalListenersAdded;
 
+    private int mSurfaceFlags = SurfaceControl.HIDDEN;
+
     public SurfaceView(Context context) {
         this(context, null);
     }
@@ -227,11 +219,8 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mParent.requestTransparentRegion(this);
-        mSession = getWindowSession();
-        mLayout.token = getWindowToken();
-        mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
-        mLayout.packageName = mContext.getOpPackageName();
         mViewVisibility = getVisibility() == VISIBLE;
+        mRequestedVisible = mViewVisibility && mWindowVisibility;
 
         if (!mGlobalListenersAdded) {
             ViewTreeObserver observer = getViewTreeObserver();
@@ -246,7 +235,7 @@
         super.onWindowVisibilityChanged(visibility);
         mWindowVisibility = visibility == VISIBLE;
         mRequestedVisible = mWindowVisibility && mViewVisibility;
-        updateWindow();
+        updateSurface();
     }
 
     @Override
@@ -264,7 +253,7 @@
             requestLayout();
         }
         mRequestedVisible = newRequestedVisible;
-        updateWindow();
+        updateSurface();
     }
 
     @Override
@@ -277,19 +266,14 @@
         }
 
         mRequestedVisible = false;
-        updateWindow();
-        mHaveFrame = false;
-        if (mWindow != null) {
-            try {
-                mSession.remove(mWindow);
-            } catch (RemoteException ex) {
-                // Not much we can do here...
-            }
-            mWindow = null;
-        }
-        mSession = null;
-        mLayout.token = null;
 
+        updateSurface();
+        if (mSurfaceControl != null) {
+            mSurfaceControl.destroy();
+        }
+        mSurfaceControl = null;
+
+        mHaveFrame = false;
         super.onDetachedFromWindow();
     }
 
@@ -308,13 +292,13 @@
     @Override
     protected boolean setFrame(int left, int top, int right, int bottom) {
         boolean result = super.setFrame(left, top, right, bottom);
-        updateWindow();
+        updateSurface();
         return result;
     }
 
     @Override
     public boolean gatherTransparentRegion(Region region) {
-        if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+        if (isAboveParent()) {
             return super.gatherTransparentRegion(region);
         }
 
@@ -341,7 +325,7 @@
 
     @Override
     public void draw(Canvas canvas) {
-        if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+        if (mDrawFinished && !isAboveParent()) {
             // draw() is not called when SKIP_DRAW is set
             if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
                 // punch a whole in the view-hierarchy below us
@@ -353,8 +337,8 @@
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
-            // if SKIP_DRAW is cleared, draw() has already punched a hole
+        if (mDrawFinished && !isAboveParent()) {
+            // draw() is not called when SKIP_DRAW is set
             if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                 // punch a whole in the view-hierarchy below us
                 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
@@ -375,9 +359,8 @@
      * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
      */
     public void setZOrderMediaOverlay(boolean isMediaOverlay) {
-        mWindowType = isMediaOverlay
-                ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
-                : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+        mSubLayer = isMediaOverlay
+            ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
     }
 
     /**
@@ -395,12 +378,9 @@
      */
     public void setZOrderOnTop(boolean onTop) {
         if (onTop) {
-            mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-            // ensures the surface is placed below the IME
-            mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            mSubLayer = APPLICATION_PANEL_SUBLAYER;
         } else {
-            mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
-            mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+            mSubLayer = APPLICATION_MEDIA_SUBLAYER;
         }
     }
 
@@ -418,31 +398,32 @@
      */
     public void setSecure(boolean isSecure) {
         if (isSecure) {
-            mLayout.flags |= WindowManager.LayoutParams.FLAG_SECURE;
+            mSurfaceFlags |= SurfaceControl.SECURE;
         } else {
-            mLayout.flags &= ~WindowManager.LayoutParams.FLAG_SECURE;
+            mSurfaceFlags &= ~SurfaceControl.SECURE;
         }
     }
 
-    /**
-     * Hack to allow special layering of windows.  The type is one of the
-     * types in WindowManager.LayoutParams.  This is a hack so:
-     * @hide
-     */
-    public void setWindowType(int type) {
-        mWindowType = type;
+    private Rect getParentSurfaceInsets() {
+        final ViewRootImpl root = getViewRootImpl();
+        if (root == null) {
+            return null;
+        } else {
+            return root.mWindowAttributes.surfaceInsets;
+        }
     }
 
     /** @hide */
-    protected void updateWindow() {
+    protected void updateSurface() {
         if (!mHaveFrame) {
             return;
         }
         ViewRootImpl viewRoot = getViewRootImpl();
-        if (viewRoot != null) {
-            mTranslator = viewRoot.mTranslator;
+        if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
+            return;
         }
 
+        mTranslator = viewRoot.mTranslator;
         if (mTranslator != null) {
             mSurface.setCompatibilityTranslator(mTranslator);
         }
@@ -452,17 +433,15 @@
         int myHeight = mRequestedHeight;
         if (myHeight <= 0) myHeight = getHeight();
 
-        final boolean creating = mWindow == null;
         final boolean formatChanged = mFormat != mRequestedFormat;
-        final boolean sizeChanged = mWindowSpaceWidth != myWidth || mWindowSpaceHeight != myHeight;
+        final boolean creating = (mSurfaceControl == null || formatChanged)
+                && mRequestedVisible;
+        final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
         final boolean visibleChanged = mVisible != mRequestedVisible;
-        final boolean layoutSizeChanged = getWidth() != mLayout.width
-                || getHeight() != mLayout.height;
-
+        final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
         boolean redrawNeeded = false;
 
-        if (creating || formatChanged || sizeChanged || visibleChanged
-            || mUpdateWindowNeeded || mReportDrawNeeded) {
+        if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
             getLocationInWindow(mLocation);
 
             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
@@ -476,93 +455,77 @@
                 final boolean visible = mVisible = mRequestedVisible;
                 mWindowSpaceLeft = mLocation[0];
                 mWindowSpaceTop = mLocation[1];
-                mWindowSpaceWidth = myWidth;
-                mWindowSpaceHeight = myHeight;
+                mSurfaceWidth = myWidth;
+                mSurfaceHeight = myHeight;
                 mFormat = mRequestedFormat;
+                mLastWindowVisibility = mWindowVisibility;
 
-                // Scaling/Translate window's layout here because mLayout is not used elsewhere.
-
-                // Places the window relative
-                mLayout.x = mWindowSpaceLeft;
-                mLayout.y = mWindowSpaceTop;
-                mLayout.width = getWidth();
-                mLayout.height = getHeight();
+                mScreenRect.left = mWindowSpaceLeft;
+                mScreenRect.top = mWindowSpaceTop;
+                mScreenRect.right = mWindowSpaceLeft + getWidth();
+                mScreenRect.bottom = mWindowSpaceTop + getHeight();
                 if (mTranslator != null) {
-                    mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
+                    mTranslator.translateRectInAppWindowToScreen(mScreenRect);
                 }
 
-                mLayout.format = mRequestedFormat;
-                mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                              | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                              | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                              | WindowManager.LayoutParams.FLAG_SCALED
-                              | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                              | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                              ;
-                if (!creating && !sizeChanged) {
-                    mLayout.privateFlags |=
-                            WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
-                } else {
-                    mLayout.privateFlags &=
-                            ~WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
+                final Rect surfaceInsets = getParentSurfaceInsets();
+                mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
+
+                if (creating) {
+                    mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
+                    mSurfaceControl = new SurfaceControl(mSurfaceSession,
+                            "SurfaceView - " + viewRoot.getTitle().toString(),
+                            mSurfaceWidth, mSurfaceHeight, mFormat,
+                            mSurfaceFlags);
                 }
 
-                if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
-                    mLayout.privateFlags |=
-                            WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-                }
-                mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
-                    | WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
-
-                if (mWindow == null) {
-                    Display display = getDisplay();
-                    mWindow = new MyWindow(this);
-                    mLayout.type = mWindowType;
-                    mLayout.gravity = Gravity.START|Gravity.TOP;
-                    mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
-                            mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets,
-                            mStableInsets);
-                }
-
-                boolean realSizeChanged;
-                boolean reportDrawNeeded;
-
-                int relayoutResult;
+                boolean realSizeChanged = false;
 
                 mSurfaceLock.lock();
                 try {
-                    mUpdateWindowNeeded = false;
-                    reportDrawNeeded = mReportDrawNeeded;
-                    mReportDrawNeeded = false;
                     mDrawingStopped = !visible;
 
                     if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
                             + "Cur surface: " + mSurface);
 
-                    relayoutResult = mSession.relayout(
-                        mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight,
-                            visible ? VISIBLE : GONE,
-                            WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
-                            mWinFrame, mOverscanInsets, mContentInsets,
-                            mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
-                            mConfiguration, mNewSurface);
-                    if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
-                        reportDrawNeeded = true;
+                    SurfaceControl.openTransaction();
+                    try {
+                        mSurfaceControl.setLayer(mSubLayer);
+                        if (mViewVisibility) {
+                            mSurfaceControl.show();
+                        } else {
+                            mSurfaceControl.hide();
+                        }
+
+                        // While creating the surface, we will set it's initial
+                        // geometry. Outside of that though, we should generally
+                        // leave it to the RenderThread.
+                        if (creating || !mRtHandlingPositionUpdates) {
+                            mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
+                            mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
+                                    0.0f, 0.0f,
+                                    mScreenRect.height() / (float) mSurfaceHeight);
+                        }
+                        if (sizeChanged) {
+                            mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight);
+                        }
+                    } finally {
+                        SurfaceControl.closeTransaction();
                     }
 
-                    if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
-                            + "New surface: " + mNewSurface
-                            + ", vis=" + visible + ", frame=" + mWinFrame);
+                    if (sizeChanged || creating) {
+                        redrawNeeded = true;
+                    }
 
                     mSurfaceFrame.left = 0;
                     mSurfaceFrame.top = 0;
                     if (mTranslator == null) {
-                        mSurfaceFrame.right = mWinFrame.width();
-                        mSurfaceFrame.bottom = mWinFrame.height();
+                        mSurfaceFrame.right = mSurfaceWidth;
+                        mSurfaceFrame.bottom = mSurfaceHeight;
                     } else {
                         float appInvertedScale = mTranslator.applicationInvertedScale;
-                        mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
-                        mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
+                        mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
+                        mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
                     }
 
                     final int surfaceWidth = mSurfaceFrame.right;
@@ -576,12 +539,11 @@
                 }
 
                 try {
-                    redrawNeeded |= creating | reportDrawNeeded;
+                    redrawNeeded |= visible && !mDrawFinished;
 
                     SurfaceHolder.Callback callbacks[] = null;
 
-                    final boolean surfaceChanged = (relayoutResult
-                            & WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0;
+                    final boolean surfaceChanged = creating;
                     if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
                         mSurfaceCreated = false;
                         if (mSurface.isValid()) {
@@ -608,7 +570,10 @@
                         }
                     }
 
-                    mSurface.transferFrom(mNewSurface);
+                    if (creating) {
+                        mSurface.copyFrom(mSurfaceControl);
+                    }
+
                     if (visible && mSurface.isValid()) {
                         if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
                             mSurfaceCreated = true;
@@ -641,53 +606,55 @@
                                 callbacks = getSurfaceCallbacks();
                             }
                             SurfaceCallbackHelper sch =
-                                    new SurfaceCallbackHelper(mSession, mWindow);
+                                    new SurfaceCallbackHelper(this::onDrawFinished);
                             sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
                         }
                     }
                 } finally {
                     mIsCreating = false;
-                    mSession.performDeferredDestroy(mWindow);
+                    if (mSurfaceControl != null && !mSurfaceCreated) {
+                        mSurfaceControl.destroy();
+                        mSurfaceControl = null;
+                    }
                 }
-            } catch (RemoteException ex) {
+            } catch (Exception ex) {
                 Log.e(TAG, "Exception from relayout", ex);
             }
             if (DEBUG) Log.v(
-                TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
-                " w=" + mLayout.width + " h=" + mLayout.height +
-                ", frame=" + mSurfaceFrame);
+                TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
+                + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
+                + ", frame=" + mSurfaceFrame);
         } else {
             // Calculate the window position in case RT loses the window
             // and we need to fallback to a UI-thread driven position update
-            getLocationInWindow(mLocation);
+            getLocationInSurface(mLocation);
             final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
                     || mWindowSpaceTop != mLocation[1];
+            final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
+                    || getHeight() != mScreenRect.height();
             if (positionChanged || layoutSizeChanged) { // Only the position has changed
                 mWindowSpaceLeft = mLocation[0];
                 mWindowSpaceTop = mLocation[1];
-                // For our size changed check, we keep mLayout.width and mLayout.height
+                // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
                 // in view local space.
-                mLocation[0] = mLayout.width = getWidth();
-                mLocation[1] = mLayout.height = getHeight();
+                mLocation[0] = getWidth();
+                mLocation[1] = getHeight();
 
-                transformFromViewToWindowSpace(mLocation);
-
-                mTmpRect.set(mWindowSpaceLeft, mWindowSpaceTop,
+                mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
                         mLocation[0], mLocation[1]);
 
                 if (mTranslator != null) {
-                    mTranslator.translateRectInAppWindowToScreen(mTmpRect);
+                    mTranslator.translateRectInAppWindowToScreen(mScreenRect);
                 }
 
                 if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
                     try {
-                        if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition UI, " +
+                        if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
                                 "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
-                                mTmpRect.left, mTmpRect.top,
-                                mTmpRect.right, mTmpRect.bottom));
-                        mSession.repositionChild(mWindow, mTmpRect.left, mTmpRect.top,
-                                mTmpRect.right, mTmpRect.bottom, -1, mTmpRect);
-                    } catch (RemoteException ex) {
+                                mScreenRect.left, mScreenRect.top,
+                                mScreenRect.right, mScreenRect.bottom));
+                        setParentSpaceRectangle(mScreenRect, -1);
+                    } catch (Exception ex) {
                         Log.e(TAG, "Exception from relayout", ex);
                     }
                 }
@@ -695,20 +662,43 @@
         }
     }
 
+    private void onDrawFinished() {
+        if (DEBUG) {
+            Log.i(TAG, System.identityHashCode(this) + " "
+                    + "finishedDrawing");
+        }
+        mHandler.sendEmptyMessage(DRAW_FINISHED_MSG);
+    }
+
+    private void setParentSpaceRectangle(Rect position, long frameNumber) {
+        ViewRootImpl viewRoot = getViewRootImpl();
+
+        SurfaceControl.openTransaction();
+        try {
+            if (frameNumber > 0) {
+                mSurfaceControl.deferTransactionUntil(viewRoot.mSurface, frameNumber);
+            }
+            mSurfaceControl.setPosition(position.left, position.top);
+            mSurfaceControl.setMatrix(position.width() / (float) mSurfaceWidth,
+                    0.0f, 0.0f,
+                    position.height() / (float) mSurfaceHeight);
+        } finally {
+            SurfaceControl.closeTransaction();
+        }
+    }
+
     private Rect mRTLastReportedPosition = new Rect();
 
     /**
      * Called by native by a Rendering Worker thread to update the window position
      * @hide
      */
-    public final void updateWindowPosition_renderWorker(long frameNumber,
+    public final void updateSurfacePosition_renderWorker(long frameNumber,
             int left, int top, int right, int bottom) {
-        IWindowSession session = mSession;
-        MyWindow window = mWindow;
-        if (session == null || window == null) {
-            // Guess we got detached, that sucks
+        if (mSurfaceControl == null) {
             return;
         }
+
         // TODO: This is teensy bit racey in that a brand new SurfaceView moving on
         // its 2nd frame if RenderThread is running slowly could potentially see
         // this as false, enter the branch, get pre-empted, then this comes along
@@ -726,35 +716,29 @@
         }
         try {
             if (DEBUG) {
-                Log.d(TAG, String.format("%d updateWindowPosition RenderWorker, frameNr = %d, " +
+                Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " +
                         "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
                         frameNumber, left, top, right, bottom));
             }
-            // Just using mRTLastReportedPosition as a dummy rect here
-            session.repositionChild(window, left, top, right, bottom,
-                    frameNumber,
-                    mRTLastReportedPosition);
-            // Now overwrite mRTLastReportedPosition with our values
             mRTLastReportedPosition.set(left, top, right, bottom);
-        } catch (RemoteException ex) {
+            setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
+            // Now overwrite mRTLastReportedPosition with our values
+        } catch (Exception ex) {
             Log.e(TAG, "Exception from repositionChild", ex);
         }
     }
 
     /**
-     * Called by native on RenderThread to notify that the window is no longer in the
+     * Called by native on RenderThread to notify that the view is no longer in the
      * draw tree. UI thread is blocked at this point.
      * @hide
      */
-    public final void windowPositionLost_uiRtSync(long frameNumber) {
+    public final void surfacePositionLost_uiRtSync(long frameNumber) {
         if (DEBUG) {
             Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
                     System.identityHashCode(this), frameNumber));
         }
-        IWindowSession session = mSession;
-        MyWindow window = mWindow;
-        if (session == null || window == null) {
-            // We got detached prior to receiving this, abort
+        if (mSurfaceControl == null) {
             return;
         }
         if (mRtHandlingPositionUpdates) {
@@ -763,19 +747,14 @@
             // safely access other member variables at this time.
             // So do what the UI thread would have done if RT wasn't handling position
             // updates.
-            mTmpRect.set(mLayout.x, mLayout.y,
-                    mLayout.x + mLayout.width,
-                    mLayout.y + mLayout.height);
-
-            if (!mTmpRect.isEmpty() && !mTmpRect.equals(mRTLastReportedPosition)) {
+            if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
                 try {
-                    if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition, " +
+                    if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " +
                             "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
-                            mTmpRect.left, mTmpRect.top,
-                            mTmpRect.right, mTmpRect.bottom));
-                    session.repositionChild(window, mTmpRect.left, mTmpRect.top,
-                            mTmpRect.right, mTmpRect.bottom, frameNumber, mWinFrame);
-                } catch (RemoteException ex) {
+                            mScreenRect.left, mScreenRect.top,
+                            mScreenRect.right, mScreenRect.bottom));
+                    setParentSpaceRectangle(mScreenRect, frameNumber);
+                } catch (Exception ex) {
                     Log.e(TAG, "Exception from relayout", ex);
                 }
             }
@@ -792,10 +771,6 @@
         return callbacks;
     }
 
-    void handleGetNewSurface() {
-        updateWindow();
-    }
-
     /**
      * Check to see if the surface has fixed size dimensions or if the surface's
      * dimensions are dimensions are dependent on its current layout.
@@ -807,65 +782,8 @@
         return (mRequestedWidth != -1 || mRequestedHeight != -1);
     }
 
-    private static class MyWindow extends BaseIWindow {
-        private final WeakReference<SurfaceView> mSurfaceView;
-
-        public MyWindow(SurfaceView surfaceView) {
-            mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
-        }
-
-        @Override
-        public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
-                Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-                Configuration newConfig, Rect backDropRect, boolean forceLayout,
-                boolean alwaysConsumeNavBar, int displayId) {
-            SurfaceView surfaceView = mSurfaceView.get();
-            if (surfaceView != null) {
-                if (DEBUG) Log.v(TAG, surfaceView + " got resized: w=" + frame.width()
-                        + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);
-                surfaceView.mSurfaceLock.lock();
-                try {
-                    if (reportDraw) {
-                        surfaceView.mUpdateWindowNeeded = true;
-                        surfaceView.mReportDrawNeeded = true;
-                        surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
-                    } else if (surfaceView.mWinFrame.width() != frame.width()
-                            || surfaceView.mWinFrame.height() != frame.height()
-                            || forceLayout) {
-                        surfaceView.mUpdateWindowNeeded = true;
-                        surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
-                    }
-                } finally {
-                    surfaceView.mSurfaceLock.unlock();
-                }
-            }
-        }
-
-        @Override
-        public void dispatchAppVisibility(boolean visible) {
-            // The point of SurfaceView is to let the app control the surface.
-        }
-
-        @Override
-        public void dispatchGetNewSurface() {
-            SurfaceView surfaceView = mSurfaceView.get();
-            if (surfaceView != null) {
-                Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
-                surfaceView.mHandler.sendMessage(msg);
-            }
-        }
-
-        @Override
-        public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
-            Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
-        }
-
-        @Override
-        public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
-        }
-
-        int mCurWidth = -1;
-        int mCurHeight = -1;
+    private boolean isAboveParent() {
+        return mSubLayer >= 0;
     }
 
     private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
@@ -913,15 +831,14 @@
 
         @Override
         public void setFormat(int format) {
-
             // for backward compatibility reason, OPAQUE always
             // means 565 for SurfaceView
             if (format == PixelFormat.OPAQUE)
                 format = PixelFormat.RGB_565;
 
             mRequestedFormat = format;
-            if (mWindow != null) {
-                updateWindow();
+            if (mSurfaceControl != null) {
+                updateSurface();
             }
         }
 
@@ -982,10 +899,10 @@
             mSurfaceLock.lock();
 
             if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
-                    + mDrawingStopped + ", win=" + mWindow);
+                    + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
 
             Canvas c = null;
-            if (!mDrawingStopped && mWindow != null) {
+            if (!mDrawingStopped && mSurfaceControl != null) {
                 try {
                     if (hardware) {
                         c = mSurface.lockHardwareCanvas();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 20d960f..f9863b0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2632,6 +2632,14 @@
         }
     }
 
+    private void onDrawFinished() {
+        try {
+            mWindowSession.finishDrawing(mWindow);
+        } catch (RemoteException e) {
+            // Have fun!
+        }
+    }
+
     private void performDraw() {
         if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
             return;
@@ -2682,7 +2690,7 @@
             }
 
             if (mSurfaceHolder != null && mSurface.isValid()) {
-                SurfaceCallbackHelper sch = new SurfaceCallbackHelper(mWindowSession, mWindow);
+                SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::onDrawFinished);
                 SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
 
                 sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
diff --git a/core/java/com/android/internal/view/SurfaceCallbackHelper.java b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
index 5b6a82c..507b673 100644
--- a/core/java/com/android/internal/view/SurfaceCallbackHelper.java
+++ b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
@@ -17,14 +17,11 @@
 package com.android.internal.view;
 
 import android.os.RemoteException;
-import android.view.IWindow;
-import android.view.IWindowSession;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 
 public class SurfaceCallbackHelper {
-    IWindowSession mSession;
-    IWindow.Stub mWindow;
+    Runnable mRunnable;
 
     int mFinishDrawingCollected = 0;
     int mFinishDrawingExpected = 0;
@@ -37,26 +34,18 @@
                     if (mFinishDrawingCollected < mFinishDrawingExpected) {
                         return;
                     }
-                    try {
-                        mSession.finishDrawing(mWindow);
-                    } catch (RemoteException e) {
-                    }
+                    mRunnable.run();
                 }
             }
     };
 
-    public SurfaceCallbackHelper(IWindowSession session,
-            IWindow.Stub window) {
-        mSession = session;
-        mWindow = window;
+    public SurfaceCallbackHelper(Runnable callbacksCollected) {
+        mRunnable = callbacksCollected;
     }
 
     public void dispatchSurfaceRedrawNeededAsync(SurfaceHolder holder, SurfaceHolder.Callback callbacks[]) {
         if (callbacks == null || callbacks.length == 0) {
-            try {
-                mSession.finishDrawing(mWindow);
-            } catch (RemoteException e) {
-            }
+            mRunnable.run();
             return;
         }
 
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index f221392..6e8c931 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -452,10 +452,6 @@
             const RenderProperties& props = node.properties();
             uirenderer::Rect bounds(props.getWidth(), props.getHeight());
             transform.mapRect(bounds);
-            bounds.left -= info.windowInsetLeft;
-            bounds.right -= info.windowInsetLeft;
-            bounds.top -= info.windowInsetTop;
-            bounds.bottom -= info.windowInsetTop;
 
             if (CC_LIKELY(transform.isPureTranslate())) {
                 // snap/round the computed bounds, so they match the rounding behavior
@@ -627,9 +623,9 @@
 int register_android_view_RenderNode(JNIEnv* env) {
     jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
     gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
-            "updateWindowPosition_renderWorker", "(JIIII)V");
+            "updateSurfacePosition_renderWorker", "(JIIII)V");
     gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
-            "windowPositionLost_uiRtSync", "(J)V");
+            "surfacePositionLost_uiRtSync", "(J)V");
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a81901d..6fbf49b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -693,7 +693,6 @@
     return JNI_TRUE;
 }
 
-
 static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeObject,
         jobject handleObject, jlong frameNumber) {
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
@@ -702,6 +701,27 @@
     ctrl->deferTransactionUntil(handle, frameNumber);
 }
 
+static void nativeDeferTransactionUntilSurface(JNIEnv* env, jclass clazz, jlong nativeObject,
+        jlong surfaceObject, jlong frameNumber) {
+    auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    sp<Surface> barrier = reinterpret_cast<Surface *>(surfaceObject);
+
+    ctrl->deferTransactionUntil(barrier, frameNumber);
+}
+
+static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong nativeObject,
+        jobject newParentObject) {
+    auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    sp<IBinder> handle = ibinderForJavaObject(env, newParentObject);
+
+    ctrl->reparentChildren(handle);
+}
+
+static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong nativeObject) {
+    auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    ctrl->detachChildren();
+}
+
 static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong nativeObject,
         jint scalingMode) {
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
@@ -824,6 +844,12 @@
             (void*)nativeSetDisplayPowerMode },
     {"nativeDeferTransactionUntil", "(JLandroid/os/IBinder;J)V",
             (void*)nativeDeferTransactionUntil },
+    {"nativeDeferTransactionUntilSurface", "(JJJ)V",
+            (void*)nativeDeferTransactionUntilSurface },
+    {"nativeReparentChildren", "(JLandroid/os/IBinder;)V",
+            (void*)nativeReparentChildren } ,
+    {"nativeSeverChildren", "(J)V",
+            (void*)nativeSeverChildren } ,
     {"nativeSetOverrideScalingMode", "(JI)V",
             (void*)nativeSetOverrideScalingMode },
     {"nativeGetHandle", "(J)Landroid/os/IBinder;",
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index dad6958..508d897 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -24,6 +24,7 @@
 #include <utils/RefBase.h>
 
 #include <gui/SurfaceComposerClient.h>
+#include <gui/Surface.h>
 
 namespace android {
 
@@ -45,6 +46,13 @@
     return reinterpret_cast<jlong>(client);
 }
 
+static jlong nativeCreateScoped(JNIEnv* env, jclass clazz, jlong surfaceObject) {
+    Surface *parent = reinterpret_cast<Surface*>(surfaceObject);
+    SurfaceComposerClient* client = new SurfaceComposerClient(parent->getIGraphicBufferProducer());
+    client->incStrong((void*)nativeCreate);
+    return reinterpret_cast<jlong>(client);
+}
+
 static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
     SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
     client->decStrong((void*)nativeCreate);
@@ -55,11 +63,12 @@
     client->dispose();
 }
 
-
 static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeCreate", "()J",
             (void*)nativeCreate },
+    { "nativeCreateScoped", "(J)J",
+            (void*)nativeCreateScoped },
     { "nativeDestroy", "(J)V",
             (void*)nativeDestroy },
     { "nativeKill", "(J)V",
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 37eae48a..99edf6e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -178,13 +178,9 @@
             }
         }
         // TODO: This is hacky
-        info.windowInsetLeft = -stagingProperties().getLeft();
-        info.windowInsetTop = -stagingProperties().getTop();
         info.updateWindowPositions = true;
         RenderNode::prepareTree(info);
         info.updateWindowPositions = false;
-        info.windowInsetLeft = 0;
-        info.windowInsetTop = 0;
         info.errorHandler = nullptr;
     }
 
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index c6fbe2b..e39614b 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -91,8 +91,6 @@
     LayerUpdateQueue* layerUpdateQueue = nullptr;
     ErrorHandler* errorHandler = nullptr;
 
-    int32_t windowInsetLeft = 0;
-    int32_t windowInsetTop = 0;
     bool updateWindowPositions = false;
 
     struct Out {
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index aee9d38e..e5af357 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -776,8 +776,8 @@
         mSurface = null;
         mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) {
             @Override
-            protected void updateWindow() {
-                super.updateWindow();
+            protected void updateSurface() {
+                super.updateSurface();
                 relayoutSessionOverlayView();
             }};
         // The surface view's content should be treated as secure all the time.
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 647adbf..4aa013a 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -785,6 +785,16 @@
         if (canFreezeBounds()) {
             freezeBounds();
         }
+
+        // In the process of tearing down before relaunching, the app will
+        // try and clean up it's child surfaces. We need to prevent this from
+        // happening, so we sever the children, transfering their ownership
+        // from the client it-self to the parent surface (owned by us).
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowState w = mChildren.get(i);
+            w.mWinAnimator.detachChildren();
+        }
+
         mPendingRelaunchCount++;
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8b62236..66ec8f0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2199,6 +2199,15 @@
         if (mAccessibilityController != null && win.getDisplayId() == DEFAULT_DISPLAY) {
             mAccessibilityController.onWindowTransitionLocked(win, transit);
         }
+
+        // When we start the exit animation we take the Surface from the client
+        // so it will stop perturbing it. We need to likewise takeaway the SurfaceFlinger
+        // side child surfaces, so they will remain preserved in their current state
+        // (rather than be cleaned up immediately by the app code).
+        SurfaceControl.openTransaction();
+        winAnimator.detachChildren();
+        SurfaceControl.closeTransaction();
+
         return focusMayChange;
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6d572d7..4806068 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1532,6 +1532,13 @@
             return changed;
         }
 
+        // Next up we will notify the client that it's visibility has changed.
+        // We need to prevent it from destroying child surfaces until
+        // the animation has finished.
+        if (!visible && isVisibleNow()) {
+            mWinAnimator.detachChildren();
+        }
+
         if (visible != isVisibleNow()) {
             if (!runningAppAnimation) {
                 final AccessibilityController accessibilityController =
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 98598e1..4b71338 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -566,6 +566,20 @@
         if (!mDestroyPreservedSurfaceUponRedraw) {
             return;
         }
+        if (mSurfaceController != null) {
+            if (mPendingDestroySurface != null) {
+                // If we are preserving a surface but we aren't relaunching that means
+                // we are just doing an in-place switch. In that case any SurfaceFlinger side
+                // child layers need to be reparented to the new surface to make this
+                // transparent to the app.
+                if (mWin.mAppToken == null || mWin.mAppToken.isRelaunching() == false) {
+                    SurfaceControl.openTransaction();
+                    mPendingDestroySurface.reparentChildrenInTransaction(mSurfaceController);
+                    SurfaceControl.closeTransaction();
+                }
+            }
+        }
+
         destroyDeferredSurfaceLocked();
         mDestroyPreservedSurfaceUponRedraw = false;
     }
@@ -1965,4 +1979,10 @@
         }
         return mForceScaleUntilResize;
     }
+
+    void detachChildren() {
+        if (mSurfaceController != null) {
+            mSurfaceController.detachChildren();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index f8e7428..f7d3343 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -135,6 +135,20 @@
         }
     }
 
+    void reparentChildrenInTransaction(WindowSurfaceController other) {
+        if (SHOW_TRANSACTIONS) Slog.i(TAG, "REPARENT from: " + this + " to: " + other);
+        if ((mSurfaceControl != null) && (other.mSurfaceControl != null)) {
+            mSurfaceControl.reparentChildren(other.getHandle());
+        }
+    }
+
+    void detachChildren() {
+        if (SHOW_TRANSACTIONS) Slog.i(TAG, "SEVER CHILDREN");
+        if (mSurfaceControl != null) {
+            mSurfaceControl.detachChildren();
+        }
+    }
+
     void hideInTransaction(String reason) {
         if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
         mHiddenForOtherReasons = true;