Fix app afterimage flashing while device unlocking

The problem is because in WMS#tryStartExitingAnimation set
win.mAnimatingExit as ture but not destroy surface when pressing
power button, so let `WindowState#mHasSurface` keeps true when
screen off. (Normally the surface should be destroyed when screen off)

This results when unlocking the screen will can see both the app
window afterimage and launcher are animating.

Check with DC#okToAnimate in tryStartExitingAnimation to ensure the
surface can be destroyed when the display is not ready to animate (e.g.
screen off).

Also, in order to cleanly clean up surfaces while cancelling recents
animation when the removal is allowed, make sure to invoke
onAnimationFinished for task's windows to finish the process of
the surface removal.

Fix: 173379232
Test: atest WmTests CtsWindowManagerDeviceTestCases
Test: atest RecentsAnimationControllerTests#\
      testCleanupAnimation_expectExitAnimationDone
Test: manul as below steps:
1. in gesture nav mode, launch any apps (e.g. Settings).
2. swipe up app task to launcher
3. before swipe up animation finish, quickly pressing power button.
4. turn on screen and unlock, see if the app window flashing then back
   to launcher.

Change-Id: Ib2778c1b2677752039be12a16a42623a25773fa2
This commit is contained in:
Ming-Shin Lu
2021-01-31 23:06:23 +08:00
parent cd6911ec52
commit 50dfb95924
3 changed files with 37 additions and 4 deletions

View File

@@ -421,7 +421,10 @@ public class RecentsAnimationController implements DeathRecipient {
if (skipAnimation(task)) {
continue;
}
addAnimation(task, !recentTaskIds.get(task.mTaskId));
addAnimation(task, !recentTaskIds.get(task.mTaskId), false /* hidden */,
(type, anim) -> task.forAllWindows(win -> {
win.onAnimationFinished(type, anim);
}, true /* traverseTopToBottom */));
}
// Skip the animation if there is nothing to animate

View File

@@ -2563,11 +2563,12 @@ public class WindowManagerService extends IWindowManager.Stub
} else if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = true;
win.mAnimatingExit = true;
} else if (win.isAnimating(TRANSITION | PARENTS)) {
} else if (win.mDisplayContent.okToAnimate() && win.isAnimating(TRANSITION | PARENTS)) {
// Currently in a hide animation... turn this into
// an exit.
win.mAnimatingExit = true;
} else if (win.getDisplayContent().mWallpaperController.isWallpaperTarget(win)) {
} else if (win.mDisplayContent.okToAnimate()
&& win.mDisplayContent.mWallpaperController.isWallpaperTarget(win)) {
// If the wallpaper is currently behind this
// window, we need to change both of them inside
// of a transaction to avoid artifacts.

View File

@@ -493,7 +493,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
initializeRecentsAnimationController(mController, homeActivity);
// Verify RecentsAnimationController will animate visible leaf task by default.
verify(mController).addAnimation(eq(leafTask), anyBoolean(), anyBoolean(), eq(null));
verify(mController).addAnimation(eq(leafTask), anyBoolean(), anyBoolean(), any());
assertTrue(leafTask.isAnimatingByRecents());
// Make sure isAnimatingByRecents will also return true when it called by the parent task.
@@ -543,6 +543,35 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
verify(navBarFadeAnimationController, never()).fadeWindowToken(anyBoolean());
}
@Test
public void testCleanupAnimation_expectExitAnimationDone() {
mWm.setRecentsAnimationController(mController);
final ActivityRecord homeActivity = createHomeActivity();
final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
activity.addWindow(win1);
initializeRecentsAnimationController(mController, homeActivity);
mController.startAnimation();
spyOn(win1);
spyOn(win1.mWinAnimator);
// Simulate when the window is exiting and cleanupAnimation invoked
// (e.g. screen off during RecentsAnimation animating), will expect the window receives
// onExitAnimationDone to destroy the surface when the removal is allowed.
win1.mWinAnimator.mSurfaceController = mock(WindowSurfaceController.class);
win1.mHasSurface = true;
win1.mAnimatingExit = true;
win1.mRemoveOnExit = true;
win1.mWindowRemovalAllowed = true;
mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
verify(win1).onAnimationFinished(eq(ANIMATION_TYPE_RECENTS), any());
verify(win1).onExitAnimationDone();
verify(win1).destroySurface(eq(false), eq(false));
assertFalse(win1.mAnimatingExit);
assertFalse(win1.mHasSurface);
}
private ActivityRecord createHomeActivity() {
final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
.setParentTask(mRootHomeTask)