Merge "Avoid recursive destruction from exit animation done" into tm-dev am: 73dfe3e741
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18753583 Change-Id: I0c3d66e1b91177cf573459953b85f3c0b2e02faa Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -2433,14 +2433,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
void removeImmediately() {
|
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) {
|
if (mRemoved) {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
ProtoLog.v(WM_DEBUG_ADD_REMOVE,
|
ProtoLog.v(WM_DEBUG_ADD_REMOVE,
|
||||||
@@ -2449,6 +2441,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
|||||||
}
|
}
|
||||||
|
|
||||||
mRemoved = true;
|
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;
|
mWillReplaceWindow = false;
|
||||||
if (mReplacementWindow != null) {
|
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
|
// Otherwise we add the service to mDestroySurface and allow it to be processed in our next
|
||||||
// transaction.
|
// transaction.
|
||||||
if (mActivityRecord != null) {
|
if (mActivityRecord != null) {
|
||||||
|
if (mAttrs.type == TYPE_BASE_APPLICATION) {
|
||||||
mActivityRecord.destroySurfaces();
|
mActivityRecord.destroySurfaces();
|
||||||
|
} else {
|
||||||
|
destroySurface(false /* cleanupOnResume */, mActivityRecord.mAppStopped);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (hasSurface) {
|
if (hasSurface) {
|
||||||
mWmService.mDestroySurface.add(this);
|
mWmService.mDestroySurface.add(this);
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
|
|||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.atMost;
|
||||||
import static org.mockito.Mockito.clearInvocations;
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -471,6 +472,44 @@ public class WindowStateTests extends WindowTestsBase {
|
|||||||
assertTrue(appWindow.mRemoved);
|
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
|
@Test
|
||||||
public void testLayoutSeqResetOnReparent() {
|
public void testLayoutSeqResetOnReparent() {
|
||||||
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
|
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
|
||||||
|
|||||||
Reference in New Issue
Block a user