Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7f5f2a5a authored by Riddle Hsu's avatar Riddle Hsu Committed by Automerger Merge Worker
Browse files

Merge "Avoid recursive destruction from exit animation done" into tm-dev am:...

Merge "Avoid recursive destruction from exit animation done" into tm-dev am: 73dfe3e7 am: 50938048

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18753583



Change-Id: I3e499792e6ad1b13b9a376bc8b816b13ba8ee126
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 5a46b8e4 50938048
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -2433,14 +2433,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP

    @Override
    void removeImmediately() {
        if (!mRemoved) {
            // Destroy surface before super call. The general pattern is that the children need
            // to be removed before the parent (so that the sync-engine tracking works). Since
            // WindowStateAnimator is a "virtual" child, we have to do it manually here.
            mWinAnimator.destroySurfaceLocked(getSyncTransaction());
        }
        super.removeImmediately();

        if (mRemoved) {
            // Nothing to do.
            ProtoLog.v(WM_DEBUG_ADD_REMOVE,
@@ -2449,6 +2441,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        }

        mRemoved = true;
        // Destroy surface before super call. The general pattern is that the children need
        // to be removed before the parent (so that the sync-engine tracking works). Since
        // WindowStateAnimator is a "virtual" child, we have to do it manually here.
        mWinAnimator.destroySurfaceLocked(getSyncTransaction());
        super.removeImmediately();

        mWillReplaceWindow = false;
        if (mReplacementWindow != null) {
@@ -5090,7 +5087,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        // Otherwise we add the service to mDestroySurface and allow it to be processed in our next
        // transaction.
        if (mActivityRecord != null) {
            if (mAttrs.type == TYPE_BASE_APPLICATION) {
                mActivityRecord.destroySurfaces();
            } else {
                destroySurface(false /* cleanupOnResume */, mActivityRecord.mAppStopped);
            }
        } else {
            if (hasSurface) {
                mWmService.mDestroySurface.add(this);
+39 −0
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atMost;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.when;

@@ -471,6 +472,44 @@ public class WindowStateTests extends WindowTestsBase {
        assertTrue(appWindow.mRemoved);
    }

    @Test
    public void testOnExitAnimationDone() {
        final WindowState parent = createWindow(null, TYPE_APPLICATION, "parent");
        final WindowState child = createWindow(parent, TYPE_APPLICATION_PANEL, "child");
        final SurfaceControl.Transaction t = parent.getPendingTransaction();
        child.startAnimation(t, mock(AnimationAdapter.class), false /* hidden */,
                SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION);
        parent.mAnimatingExit = parent.mRemoveOnExit = parent.mWindowRemovalAllowed = true;
        child.mAnimatingExit = child.mRemoveOnExit = child.mWindowRemovalAllowed = true;
        final int[] numRemovals = new int[2];
        parent.registerWindowContainerListener(new WindowContainerListener() {
            @Override
            public void onRemoved() {
                numRemovals[0]++;
            }
        });
        child.registerWindowContainerListener(new WindowContainerListener() {
            @Override
            public void onRemoved() {
                numRemovals[1]++;
            }
        });
        spyOn(parent);
        // parent onExitAnimationDone
        //   -> child onExitAnimationDone() -> no-op because isAnimating()
        //   -> parent destroySurface()
        //     -> parent removeImmediately() because mDestroying+mRemoveOnExit
        //       -> child removeImmediately() -> cancelAnimation()
        //       -> child onExitAnimationDone()
        //         -> child destroySurface() because animation is canceled
        //           -> child removeImmediately() -> no-op because mRemoved
        parent.onExitAnimationDone();
        // There must be no additional destroySurface() of parent from its child.
        verify(parent, atMost(1)).destroySurface(anyBoolean(), anyBoolean());
        assertEquals(1, numRemovals[0]);
        assertEquals(1, numRemovals[1]);
    }

    @Test
    public void testLayoutSeqResetOnReparent() {
        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");