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

Commit a8849f27 authored by Vadim Caen's avatar Vadim Caen
Browse files

Ignore rotation update during recent animation.

During the recent animation, the closing app is still considered on top
and its required orientation is used for the next rotation computation.

When going to launcher and rotating the device at the same time, a
rotation update is triggered by the sensor and if the closing app allows
a change of orientation, the display ends up rotating at the end of the
animation, which make the launcher rotate even if it is not supposed to
do so.

Test: atest
WmTests: com.android.server.wm.DisplayContentTests#testRecentsNotRotatingWithFixedRotation
Fixes: 157447718
Change-Id: I3f2a46ddfe5e76ad3200ea27ad272ae36b6bcc8d
parent 26dfdc58
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.os.Build.VERSION_CODES.N;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
@@ -1526,12 +1527,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    }

    /**
     * Sets the provided record to {@link mFixedRotationLaunchingApp} if possible to apply fixed
     * Sets the provided record to {@link #mFixedRotationLaunchingApp} if possible to apply fixed
     * rotation transform to it and indicate that the display may be rotated after it is launched.
     */
    void setFixedRotationLaunchingApp(@NonNull ActivityRecord r, @Surface.Rotation int rotation) {
        final WindowToken prevRotatedLaunchingApp = mFixedRotationLaunchingApp;
        if (prevRotatedLaunchingApp != null && prevRotatedLaunchingApp == r
        if (prevRotatedLaunchingApp == r
                && r.getWindowConfiguration().getRotation() == rotation) {
            // The given launching app and target rotation are the same as the existing ones.
            return;
@@ -5659,6 +5660,16 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            }
        }

        /**
         * Return {@code true} if there is an ongoing animation to the "Recents" activity and this
         * activity as a fixed orientation so shouldn't be rotated.
         */
        boolean isFixedOrientationRecentsAnimating() {
            return mAnimatingRecents != null
                    && mAnimatingRecents.getRequestedConfigurationOrientation()
                    != ORIENTATION_UNDEFINED;
        }

        @Override
        public void onAppTransitionFinishedLocked(IBinder token) {
            final ActivityRecord r = getActivityRecord(token);
+9 −0
Original line number Diff line number Diff line
@@ -430,6 +430,15 @@ public class DisplayRotation {
                        "Deferring rotation, still finishing previous rotation");
                return false;
            }

            if (mDisplayContent.mFixedRotationTransitionListener
                    .isFixedOrientationRecentsAnimating()) {
                // During the recents animation, the closing app might still be considered on top.
                // In order to ignore its requested orientation to avoid a sensor led rotation (e.g
                // user rotating the device while the recents animation is running), we ignore
                // rotation update while the animation is running.
                return false;
            }
        }

        if (!mService.mDisplayEnabled) {
+21 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -79,6 +80,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doCallRealMethod;

import android.annotation.SuppressLint;
import android.app.ActivityTaskManager;
@@ -1230,12 +1232,30 @@ public class DisplayContentTests extends WindowTestsBase {
        assertTrue(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging());
    }

    @Test
    public void testRecentsNotRotatingWithFixedRotation() {
        final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
        doCallRealMethod().when(displayRotation).updateRotationUnchecked(anyBoolean());
        doCallRealMethod().when(displayRotation).updateOrientation(anyInt(), anyBoolean());

        final ActivityRecord recentsActivity = createActivityRecord(mDisplayContent,
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS);
        recentsActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);

        mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity);
        displayRotation.setRotation((displayRotation.getRotation() + 1) % 4);
        assertFalse(displayRotation.updateRotationUnchecked(false));

        mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation(false);
        assertTrue(displayRotation.updateRotationUnchecked(false));
    }

    @Test
    public void testRemoteRotation() {
        DisplayContent dc = createNewDisplay();

        final DisplayRotation dr = dc.getDisplayRotation();
        Mockito.doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
        doCallRealMethod().when(dr).updateRotationUnchecked(anyBoolean());
        Mockito.doReturn(ROTATION_90).when(dr).rotationForOrientation(anyInt(), anyInt());
        final boolean[] continued = new boolean[1];
        // TODO(display-merge): Remove cast