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

Commit 7d82f0a2 authored by Pablo Gamito's avatar Pablo Gamito
Browse files

Prevent flicker on orientation change while starting

It's common for apps to set the orentation in the on fragment attach or
some otherway that delays that orentation change to a point when the
opening activity transition has alrady been started. In this case the
orientation change will trigger an activity restart but the position of
the activity and letterboxing are updated before the activity re-draws
itself with the new configuration, which leads to a flicker.

Test: use test app from bug and make sure issue doesn't reproduce
Bug: 271276745

Change-Id: I303721bb33bbca32e2e65b7c6f1e0905771d221a
parent 86305544
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -4025,7 +4025,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    }

    void finishRelaunching() {
        mLetterboxUiController.setRelauchingAfterRequestedOrientationChanged(false);
        mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(false);
        mTaskSupervisor.getActivityMetricsLogger().notifyActivityRelaunched(this);

        if (mPendingRelaunchCount > 0) {
@@ -9420,7 +9420,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                mRelaunchReason = RELAUNCH_REASON_NONE;
            }
            if (isRequestedOrientationChanged) {
                mLetterboxUiController.setRelauchingAfterRequestedOrientationChanged(true);
                mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(true);
            }
            if (mState == PAUSING) {
                // A little annoying: we are waiting for this activity to finish pausing. Let's not
+27 −5
Original line number Diff line number Diff line
@@ -241,7 +241,9 @@ final class LetterboxUiController {
    @Nullable
    private final Boolean mBooleanPropertyFakeFocus;

    private boolean mIsRelauchingAfterRequestedOrientationChanged;
    private boolean mIsRelaunchingAfterRequestedOrientationChanged;

    private boolean mLastShouldShowLetterboxUi;

    private boolean mDoubleTapEvent;

@@ -394,7 +396,7 @@ final class LetterboxUiController {
                        ::isPolicyForIgnoringRequestedOrientationEnabled,
                mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled,
                mBooleanPropertyIgnoreRequestedOrientation)) {
            if (mIsRelauchingAfterRequestedOrientationChanged) {
            if (mIsRelaunchingAfterRequestedOrientationChanged) {
                Slog.w(TAG, "Ignoring orientation update to "
                        + screenOrientationToString(requestedOrientation)
                        + " due to relaunching after setRequestedOrientation for "
@@ -483,8 +485,8 @@ final class LetterboxUiController {
     * Sets whether an activity is relaunching after the app has called {@link
     * android.app.Activity#setRequestedOrientation}.
     */
    void setRelauchingAfterRequestedOrientationChanged(boolean isRelaunching) {
        mIsRelauchingAfterRequestedOrientationChanged = isRelaunching;
    void setRelaunchingAfterRequestedOrientationChanged(boolean isRelaunching) {
        mIsRelaunchingAfterRequestedOrientationChanged = isRelaunching;
    }

    /**
@@ -1161,12 +1163,28 @@ final class LetterboxUiController {

    @VisibleForTesting
    boolean shouldShowLetterboxUi(WindowState mainWindow) {
        return (mActivityRecord.isInLetterboxAnimation() || isSurfaceVisible(mainWindow))
        if (mIsRelaunchingAfterRequestedOrientationChanged || !isSurfaceReadyToShow(mainWindow)) {
            return mLastShouldShowLetterboxUi;
        }

        final boolean shouldShowLetterboxUi =
                (mActivityRecord.isInLetterboxAnimation() || isSurfaceVisible(mainWindow))
                && mainWindow.areAppWindowBoundsLetterboxed()
                // Check for FLAG_SHOW_WALLPAPER explicitly instead of using
                // WindowContainer#showWallpaper because the later will return true when this
                // activity is using blurred wallpaper for letterbox background.
                && (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) == 0;

        mLastShouldShowLetterboxUi = shouldShowLetterboxUi;

        return shouldShowLetterboxUi;
    }

    @VisibleForTesting
    boolean isSurfaceReadyToShow(WindowState mainWindow) {
        return mainWindow.isDrawn() // Regular case
                // Waiting for relayoutWindow to call preserveSurface
                || mainWindow.isDragResizeChanged();
    }

    @VisibleForTesting
@@ -1302,6 +1320,10 @@ final class LetterboxUiController {
        return null;
    }

    boolean getIsRelaunchingAfterRequestedOrientationChanged() {
        return mIsRelaunchingAfterRequestedOrientationChanged;
    }

    private void adjustBoundsForTaskbar(final WindowState mainWindow, final Rect bounds) {
        // Rounded corners should be displayed above the taskbar. When taskbar is hidden,
        // an insets frame is equal to a navigation bar which shouldn't affect position of
+11 −2
Original line number Diff line number Diff line
@@ -5596,8 +5596,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
            if (surfaceInsetsChanged) {
                mLastSurfaceInsets.set(mAttrs.surfaceInsets);
            }
            if (surfaceSizeChanged && mWinAnimator.getShown() && !canPlayMoveAnimation()
                    && okToDisplay() && mSyncState == SYNC_STATE_NONE) {
            final boolean surfaceResizedWithoutMoveAnimation = surfaceSizeChanged
                    && mWinAnimator.getShown() && !canPlayMoveAnimation() && okToDisplay()
                    && mSyncState == SYNC_STATE_NONE;
            final ActivityRecord activityRecord = getActivityRecord();
            // If this window belongs to an activity that is relaunching due to an orientation
            // change then delay the position update until it has redrawn to avoid any flickers.
            final boolean isLetterboxedAndRelaunching = activityRecord != null
                    && activityRecord.areBoundsLetterboxed()
                    && activityRecord.mLetterboxUiController
                        .getIsRelaunchingAfterRequestedOrientationChanged();
            if (surfaceResizedWithoutMoveAnimation || isLetterboxedAndRelaunching) {
                applyWithNextDraw(mSetSurfacePositionConsumer);
            } else {
                mSetSurfacePositionConsumer.accept(t);
+2 −2
Original line number Diff line number Diff line
@@ -145,7 +145,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
        mActivity = setUpActivityWithComponent();
        mController = new LetterboxUiController(mWm, mActivity);
        prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch();
        mController.setRelauchingAfterRequestedOrientationChanged(false);
        mController.setRelaunchingAfterRequestedOrientationChanged(false);

        spyOn(mDisplayContent.mDisplayRotationCompatPolicy);
        doReturn(true).when(mDisplayContent.mDisplayRotationCompatPolicy)
@@ -864,7 +864,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
    private void prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch() {
        doReturn(true).when(mLetterboxConfiguration)
                .isPolicyForIgnoringRequestedOrientationEnabled();
        mController.setRelauchingAfterRequestedOrientationChanged(true);
        mController.setRelaunchingAfterRequestedOrientationChanged(true);
    }

    private ActivityRecord setUpActivityWithComponent() {
+2 −0
Original line number Diff line number Diff line
@@ -738,6 +738,8 @@ public class SizeCompatTests extends WindowTestsBase {
        assertEquals(window, mActivity.findMainWindow());

        spyOn(mActivity.mLetterboxUiController);
        doReturn(true).when(mActivity.mLetterboxUiController)
                .isSurfaceReadyToShow(any());
        doReturn(true).when(mActivity.mLetterboxUiController)
                .isSurfaceVisible(any());