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

Commit d1d2e8bf authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Avoid updating display orientation from closing activity

This prevents continueUpdateOrientationForDiffOrienLaunchingApp from
being called twice (especially the order is random by the hashcode of
transition participants) for a transition when launching fixed
rotation activity. Otherwise if the display orientation is not changed
by the method, it will clear the rotation transform of the launching
activity too early, which causes flickering by
rotated > not-rotated > rotated.

Since shell transition and the support of respect-non-top-visible
orientation, some legacy conditions can be replaced. Also make
the tests adopt shell transition.

Bug: 374898575
Flag: EXEMPT bugfix
Test: atest DisplayContentTests#testApplyTopFixedRotationTransform
            testFinishFixedRotationNoAppTransitioningTask

Change-Id: I2d0e265d25c1a81f044975a73d955aac658341a2
parent 9afbd46d
Loading
Loading
Loading
Loading
+8 −10
Original line number Diff line number Diff line
@@ -6923,27 +6923,25 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
                return;
            }
            if (mFixedRotationLaunchingApp.hasFixedRotationTransform(r)) {
                if (!r.isVisible()) {
                    // Let the opening activity update orientation.
                    return;
                }
                if (mFixedRotationLaunchingApp.hasAnimatingFixedRotationTransition()) {
                    // Waiting until all of the associated activities have done animation, or the
                    // orientation would be updated too early and cause flickering.
                    return;
                }
            } else {
                // Handle a corner case that the task of {@link #mFixedRotationLaunchingApp} is no
                // longer animating but the corresponding transition finished event won't notify.
                // E.g. activity A transferred starting window to B, only A will receive transition
                // finished event. A doesn't have fixed rotation but B is the rotated launching app.
                final Task task = r.getTask();
                if (task != mFixedRotationLaunchingApp.getTask()
                // Check to skip updating display orientation by a non-top activity.
                if ((!r.isVisible() || !mFixedRotationLaunchingApp.fillsParent())
                        // When closing a translucent task A (r.fillsParent() is false) to a
                        // visible task B, because only A has visibility change, there is only A's
                        // transition callback. Then it still needs to update orientation for B.
                        && (!mWmService.mFlags.mRespectNonTopVisibleFixedOrientation
                                || r.fillsParent())) {
                    // Different tasks won't be in one activity transition animation.
                        && r.fillsParent()) {
                    return;
                }
                if (task.getActivity(ActivityRecord::isInTransition) != null) {
                if (r.inTransition()) {
                    return;
                    // Continue to update orientation because the transition of the top rotated
                    // launching activity is done.
+13 −19
Original line number Diff line number Diff line
@@ -1609,8 +1609,10 @@ public class DisplayContentTests extends WindowTestsBase {

        final ActivityRecord app = mAppWindow.mActivityRecord;
        app.setVisible(false);
        mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN);
        mDisplayContent.mOpeningApps.add(app);
        app.setVisibleRequested(false);
        registerTestTransitionPlayer();
        mDisplayContent.requestTransitionAndLegacyPrepare(WindowManager.TRANSIT_OPEN, 0);
        app.setVisibility(true);
        final int newOrientation = getRotatedOrientation(mDisplayContent);
        app.setRequestedOrientation(newOrientation);

@@ -1641,14 +1643,6 @@ public class DisplayContentTests extends WindowTestsBase {
        assertEquals(state.isSourceOrDefaultVisible(statusBarId, statusBars()),
                rotatedState.isSourceOrDefaultVisible(statusBarId, statusBars()));

        final Rect outFrame = new Rect();
        final Rect outInsets = new Rect();
        final Rect outStableInsets = new Rect();
        final Rect outSurfaceInsets = new Rect();
        mAppWindow.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
        // The animation frames should not be rotated because display hasn't rotated.
        assertEquals(mDisplayContent.getBounds(), outFrame);

        // The display should keep current orientation and the rotated configuration should apply
        // to the activity.
        assertEquals(config.orientation, mDisplayContent.getConfiguration().orientation);
@@ -1676,9 +1670,8 @@ public class DisplayContentTests extends WindowTestsBase {
        // Launch another activity before the transition is finished.
        final Task task2 = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent).build();
        final ActivityRecord app2 = new ActivityBuilder(mAtm).setTask(task2)
                .setUseProcess(app.app).build();
        app2.setVisible(false);
        mDisplayContent.mOpeningApps.add(app2);
                .setUseProcess(app.app).setVisible(false).build();
        app2.setVisibility(true);
        app2.setRequestedOrientation(newOrientation);

        // The activity should share the same transform state as the existing one. The activity
@@ -1701,14 +1694,15 @@ public class DisplayContentTests extends WindowTestsBase {
        assertTrue(mImeWindow.isAnimating(PARENTS, ANIMATION_TYPE_TOKEN_TRANSFORM));

        // The fixed rotation transform can only be finished when all animation finished.
        doReturn(false).when(app2).isAnimating(anyInt(), anyInt());
        mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app2.token);
        doReturn(false).when(app2).inTransition();
        mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(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);
        app.setVisible(true);
        doReturn(false).when(app).inTransition();
        mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);
        mStatusBarWindow.finishSeamlessRotation(t);
        mNavBarWindow.finishSeamlessRotation(t);

@@ -1726,7 +1720,7 @@ public class DisplayContentTests extends WindowTestsBase {
        final Task task = app.getTask();
        final ActivityRecord app2 = new ActivityBuilder(mWm.mAtmService).setTask(task).build();
        mDisplayContent.setFixedRotationLaunchingApp(app2, (mDisplayContent.getRotation() + 1) % 4);
        doReturn(true).when(app).inTransitionSelfOrParent();
        doReturn(true).when(app).inTransition();
        // If the task contains a transition, this should be no-op.
        mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);

@@ -1736,7 +1730,7 @@ public class DisplayContentTests extends WindowTestsBase {
        // The display should be unlikely to be in transition, but if it happens, the fixed
        // rotation should proceed to finish because the activity/task level transition is finished.
        doReturn(true).when(mDisplayContent).inTransition();
        doReturn(false).when(app).inTransitionSelfOrParent();
        doReturn(false).when(app).inTransition();
        // Although this notifies app instead of app2 that uses the fixed rotation, app2 should
        // still finish the transform because there is no more transition event.
        mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);