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

Commit 242be905 authored by Louis Chang's avatar Louis Chang
Browse files

Wait for all of associated activities done animating

Fixed rotation transform was finished and continued
to update the orientation when transferring the
starting window, which was before the activity ready to
show and caused flickers. This can happen while trampoline
activities were started during app launch.

This also fixes other flickers that happens when the
fixed rotation launching app's animation finished
before other associated activities.

Bug: 157446341
Test: atest DisplayContentTests AppWindowTokenTests
Change-Id: Ibeb50edc7dfd9dddffe2c420fde92c1ebb70ed37
parent 5463497b
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -3355,6 +3355,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A

            final long origId = Binder.clearCallingIdentity();
            try {
                // Link the fixed rotation transform to this activity since we are transferring the
                // starting window.
                if (fromActivity.hasFixedRotationTransform()) {
                    mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(this,
                            false /* checkOpening */);
                }

                // Transfer the starting window over to the new token.
                mStartingData = fromActivity.mStartingData;
                startingSurface = fromActivity.startingSurface;
+5 −1
Original line number Diff line number Diff line
@@ -5671,7 +5671,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            }
            if (mFixedRotationLaunchingApp != null
                    && mFixedRotationLaunchingApp.hasFixedRotationTransform(r)) {
                // Waiting until all of the associated activities have done animation, or the
                // orientation would be updated too early and cause flickers.
                if (!mFixedRotationLaunchingApp.hasAnimatingFixedRotationTransition()) {
                    continueUpdateOrientationForDiffOrienLaunchingApp();
                }
            } else {
                r.finishFixedRotationTransform();
            }
+19 −0
Original line number Diff line number Diff line
@@ -554,6 +554,25 @@ class WindowToken extends WindowContainer<WindowState> {
        notifyFixedRotationTransform(true /* enabled */);
    }

    /**
     * Return {@code true} if one of the associated activity is still animating. Otherwise,
     * return {@code false}.
     */
    boolean hasAnimatingFixedRotationTransition() {
        if (mFixedRotationTransformState == null) {
            return false;
        }

        for (int i = mFixedRotationTransformState.mAssociatedTokens.size() - 1; i >= 0; i--) {
            final ActivityRecord r =
                    mFixedRotationTransformState.mAssociatedTokens.get(i).asActivityRecord();
            if (r != null && r.isAnimating(TRANSITION | PARENTS)) {
                return true;
            }
        }
        return false;
    }

    void finishFixedRotationTransform() {
        finishFixedRotationTransform(null /* applyDisplayRotation */);
    }
+27 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
@@ -452,6 +453,32 @@ public class AppWindowTokenTests extends WindowTestsBase {
        assertFalse(middle.isVisible());
    }

    @Test
    public void testTransferStartingWindowSetFixedRotation() {
        mWm.mIsFixedRotationTransformEnabled = true;
        final ActivityRecord topActivity = createTestActivityRecordForGivenTask(mTask);
        mTask.positionChildAt(topActivity, POSITION_TOP);
        mActivity.addStartingWindow(mPackageName,
                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
                false);
        waitUntilHandlersIdle();

        // Make activities to have different rotation from it display and set fixed rotation
        // transform to activity1.
        int rotation = (mDisplayContent.getRotation() + 1) % 4;
        mDisplayContent.setFixedRotationLaunchingApp(mActivity, rotation);
        doReturn(rotation).when(mDisplayContent)
                .rotationForActivityInDifferentOrientation(topActivity);

        // Make sure the fixed rotation transform linked to activity2 when adding starting window
        // on activity2.
        topActivity.addStartingWindow(mPackageName,
                android.R.style.Theme, null, "Test", 0, 0, 0, 0, mActivity.appToken.asBinder(),
                false, false, false, true, false);
        waitUntilHandlersIdle();
        assertTrue(topActivity.hasFixedRotationTransform());
    }

    private ActivityRecord createIsolatedTestActivityRecord() {
        final ActivityStack taskStack = createTaskStackOnDisplay(mDisplayContent);
        final Task task = createTaskInStack(taskStack, 0 /* userId */);
+7 −0
Original line number Diff line number Diff line
@@ -1144,7 +1144,14 @@ public class DisplayContentTests extends WindowTestsBase {
        assertTrue(app.hasFixedRotationTransform(app2));
        assertTrue(mDisplayContent.isFixedRotationLaunchingApp(app2));

        // The fixed rotation transform can only be finished when all animation finished.
        doReturn(false).when(app2).isAnimating(anyInt(), anyInt());
        mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app2.token);
        assertTrue(app.hasFixedRotationTransform());
        assertTrue(app2.hasFixedRotationTransform());

        // The display should be rotated after the launch is finished.
        doReturn(false).when(app).isAnimating(anyInt(), anyInt());
        mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app.token);

        // The fixed rotation should be cleared and the new rotation is applied to display.