Loading services/core/java/com/android/server/wm/WindowState.java +10 −9 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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) { Loading Loading @@ -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); Loading services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +39 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"); Loading Loading
services/core/java/com/android/server/wm/WindowState.java +10 −9 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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) { Loading Loading @@ -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); Loading
services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +39 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"); Loading