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

Commit 1ba311c2 authored by Chris Li's avatar Chris Li
Browse files

Include embedding activity change in transition

When enter ActivityEmbedding split, we will reparent the fill parent
activity to an embedded TaskFragment of different size. Before, because
the embedded TaskFragment is also a change target, the activity will be
excluded from the change targets. Now, we also include such activity so
that we can animate the transition of it.

Bug: 207070762
Test: atest WmTests:TransitionTests#testIncludeEmbeddedActivityReparent
Change-Id: I2de3a6e9ba2f74e455c56abd24010fff2c51e53d
parent fe1eba3a
Loading
Loading
Loading
Loading
+19 −9
Original line number Diff line number Diff line
@@ -1192,7 +1192,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
            return false;
        }

        final @TransitionInfo.TransitionMode int mode = changes.get(target).getTransitMode(target);
        final ChangeInfo change = changes.get(target);
        if (change.mStartParent != null && target.getParent() != change.mStartParent) {
            // When a window is reparented, the state change won't fit into any of the parents.
            // Don't promote such change so that we can animate the reparent if needed.
            return false;
        }

        final @TransitionInfo.TransitionMode int mode = change.getTransitMode(target);
        for (int i = parent.getChildCount() - 1; i >= 0; --i) {
            final WindowContainer<?> sibling = parent.getChildAt(i);
            if (target == sibling) continue;
@@ -1332,14 +1339,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
                    // Intermediate parents must be those that has window to be managed by Shell.
                    continue;
                }
                if (parentChange.mParent != null && !skipIntermediateReports) {
                    changes.get(wc).mParent = p;
                if (parentChange.mEndParent != null && !skipIntermediateReports) {
                    changes.get(wc).mEndParent = p;
                    // The chain above the parent was processed.
                    break;
                }
                if (targetList.contains(p)) {
                    if (skipIntermediateReports) {
                        changes.get(wc).mParent = p;
                        changes.get(wc).mEndParent = p;
                    } else {
                        intermediates.add(p);
                    }
@@ -1351,10 +1358,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
            }
            if (!foundParentInTargets || intermediates.isEmpty()) continue;
            // Add any always-report parents along the way.
            changes.get(wc).mParent = intermediates.get(0);
            changes.get(wc).mEndParent = intermediates.get(0);
            for (int j = 0; j < intermediates.size() - 1; j++) {
                final WindowContainer<?> intermediate = intermediates.get(j);
                changes.get(intermediate).mParent = intermediates.get(j + 1);
                changes.get(intermediate).mEndParent = intermediates.get(j + 1);
                targets.add(intermediate);
            }
        }
@@ -1467,8 +1474,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
                    target.mRemoteToken != null ? target.mRemoteToken.toWindowContainerToken()
                            : null, getLeashSurface(target, startT));
            // TODO(shell-transitions): Use leash for non-organized windows.
            if (info.mParent != null) {
                change.setParent(info.mParent.mRemoteToken.toWindowContainerToken());
            if (info.mEndParent != null) {
                change.setParent(info.mEndParent.mRemoteToken.toWindowContainerToken());
            }
            change.setMode(info.getTransitMode(target));
            change.setStartAbsBounds(info.mAbsoluteBounds);
@@ -1651,7 +1658,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
        @interface Flag {}

        // Usually "post" change state.
        WindowContainer mParent;
        WindowContainer mEndParent;
        // Parent before change state.
        WindowContainer mStartParent;

        // State tracking
        boolean mExistenceChanged = false;
@@ -1672,6 +1681,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
            mAbsoluteBounds.set(origState.getBounds());
            mShowWallpaper = origState.showWallpaper();
            mRotation = origState.getWindowConfiguration().getRotation();
            mStartParent = origState.getParent();
        }

        @VisibleForTesting
+35 −0
Original line number Diff line number Diff line
@@ -36,8 +36,10 @@ import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import static android.window.TransitionInfo.isIndependent;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.WindowContainer.POSITION_TOP;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -1079,6 +1081,39 @@ public class TransitionTests extends WindowTestsBase {
        assertTrue((info.getChanges().get(1).getFlags() & FLAG_IS_EMBEDDED) != 0);
    }

    @Test
    public void testIncludeEmbeddedActivityReparent() {
        final Transition transition = createTestTransition(TRANSIT_OPEN);
        final Task task = createTask(mDisplayContent);
        task.setBounds(new Rect(0, 0, 2000, 1000));
        final ActivityRecord activity = createActivityRecord(task);
        activity.mVisibleRequested = true;
        // Skip manipulate the SurfaceControl.
        doNothing().when(activity).setDropInputMode(anyInt());
        final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
        mAtm.mTaskFragmentOrganizerController.registerOrganizer(
                ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()));
        final TaskFragment embeddedTf = new TaskFragmentBuilder(mAtm)
                .setParentTask(task)
                .setOrganizer(organizer)
                .build();
        // TaskFragment with different bounds from Task.
        embeddedTf.setBounds(new Rect(0, 0, 1000, 1000));

        // Start states.
        transition.collect(activity);
        transition.collectExistenceChange(embeddedTf);

        // End states.
        activity.reparent(embeddedTf, POSITION_TOP);

        // Verify that both activity and TaskFragment are included.
        final ArrayList<WindowContainer> targets = Transition.calculateTargets(
                transition.mParticipants, transition.mChanges);
        assertTrue(targets.contains(embeddedTf));
        assertTrue(targets.contains(activity));
    }

    private static void makeTaskOrganized(Task... tasks) {
        final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
        for (Task t : tasks) {