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

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

Clear fixed rotation for app no longer changes rotation

For example: launch a landscape activity while device is portrait,
and then launch another portrait activity before previous transition
is done. If the landscape activity is destroyed before sending the
fixed rotation adjustment for restoration, the adjustment is always
retained by client side app. That causes the Display objects
associated with application Resources always return rotation from
the adjustment.

This change clear the rotated state immediately when the top app
has changed to the one that won't rotate the display. So the previous
activity can receive the adjustment for restoration in time.

Also simply a bit for the path of clearing fixed rotation state to
avoid sending duplicated adjustments.

Bug: 177390830
Test: DisplayContentTests#testClearIntermediateFixedRotation

Change-Id: Ic13dff8b7a23a6022201a8fe7a981bb511b6e856
parent 1e465216
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -1559,6 +1559,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        }
        final int rotation = rotationForActivityInDifferentOrientation(r);
        if (rotation == ROTATION_UNDEFINED) {
            // The display rotation won't be changed by current top activity. If there was fixed
            // rotation activity, its rotated state should be cleared to cancel the adjustments.
            if (hasTopFixedRotationLaunchingApp()
                    // Avoid breaking recents animation.
                    && !mFixedRotationLaunchingApp.getTask().isAnimatingByRecents()) {
                clearFixedRotationLaunchingApp();
            }
            return false;
        }
        if (!r.getParent().matchParentBounds()) {
+4 −6
Original line number Diff line number Diff line
@@ -647,11 +647,6 @@ class WindowToken extends WindowContainer<WindowState> {
        state.mIsTransforming = false;
        if (applyDisplayRotation != null) {
            applyDisplayRotation.run();
        } else {
            // The display will not rotate to the rotation of this container, let's cancel them.
            for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
                state.mAssociatedTokens.get(i).cancelFixedRotationTransform();
            }
        }
        // The state is cleared at the end, because it is used to indicate that other windows can
        // use seamless rotation when applying rotation to display.
@@ -659,6 +654,10 @@ class WindowToken extends WindowContainer<WindowState> {
            final WindowToken token = state.mAssociatedTokens.get(i);
            token.mFixedRotationTransformState = null;
            token.notifyFixedRotationTransform(false /* enabled */);
            if (applyDisplayRotation == null) {
                // Notify cancellation because the display does not change rotation.
                token.cancelFixedRotationTransform();
            }
        }
    }

@@ -707,7 +706,6 @@ class WindowToken extends WindowContainer<WindowState> {
            // The window may be detached or detaching.
            return;
        }
        notifyFixedRotationTransform(false /* enabled */);
        final int originalRotation = getWindowConfiguration().getRotation();
        onConfigurationChanged(parent.getConfiguration());
        onCancelFixedRotationTransform(originalRotation);
+28 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ import static org.mockito.Mockito.doCallRealMethod;
import android.annotation.SuppressLint;
import android.app.ActivityTaskManager;
import android.app.WindowConfiguration;
import android.app.servertransaction.FixedRotationAdjustmentsItem;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
@@ -1467,6 +1468,33 @@ public class DisplayContentTests extends WindowTestsBase {
        assertFalse(recentsActivity.hasFixedRotationTransform());
    }

    @Test
    public void testClearIntermediateFixedRotation() throws RemoteException {
        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
        mDisplayContent.setFixedRotationLaunchingApp(activity,
                (mDisplayContent.getRotation() + 1) % 4);
        // Create a window so FixedRotationAdjustmentsItem can be sent.
        createWindow(null, TYPE_APPLICATION_STARTING, activity, "AppWin");
        final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
        activity2.setVisible(false);
        clearInvocations(mAtm.getLifecycleManager());
        // The first activity has applied fixed rotation but the second activity becomes the top
        // before the transition is done and it has the same rotation as display, so the dispatched
        // rotation adjustment of first activity must be cleared.
        mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(activity2,
                false /* checkOpening */);

        final ArgumentCaptor<FixedRotationAdjustmentsItem> adjustmentsCaptor =
                ArgumentCaptor.forClass(FixedRotationAdjustmentsItem.class);
        verify(mAtm.getLifecycleManager(), atLeastOnce()).scheduleTransaction(
                eq(activity.app.getThread()), adjustmentsCaptor.capture());
        assertFalse(activity.hasFixedRotationTransform());
        final FixedRotationAdjustmentsItem clearAdjustments = FixedRotationAdjustmentsItem.obtain(
                activity.token, null /* fixedRotationAdjustments */);
        // The captor may match other items. The first one must be the item to clear adjustments.
        assertEquals(clearAdjustments, adjustmentsCaptor.getAllValues().get(0));
    }

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