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

Commit cc18bee6 authored by Chris Li's avatar Chris Li
Browse files

Request change transition for layout direction change for legacy

Before, we check if the bounds are resized to start a change transition
to avoid unnecessary screenshot. However, when the layout direction is
changed, we also want to have a change transition when the bounds are
not resized.

Bug: 241043533
Fix: 258130319
Test: atest WmTests:TaskFragmentTest
Change-Id: I413febe18c2288600066e9f8d641d6ab4ec5f126
parent f2296dcb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2098,6 +2098,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
                    // from the client organizer, so the PIP activity can get the correct config
                    // from the Task, and prevent conflict with the PipTaskOrganizer.
                    tf.updateRequestedOverrideConfiguration(EMPTY);
                    tf.updateRelativeEmbeddedBounds();
                }
            });
            rootTask.setWindowingMode(WINDOWING_MODE_PINNED);
+52 −6
Original line number Diff line number Diff line
@@ -299,6 +299,14 @@ class TaskFragment extends WindowContainer<WindowContainer> {
    @Nullable
    private final IBinder mFragmentToken;

    /**
     * The bounds of the embedded TaskFragment relative to the parent Task.
     * {@code null} if it is not {@link #mIsEmbedded}
     * TODO(b/261785978) cleanup with legacy app transition
     */
    @Nullable
    private final Rect mRelativeEmbeddedBounds;

    /**
     * Whether to delay the call to {@link #updateOrganizedTaskFragmentSurface()} when there is a
     * configuration change.
@@ -381,6 +389,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
        mRootWindowContainer = mAtmService.mRootWindowContainer;
        mCreatedByOrganizer = createdByOrganizer;
        mIsEmbedded = isEmbedded;
        mRelativeEmbeddedBounds = isEmbedded ? new Rect() : null;
        mTaskFragmentOrganizerController =
                mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController;
        mFragmentToken = fragmentToken;
@@ -2419,16 +2428,53 @@ class TaskFragment extends WindowContainer<WindowContainer> {
        }
    }

    /** Whether we should prepare a transition for this {@link TaskFragment} bounds change. */
    boolean shouldStartChangeTransition(Rect startBounds) {
    /**
     * Gets the relative bounds of this embedded TaskFragment. This should only be called on
     * embedded TaskFragment.
     */
    @NonNull
    Rect getRelativeEmbeddedBounds() {
        if (mRelativeEmbeddedBounds == null) {
            throw new IllegalStateException("The TaskFragment is not embedded");
        }
        return mRelativeEmbeddedBounds;
    }

    /**
     * Updates the record of the relative bounds of this embedded TaskFragment. This should only be
     * called when the embedded TaskFragment's override bounds are changed.
     * Returns {@code true} if the bounds is changed.
     */
    void updateRelativeEmbeddedBounds() {
        // We only record the override bounds, which means it will not be changed when it is filling
        // Task, and resize with the parent.
        getRequestedOverrideBounds(mTmpBounds);
        getRelativePosition(mTmpPoint);
        mTmpBounds.offsetTo(mTmpPoint.x, mTmpPoint.y);
        mRelativeEmbeddedBounds.set(mTmpBounds);
    }

    /**
     * Updates the record of relative bounds of this embedded TaskFragment, and checks whether we
     * should prepare a transition for the bounds change.
     */
    boolean shouldStartChangeTransition(@NonNull Rect absStartBounds,
            @NonNull Rect relStartBounds) {
        if (mTaskFragmentOrganizer == null || !canStartChangeTransition()) {
            return false;
        }

        // Only take snapshot if the bounds are resized.
        if (mTransitionController.isShellTransitionsEnabled()) {
            // For Shell transition, the change will be collected anyway, so only take snapshot when
            // the bounds are resized.
            final Rect endBounds = getConfiguration().windowConfiguration.getBounds();
        return endBounds.width() != startBounds.width()
                || endBounds.height() != startBounds.height();
            return endBounds.width() != absStartBounds.width()
                    || endBounds.height() != absStartBounds.height();
        } else {
            // For legacy transition, we need to trigger a change transition as long as the bounds
            // is changed, even if it is not resized.
            return !relStartBounds.equals(mRelativeEmbeddedBounds);
        }
    }

    /** Records the starting bounds of the closing organized TaskFragment. */
+7 −5
Original line number Diff line number Diff line
@@ -148,7 +148,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
    @VisibleForTesting
    final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>();

    private final Rect mTmpBounds = new Rect();
    private final Rect mTmpBounds0 = new Rect();
    private final Rect mTmpBounds1 = new Rect();

    WindowOrganizerController(ActivityTaskManagerService atm) {
        mService = atm;
@@ -803,14 +804,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
        // When the TaskFragment is resized, we may want to create a change transition for it, for
        // which we want to defer the surface update until we determine whether or not to start
        // change transition.
        mTmpBounds.set(taskFragment.getBounds());
        mTmpBounds0.set(taskFragment.getBounds());
        mTmpBounds1.set(taskFragment.getRelativeEmbeddedBounds());
        taskFragment.deferOrganizedTaskFragmentSurfaceUpdate();
        final int effects = applyChanges(taskFragment, c, errorCallbackToken);
        if (taskFragment.shouldStartChangeTransition(mTmpBounds)) {
            taskFragment.initializeChangeTransition(mTmpBounds);
        taskFragment.updateRelativeEmbeddedBounds();
        if (taskFragment.shouldStartChangeTransition(mTmpBounds0, mTmpBounds1)) {
            taskFragment.initializeChangeTransition(mTmpBounds0);
        }
        taskFragment.continueOrganizedTaskFragmentSurfaceUpdate();
        mTmpBounds.set(0, 0, 0, 0);
        return effects;
    }

+36 −2
Original line number Diff line number Diff line
@@ -106,19 +106,50 @@ public class TaskFragmentTest extends WindowTestsBase {
        verify(mTransaction).setWindowCrop(mLeash, 1000, 1000);
    }

    @Test
    public void testShouldStartChangeTransition_relativePositionChange() {
        mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer);
        final Rect startBounds = new Rect(0, 0, 500, 1000);
        final Rect endBounds = new Rect(500, 0, 1000, 1000);
        mTaskFragment.setBounds(startBounds);
        mTaskFragment.updateRelativeEmbeddedBounds();
        doReturn(true).when(mTaskFragment).isVisible();
        doReturn(true).when(mTaskFragment).isVisibleRequested();

        // Do not resize, just change the relative position.
        final Rect relStartBounds = new Rect(mTaskFragment.getRelativeEmbeddedBounds());
        mTaskFragment.setBounds(endBounds);
        mTaskFragment.updateRelativeEmbeddedBounds();
        spyOn(mDisplayContent.mTransitionController);

        // For Shell transition, we don't want to take snapshot when the bounds are not resized
        doReturn(true).when(mDisplayContent.mTransitionController)
                .isShellTransitionsEnabled();
        assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds));

        // For legacy transition, we want to request a change transition even if it is just relative
        // bounds change.
        doReturn(false).when(mDisplayContent.mTransitionController)
                .isShellTransitionsEnabled();
        assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds));
    }

    @Test
    public void testStartChangeTransition_resetSurface() {
        mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer);
        final Rect startBounds = new Rect(0, 0, 1000, 1000);
        final Rect endBounds = new Rect(500, 500, 1000, 1000);
        mTaskFragment.setBounds(startBounds);
        mTaskFragment.updateRelativeEmbeddedBounds();
        doReturn(true).when(mTaskFragment).isVisible();
        doReturn(true).when(mTaskFragment).isVisibleRequested();

        clearInvocations(mTransaction);
        final Rect relStartBounds = new Rect(mTaskFragment.getRelativeEmbeddedBounds());
        mTaskFragment.deferOrganizedTaskFragmentSurfaceUpdate();
        mTaskFragment.setBounds(endBounds);
        assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds));
        mTaskFragment.updateRelativeEmbeddedBounds();
        assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds));
        mTaskFragment.initializeChangeTransition(startBounds);
        mTaskFragment.continueOrganizedTaskFragmentSurfaceUpdate();

@@ -157,17 +188,20 @@ public class TaskFragmentTest extends WindowTestsBase {
        final Rect startBounds = new Rect(0, 0, 1000, 1000);
        final Rect endBounds = new Rect(500, 500, 1000, 1000);
        mTaskFragment.setBounds(startBounds);
        mTaskFragment.updateRelativeEmbeddedBounds();
        doReturn(true).when(mTaskFragment).isVisible();
        doReturn(true).when(mTaskFragment).isVisibleRequested();

        final Rect relStartBounds = new Rect(mTaskFragment.getRelativeEmbeddedBounds());
        final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
        displayPolicy.screenTurnedOff();

        assertFalse(mTaskFragment.okToAnimate());

        mTaskFragment.setBounds(endBounds);
        mTaskFragment.updateRelativeEmbeddedBounds();

        assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds));
        assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds));
    }

    /**