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

Commit 50dfb959 authored by Ming-Shin Lu's avatar Ming-Shin Lu
Browse files

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
parent cd6911ec
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -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
+3 −2
Original line number Diff line number Diff line
@@ -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.
+30 −1
Original line number Diff line number Diff line
@@ -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)