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

Commit 4b86a040 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Ensure that participated activities are not omitted by ancestor

... when preparing transition targets.

Previously, the first step of the calculation finds the top participant
if possible, and once there is one, only the level above task will be
added. Because it assumes that the parent of participant can represent
it. But there are more than one participants belong to an ancestor, the
descendants may have individual changes, so they should be still in the
transition targets. Otherwise the animation may have nothing to do.

Now all valid participants are added into the target lists, and then
combine the targets from bottom to up based on depth. So it can be
done in 1 pass (originally it requires 3 passes when launching a new
task from home, 4 passes when starting recents).

The population of ChangeInfo#mParent is moved after tryPromo so it
can skip the targets which were removed, and the parent info can
be updated in a single place.

Bug: 213867980
Test: TransitionTests#testOpenActivityInTheSameTaskWithDisplayChange
Test: adb shell setprop persist.debug.shell_transit 1; reboot
      Start a landscape activity from a portrait activity in the
      same task. The animation should not jump cut.

Change-Id: I23a3326611dcb5664b204748280ae15b2377f318
parent d5b09e89
Loading
Loading
Loading
Loading
+24 −48
Original line number Diff line number Diff line
@@ -355,6 +355,12 @@
      "group": "WM_DEBUG_ORIENTATION",
      "at": "com\/android\/server\/wm\/DisplayRotation.java"
    },
    "-1728919185": {
      "message": "        unrelated invisible sibling %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "-1715268616": {
      "message": "Last window, removing starting window %s",
      "level": "VERBOSE",
@@ -451,12 +457,6 @@
      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
    },
    "-1587921395": {
      "message": "  Top targets: %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "-1585311008": {
      "message": "Bring to front target: %s from %s",
      "level": "DEBUG",
@@ -709,12 +709,6 @@
      "group": "WM_DEBUG_TASKS",
      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
    },
    "-1375751630": {
      "message": "  --- Start combine pass ---",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "-1364754753": {
      "message": "Task vanished taskId=%d",
      "level": "VERBOSE",
@@ -1177,12 +1171,6 @@
      "group": "WM_DEBUG_IME",
      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
    },
    "-855366859": {
      "message": "        merging children in from %s: %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "-853404763": {
      "message": "\twallpaper=%s",
      "level": "DEBUG",
@@ -1243,6 +1231,12 @@
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "-779095785": {
      "message": "        sibling is a participant with mode %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "-775004869": {
      "message": "Not a match: %s",
      "level": "DEBUG",
@@ -1555,12 +1549,6 @@
      "group": "WM_DEBUG_CONFIGURATION",
      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
    },
    "-446752714": {
      "message": "        SKIP: sibling contains top target %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "-445944810": {
      "message": "finish(%b): mCanceled=%b",
      "level": "DEBUG",
@@ -1729,12 +1717,6 @@
      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
    },
    "-302335479": {
      "message": "        remove from topTargets %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "-292790591": {
      "message": "Attempted to set IME policy to a display that does not exist: %d",
      "level": "WARN",
@@ -2077,6 +2059,12 @@
      "group": "WM_DEBUG_STARTING_WINDOW",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "112145970": {
      "message": "      SKIP: its sibling was rejected",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "114070759": {
      "message": "New wallpaper target: %s prevTarget: %s caller=%s",
      "level": "VERBOSE",
@@ -2413,6 +2401,12 @@
      "group": "WM_SHOW_SURFACE_ALLOC",
      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
    },
    "405146734": {
      "message": "  Final targets: %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "416924848": {
      "message": "InsetsSource Control %s for target %s",
      "level": "DEBUG",
@@ -2437,12 +2431,6 @@
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "430260320": {
      "message": "        sibling is a top target with mode %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "431715812": {
      "message": "Launch on display check: allow launch any on display",
      "level": "DEBUG",
@@ -2761,12 +2749,6 @@
      "group": "WM_SHOW_SURFACE_ALLOC",
      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
    },
    "751854538": {
      "message": "DisplayArea keep clear rects changed name =%s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_ORGANIZER",
      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
    },
    "765395228": {
      "message": "onAnimationFinished(): controller=%s reorderMode=%d",
      "level": "DEBUG",
@@ -3097,12 +3079,6 @@
      "group": "WM_DEBUG_WALLPAPER",
      "at": "com\/android\/server\/wm\/WallpaperController.java"
    },
    "1186730970": {
      "message": "          no common mode yet, so set it",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
      "at": "com\/android\/server\/wm\/Transition.java"
    },
    "1191587912": {
      "message": "Moved rootTask=%s behind rootTask=%s",
      "level": "DEBUG",
+187 −211

File changed.

Preview size limit exceeded, changes collapsed.

+5 −0
Original line number Diff line number Diff line
@@ -661,6 +661,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        }
    }

    /** Returns the total number of descendants, including self. */
    int getTreeWeight() {
        return mTreeWeight;
    }

    /**
     * @return The index of this element in the hierarchy tree in prefix order.
     */
+63 −28
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.SurfaceControl;
import android.view.TransactionCommittedListener;
import android.window.IDisplayAreaOrganizer;
import android.window.ITaskOrganizer;
import android.window.ITransitionPlayer;
import android.window.TransitionInfo;
@@ -60,6 +61,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@@ -106,7 +109,7 @@ public class TransitionTests extends WindowTestsBase {
        // Check basic both tasks participating
        participants.add(oldTask);
        participants.add(newTask);
        ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes);
        ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
        TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
        assertEquals(2, info.getChanges().size());
        assertEquals(transit, info.getType());
@@ -171,7 +174,7 @@ public class TransitionTests extends WindowTestsBase {
        participants.add(oldTask);
        participants.add(opening);
        participants.add(opening2);
        ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes);
        ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
        TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
        assertEquals(2, info.getChanges().size());
        assertEquals(transit, info.getType());
@@ -217,15 +220,14 @@ public class TransitionTests extends WindowTestsBase {
        // Check promotion to DisplayArea
        participants.add(showing);
        participants.add(showing2);
        ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes);
        ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
        TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
        assertEquals(1, info.getChanges().size());
        assertEquals(transit, info.getType());
        assertNotNull(info.getChange(tda.mRemoteToken.toWindowContainerToken()));

        ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
        // Check that organized tasks get reported even if not top
        showTask.mTaskOrganizer = mockOrg;
        makeTaskOrganized(showTask);
        targets = Transition.calculateTargets(participants, changes);
        info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
        assertEquals(2, info.getChanges().size());
@@ -255,7 +257,7 @@ public class TransitionTests extends WindowTestsBase {
        opening.mVisibleRequested = true;
        closing.mVisibleRequested = false;

        ArraySet<WindowContainer> targets = Transition.calculateTargets(
        ArrayList<WindowContainer> targets = Transition.calculateTargets(
                transition.mParticipants, transition.mChanges);
        TransitionInfo info = Transition.calculateTransitionInfo(
                0, 0, targets, transition.mChanges);
@@ -292,7 +294,7 @@ public class TransitionTests extends WindowTestsBase {
            tasks[i].getTopMostActivity().mVisibleRequested = (i % 2) != 0;
        }

        ArraySet<WindowContainer> targets = Transition.calculateTargets(
        ArrayList<WindowContainer> targets = Transition.calculateTargets(
                transition.mParticipants, transition.mChanges);
        TransitionInfo info = Transition.calculateTransitionInfo(
                0, 0, targets, transition.mChanges);
@@ -341,7 +343,7 @@ public class TransitionTests extends WindowTestsBase {
            tasks[i].getTopMostActivity().mVisibleRequested = (i % 2) != 0;
        }

        ArraySet<WindowContainer> targets = Transition.calculateTargets(
        ArrayList<WindowContainer> targets = Transition.calculateTargets(
                transition.mParticipants, transition.mChanges);
        TransitionInfo info = Transition.calculateTransitionInfo(
                0, 0, targets, transition.mChanges);
@@ -363,13 +365,7 @@ public class TransitionTests extends WindowTestsBase {
                mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
        // Make DA organized so we can check that they don't get included.
        WindowContainer parent = wallpaperWindowToken.getParent();
        while (parent != null && parent != mDisplayContent) {
            if (parent.asDisplayArea() != null) {
                parent.asDisplayArea().setOrganizer(
                        mock(android.window.IDisplayAreaOrganizer.class), true /* skipAppear */);
            }
            parent = parent.getParent();
        }
        makeDisplayAreaOrganized(parent, mDisplayContent);
        final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
                "wallpaperWindow");
        wallpaperWindowToken.setVisibleRequested(false);
@@ -381,7 +377,7 @@ public class TransitionTests extends WindowTestsBase {
        mDisplayContent.getWindowConfiguration().setRotation(
                (mDisplayContent.getWindowConfiguration().getRotation() + 1) % 4);

        ArraySet<WindowContainer> targets = Transition.calculateTargets(
        ArrayList<WindowContainer> targets = Transition.calculateTargets(
                transition.mParticipants, transition.mChanges);
        TransitionInfo info = Transition.calculateTransitionInfo(
                0, 0, targets, transition.mChanges);
@@ -393,12 +389,38 @@ public class TransitionTests extends WindowTestsBase {
                info.getChanges().get(0).getParent());
    }

    @Test
    public void testOpenActivityInTheSameTaskWithDisplayChange() {
        final ActivityRecord closing = createActivityRecord(mDisplayContent);
        closing.mVisibleRequested = true;
        final Task task = closing.getTask();
        makeTaskOrganized(task);
        final ActivityRecord opening = createActivityRecord(task);
        opening.mVisibleRequested = false;
        makeDisplayAreaOrganized(mDisplayContent.getDefaultTaskDisplayArea(), mDisplayContent);
        final WindowContainer<?>[] wcs = { closing, opening, task, mDisplayContent };
        final Transition transition = createTestTransition(TRANSIT_OPEN);
        for (WindowContainer<?> wc : wcs) {
            transition.collect(wc);
        }
        closing.mVisibleRequested = false;
        opening.mVisibleRequested = true;
        final int newRotation = mDisplayContent.getWindowConfiguration().getRotation() + 1;
        for (WindowContainer<?> wc : wcs) {
            wc.getWindowConfiguration().setRotation(newRotation);
        }

        final ArrayList<WindowContainer> targets = Transition.calculateTargets(
                transition.mParticipants, transition.mChanges);
        // Especially the activities must be in the targets.
        assertTrue(targets.containsAll(Arrays.asList(wcs)));
    }

    @Test
    public void testIndependent() {
        final Transition transition = createTestTransition(TRANSIT_OPEN);
        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
        ArraySet<WindowContainer> participants = transition.mParticipants;
        ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);

        final Task openTask = createTask(mDisplayContent);
        final Task openInOpenTask = createTaskInRootTask(openTask, 0);
@@ -410,10 +432,8 @@ public class TransitionTests extends WindowTestsBase {
        final ActivityRecord changeInChange = createActivityRecord(changeInChangeTask);
        final ActivityRecord openInChange = createActivityRecord(openInChangeTask);
        // set organizer for everything so that they all get added to transition info
        for (Task t : new Task[]{
                openTask, openInOpenTask, changeTask, changeInChangeTask, openInChangeTask}) {
            t.mTaskOrganizer = mockOrg;
        }
        makeTaskOrganized(openTask, openInOpenTask, changeTask, changeInChangeTask,
                openInChangeTask);

        // Start states.
        changes.put(openTask, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
@@ -440,7 +460,8 @@ public class TransitionTests extends WindowTestsBase {
        participants.add(openInChange);
        // Explicitly add changeTask (to test independence with parents)
        participants.add(changeTask);
        ArraySet<WindowContainer> targets = Transition.calculateTargets(participants, changes);
        final ArrayList<WindowContainer> targets =
                Transition.calculateTargets(participants, changes);
        TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, changes);
        // Root changes should always be considered independent
        assertTrue(isIndependent(
@@ -581,17 +602,15 @@ public class TransitionTests extends WindowTestsBase {
        final TransitionController controller = new TransitionController(mAtm, snapshotController);
        final ITransitionPlayer player = new ITransitionPlayer.Default();
        controller.registerTransitionPlayer(player, null /* appThread */);
        ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
        final Transition openTransition = controller.createTransition(TRANSIT_OPEN);

        // Start out with task2 visible and set up a transition that closes task2 and opens task1
        final Task task1 = createTask(mDisplayContent);
        task1.mTaskOrganizer = mockOrg;
        final ActivityRecord activity1 = createActivityRecord(task1);
        activity1.mVisibleRequested = false;
        activity1.setVisible(false);
        final Task task2 = createTask(mDisplayContent);
        task2.mTaskOrganizer = mockOrg;
        makeTaskOrganized(task1, task2);
        final ActivityRecord activity2 = createActivityRecord(task1);
        activity2.mVisibleRequested = true;
        activity2.setVisible(true);
@@ -647,17 +666,15 @@ public class TransitionTests extends WindowTestsBase {
        final TransitionController controller = new TransitionController(mAtm, snapshotController);
        final ITransitionPlayer player = new ITransitionPlayer.Default();
        controller.registerTransitionPlayer(player, null /* appThread */);
        ITaskOrganizer mockOrg = mock(ITaskOrganizer.class);
        final Transition openTransition = controller.createTransition(TRANSIT_OPEN);

        // Start out with task2 visible and set up a transition that closes task2 and opens task1
        final Task task1 = createTask(mDisplayContent);
        task1.mTaskOrganizer = mockOrg;
        final ActivityRecord activity1 = createActivityRecord(task1);
        activity1.mVisibleRequested = false;
        activity1.setVisible(false);
        final Task task2 = createTask(mDisplayContent);
        task2.mTaskOrganizer = mockOrg;
        makeTaskOrganized(task1, task2);
        final ActivityRecord activity2 = createActivityRecord(task2);
        activity2.mVisibleRequested = true;
        activity2.setVisible(true);
@@ -706,6 +723,24 @@ public class TransitionTests extends WindowTestsBase {
        verify(snapshotController, times(1)).recordTaskSnapshot(eq(task1), eq(false));
    }

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

    private static void makeDisplayAreaOrganized(WindowContainer<?> from,
            WindowContainer<?> end) {
        final IDisplayAreaOrganizer organizer = mock(IDisplayAreaOrganizer.class);
        while (from != null && from != end) {
            if (from.asDisplayArea() != null) {
                from.asDisplayArea().mOrganizer = organizer;
            }
            from = from.getParent();
        }
    }

    /** Fill the change map with all the parents of top. Change maps are usually fully populated */
    private static void fillChangeMap(ArrayMap<WindowContainer, Transition.ChangeInfo> changes,
            WindowContainer top) {