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

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

Apply fixed rotation when showing snapshot starting window

Unlike splash screen starting window that inherits the size of
activity directly, task snapshot needs the final size to draw right
after adding to display. Otherwise the content will look like as
cropped because the surface size uses different orientation.

And because starting window is added before executing transition,
assume there will have transition if the owner of starting window
is also the top activity.

Bug: 155862858
Test: ActivityRecordTests#testFixedRotationSnapshotStartingWindow
Change-Id: Idb4f9a92a6e2594356416afd0ab6360e94e66497
parent eae6ef3e
Loading
Loading
Loading
Loading
+24 −20
Original line number Diff line number Diff line
@@ -1393,18 +1393,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        final WindowContainer orientationSource = getLastOrientationSource();
        final ActivityRecord r =
                orientationSource != null ? orientationSource.asActivityRecord() : null;
        if (r != null && r.getTask() != null
                && orientation != r.getTask().mLastReportedRequestedOrientation) {
        if (r != null) {
            final Task task = r.getTask();
            if (task != null && orientation != task.mLastReportedRequestedOrientation) {
                task.mLastReportedRequestedOrientation = orientation;
                mAtmService.getTaskChangeNotificationController()
                        .notifyTaskRequestedOrientationChanged(task.mTaskId, orientation);
            }
            // Currently there is no use case from non-activity.
        if (r != null && handleTopActivityLaunchingInDifferentOrientation(r)) {
            if (handleTopActivityLaunchingInDifferentOrientation(r, true /* checkOpening */)) {
                // Display orientation should be deferred until the top fixed rotation is finished.
                return false;
            }
        }
        return mDisplayRotation.updateOrientation(orientation, forceUpdate);
    }

@@ -1435,9 +1436,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
     * is launching until the launch animation is done to avoid showing the previous activity
     * inadvertently in a wrong orientation.
     *
     * @param r The launching activity which may change display orientation.
     * @param checkOpening Whether to check if the activity is animating by transition. Set to
     *                     {@code true} if the caller is not sure whether the activity is launching.
     * @return {@code true} if the fixed rotation is started.
     */
    private boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r) {
    boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r,
            boolean checkOpening) {
        if (!mWmService.mIsFixedRotationTransformEnabled) {
            return false;
        }
@@ -1448,15 +1453,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            // It has been set and not yet finished.
            return true;
        }
        if (!mAppTransition.isTransitionSet()) {
        if (checkOpening) {
            if (!mAppTransition.isTransitionSet() && !mOpeningApps.contains(r)) {
                // Apply normal rotation animation in case of the activity set different requested
                // orientation without activity switch.
                return false;
            }
        if (!mOpeningApps.contains(r)
                // Without screen rotation, the rotation behavior of non-top visible activities is
                // undefined. So the fixed rotated activity needs to cover the screen.
                && r.findMainWindow() != mDisplayPolicy.getTopFullscreenOpaqueWindow()) {
        } else if (r != topRunningActivity()) {
            // If the transition has not started yet, the activity must be the top.
            return false;
        }
        final int rotation = rotationForActivityInDifferentOrientation(r);
+10 −0
Original line number Diff line number Diff line
@@ -195,6 +195,16 @@ class TaskSnapshotSurface implements StartingSurface {
                        + activity);
                return null;
            }
            if (topFullscreenActivity.getWindowConfiguration().getRotation()
                    != snapshot.getRotation()) {
                // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
                // that the activity will be updated to the same rotation as the snapshot. Since
                // the transition is not started yet, fixed rotation transform needs to be applied
                // earlier to make the snapshot show in a rotated container.
                activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
                        topFullscreenActivity, false /* checkOpening */);
            }

            sysUiVis = topFullscreenOpaqueWindow.getSystemUiVisibility();
            WindowManager.LayoutParams attrs = topFullscreenOpaqueWindow.mAttrs;
            windowFlags = attrs.flags;
+46 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
@@ -83,14 +84,18 @@ import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.MergedConfiguration;
import android.util.MutableBoolean;
import android.view.DisplayInfo;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner.Stub;
import android.view.IWindowSession;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;

import androidx.test.filters.MediumTest;

@@ -1454,6 +1459,47 @@ public class ActivityRecordTests extends ActivityTestsBase {
        assertFalse(mActivity.isSnapshotCompatible(snapshot));
    }

    @Test
    public void testFixedRotationSnapshotStartingWindow() {
        mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
        // TaskSnapshotSurface requires a fullscreen opaque window.
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
        params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
        final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
                mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
        mActivity.addWindow(w);

        // Assume the activity is launching in different rotation, and there was an available
        // snapshot accepted by {@link Activity#isSnapshotCompatible}.
        final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
                .setRotation((mActivity.getWindowConfiguration().getRotation() + 1) % 4)
                .build();
        setRotatedScreenOrientationSilently(mActivity);

        final IWindowSession session = WindowManagerGlobal.getWindowSession();
        spyOn(session);
        try {
            // Return error to skip unnecessary operation.
            doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
                    any() /* window */, anyInt() /* seq */, any() /* attrs */,
                    anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* outFrame */,
                    any() /* outContentInsets */, any() /* outStableInsets */,
                    any() /* outDisplayCutout */, any() /* outInputChannel */,
                    any() /* outInsetsState */, any() /* outActiveControls */);
            TaskSnapshotSurface.create(mService.mWindowManager, mActivity, snapshot);
        } catch (RemoteException ignored) {
        } finally {
            reset(session);
        }

        // Because the rotation of snapshot and the corresponding top activity are different, fixed
        // rotation should be applied when creating snapshot surface if the display rotation may be
        // changed according to the activity orientation.
        assertTrue(mActivity.hasFixedRotationTransform());
        assertEquals(mActivity, mActivity.mDisplayContent.mFixedRotationLaunchingApp);
    }

    /**
     * Sets orientation without notifying the parent to simulate that the display has not applied
     * the requested orientation yet.