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

Commit b0122421 authored by Chris Li's avatar Chris Li Committed by Android (Google) Code Review
Browse files

Merge "Allow multiple adjacent TFs (5/n)" into main

parents 33b821c2 6d95ffe0
Loading
Loading
Loading
Loading
+15 −3
Original line number Diff line number Diff line
@@ -3523,10 +3523,18 @@ class TaskFragment extends WindowContainer<WindowContainer> {
                throw new IllegalStateException("allowMultipleAdjacentTaskFragments must be"
                        + " enabled to set more than two TaskFragments adjacent to each other.");
            }
            if (taskFragments.size() < 2) {
            final int size = taskFragments.size();
            if (size < 2) {
                throw new IllegalArgumentException("Adjacent TaskFragments must contain at least"
                        + " two TaskFragments, but only " + taskFragments.size()
                        + " were provided.");
                        + " two TaskFragments, but only " + size + " were provided.");
            }
            if (size > 2) {
                for (int i = 0; i < size; i++) {
                    if (taskFragments.valueAt(i).asTask() == null) {
                        throw new IllegalArgumentException(
                                "Not yet support 3+ adjacent for non-Task TFs");
                    }
                }
            }
            mAdjacentSet = taskFragments;
        }
@@ -3604,6 +3612,10 @@ class TaskFragment extends WindowContainer<WindowContainer> {
            return false;
        }

        int size() {
            return mAdjacentSet.size();
        }

        @Override
        public boolean equals(@Nullable Object o) {
            if (this == o) {
+49 −15
Original line number Diff line number Diff line
@@ -9150,7 +9150,7 @@ public class WindowManagerService extends IWindowManager.Stub
        // handling the touch-outside event to prevent focus rapid changes back-n-forth.
        final boolean shouldDelayTouchForEmbeddedActivity = activity != null
                && activity.isEmbedded()
                && activity.getTaskFragment().getAdjacentTaskFragment() != null;
                && activity.getTaskFragment().hasAdjacentTaskFragment();

        // For cases when there are multiple freeform windows where non-top windows are blocking
        // the gesture zones, delay handling the touch-outside event to prevent refocusing the
@@ -9529,9 +9529,13 @@ public class WindowManagerService extends IWindowManager.Stub
            return focusedActivity;
        }

        if (!taskFragment.hasAdjacentTaskFragment()) {
            return focusedActivity;
        }

        if (!Flags.allowMultipleAdjacentTaskFragments()) {
            final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
        final ActivityRecord adjacentTopActivity =
                adjacentTaskFragment != null ? adjacentTaskFragment.topRunningActivity() : null;
            final ActivityRecord adjacentTopActivity = adjacentTaskFragment.topRunningActivity();
            if (adjacentTopActivity == null) {
                // Return if no adjacent activity.
                return focusedActivity;
@@ -9546,6 +9550,22 @@ public class WindowManagerService extends IWindowManager.Stub
            return adjacentTopActivity;
        }

        // Find the adjacent activity with more recently active window.
        final ActivityRecord[] mostRecentActiveActivity = { focusedActivity };
        final long[] mostRecentActiveTime = { focusedActivity.getLastWindowCreateTime() };
        taskFragment.forOtherAdjacentTaskFragments(adjacentTaskFragment -> {
            final ActivityRecord adjacentTopActivity = adjacentTaskFragment.topRunningActivity();
            if (adjacentTopActivity != null) {
                final long lastWindowCreateTime = adjacentTopActivity.getLastWindowCreateTime();
                if (lastWindowCreateTime > mostRecentActiveTime[0]) {
                    mostRecentActiveTime[0] = lastWindowCreateTime;
                    mostRecentActiveActivity[0] = adjacentTopActivity;
                }
            }
        });
        return mostRecentActiveActivity[0];
    }

    @NonNull
    WindowState getMostRecentUsedEmbeddedWindowForBack(@NonNull WindowState focusedWindow) {
        final ActivityRecord focusedActivity = focusedWindow.getActivityRecord();
@@ -9592,14 +9612,28 @@ public class WindowManagerService extends IWindowManager.Stub
            return false;
        }
        final TaskFragment fromFragment = fromWin.getTaskFragment();
        if (fromFragment == null) {
        if (fromFragment == null || fromFragment.asTask() != null) {
            // Don't move the focus to another task.
            return false;
        }
        final TaskFragment adjacentFragment = fromFragment.getAdjacentTaskFragment();
        if (adjacentFragment == null || adjacentFragment.asTask() != null) {
            // Don't move the focus to another task.
        if (!fromFragment.hasAdjacentTaskFragment()) {
            // No adjacent window.
            return false;
        }
        final TaskFragment adjacentFragment;
        if (Flags.allowMultipleAdjacentTaskFragments()) {
            if (fromFragment.getAdjacentTaskFragments().size() > 2) {
                throw new IllegalStateException("Not yet support 3+ adjacent for non-Task TFs");
            }
            final TaskFragment[] tmpAdjacent = new TaskFragment[1];
            fromFragment.forOtherAdjacentTaskFragments(adjacentTF -> {
                tmpAdjacent[0] = adjacentTF;
                return true;
            });
            adjacentFragment = tmpAdjacent[0];
        } else {
            adjacentFragment = fromFragment.getAdjacentTaskFragment();
        }
        if (adjacentFragment.isIsolatedNav()) {
            // Don't move the focus if the adjacent TF is isolated navigation.
            return false;
+82 −69
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.clearInvocations;
@@ -1070,94 +1071,106 @@ public class TaskFragmentTest extends WindowTestsBase {

    @EnableFlags(Flags.FLAG_ALLOW_MULTIPLE_ADJACENT_TASK_FRAGMENTS)
    @Test
    public void testSetAdjacentTaskFragments() {
    public void testAdjacentSetForTaskFragments() {
        final Task task = createTask(mDisplayContent);
        final TaskFragment tf0 = createTaskFragmentWithActivity(task);
        final TaskFragment tf1 = createTaskFragmentWithActivity(task);
        final TaskFragment tf2 = createTaskFragmentWithActivity(task);
        final TaskFragment.AdjacentSet adjacentTfs = new TaskFragment.AdjacentSet(tf0, tf1, tf2);
        assertFalse(tf0.hasAdjacentTaskFragment());

        tf0.setAdjacentTaskFragments(adjacentTfs);

        assertSame(adjacentTfs, tf0.getAdjacentTaskFragments());
        assertSame(adjacentTfs, tf1.getAdjacentTaskFragments());
        assertSame(adjacentTfs, tf2.getAdjacentTaskFragments());
        assertTrue(tf0.hasAdjacentTaskFragment());
        assertTrue(tf1.hasAdjacentTaskFragment());
        assertTrue(tf2.hasAdjacentTaskFragment());

        final TaskFragment.AdjacentSet adjacentTfs2 = new TaskFragment.AdjacentSet(tf0, tf1);
        tf0.setAdjacentTaskFragments(adjacentTfs2);

        assertSame(adjacentTfs2, tf0.getAdjacentTaskFragments());
        assertSame(adjacentTfs2, tf1.getAdjacentTaskFragments());
        assertNull(tf2.getAdjacentTaskFragments());
        assertTrue(tf0.hasAdjacentTaskFragment());
        assertTrue(tf1.hasAdjacentTaskFragment());
        assertFalse(tf2.hasAdjacentTaskFragment());

        // Can have two TFs adjacent,
        new TaskFragment.AdjacentSet(tf0, tf1);

        // 3+ TFs adjacent is not yet supported.
        assertThrows(IllegalArgumentException.class,
                () -> new TaskFragment.AdjacentSet(tf0, tf1, tf2));
    }

    @EnableFlags(Flags.FLAG_ALLOW_MULTIPLE_ADJACENT_TASK_FRAGMENTS)
    @Test
    public void testClearAdjacentTaskFragments() {
        final Task task = createTask(mDisplayContent);
        final TaskFragment tf0 = createTaskFragmentWithActivity(task);
        final TaskFragment tf1 = createTaskFragmentWithActivity(task);
        final TaskFragment tf2 = createTaskFragmentWithActivity(task);
        final TaskFragment.AdjacentSet adjacentTfs = new TaskFragment.AdjacentSet(tf0, tf1, tf2);
        tf0.setAdjacentTaskFragments(adjacentTfs);

        tf0.clearAdjacentTaskFragments();
    public void testSetAdjacentTaskFragments() {
        final Task task0 = createTask(mDisplayContent);
        final Task task1 = createTask(mDisplayContent);
        final Task task2 = createTask(mDisplayContent);
        final TaskFragment.AdjacentSet adjTasks = new TaskFragment.AdjacentSet(task0, task1, task2);
        assertFalse(task0.hasAdjacentTaskFragment());

        task0.setAdjacentTaskFragments(adjTasks);

        assertSame(adjTasks, task0.getAdjacentTaskFragments());
        assertSame(adjTasks, task1.getAdjacentTaskFragments());
        assertSame(adjTasks, task2.getAdjacentTaskFragments());
        assertTrue(task0.hasAdjacentTaskFragment());
        assertTrue(task1.hasAdjacentTaskFragment());
        assertTrue(task2.hasAdjacentTaskFragment());

        final TaskFragment.AdjacentSet adjTasks2 = new TaskFragment.AdjacentSet(task0, task1);
        task0.setAdjacentTaskFragments(adjTasks2);

        assertSame(adjTasks2, task0.getAdjacentTaskFragments());
        assertSame(adjTasks2, task1.getAdjacentTaskFragments());
        assertNull(task2.getAdjacentTaskFragments());
        assertTrue(task0.hasAdjacentTaskFragment());
        assertTrue(task1.hasAdjacentTaskFragment());
        assertFalse(task2.hasAdjacentTaskFragment());
    }

        assertNull(tf0.getAdjacentTaskFragments());
        assertNull(tf1.getAdjacentTaskFragments());
        assertNull(tf2.getAdjacentTaskFragments());
        assertFalse(tf0.hasAdjacentTaskFragment());
        assertFalse(tf1.hasAdjacentTaskFragment());
        assertFalse(tf2.hasAdjacentTaskFragment());
    @EnableFlags(Flags.FLAG_ALLOW_MULTIPLE_ADJACENT_TASK_FRAGMENTS)
    @Test
    public void testClearAdjacentTaskFragments() {
        final Task task0 = createTask(mDisplayContent);
        final Task task1 = createTask(mDisplayContent);
        final Task task2 = createTask(mDisplayContent);
        final TaskFragment.AdjacentSet adjTasks = new TaskFragment.AdjacentSet(task0, task1, task2);
        task0.setAdjacentTaskFragments(adjTasks);

        task0.clearAdjacentTaskFragments();

        assertNull(task0.getAdjacentTaskFragments());
        assertNull(task1.getAdjacentTaskFragments());
        assertNull(task2.getAdjacentTaskFragments());
        assertFalse(task0.hasAdjacentTaskFragment());
        assertFalse(task1.hasAdjacentTaskFragment());
        assertFalse(task2.hasAdjacentTaskFragment());
    }

    @EnableFlags(Flags.FLAG_ALLOW_MULTIPLE_ADJACENT_TASK_FRAGMENTS)
    @Test
    public void testRemoveFromAdjacentTaskFragments() {
        final Task task = createTask(mDisplayContent);
        final TaskFragment tf0 = createTaskFragmentWithActivity(task);
        final TaskFragment tf1 = createTaskFragmentWithActivity(task);
        final TaskFragment tf2 = createTaskFragmentWithActivity(task);
        final TaskFragment.AdjacentSet adjacentTfs = new TaskFragment.AdjacentSet(tf0, tf1, tf2);
        tf0.setAdjacentTaskFragments(adjacentTfs);

        tf0.removeFromAdjacentTaskFragments();

        assertNull(tf0.getAdjacentTaskFragments());
        assertSame(adjacentTfs, tf1.getAdjacentTaskFragments());
        assertSame(adjacentTfs, tf2.getAdjacentTaskFragments());
        assertFalse(adjacentTfs.contains(tf0));
        assertTrue(tf1.isAdjacentTo(tf2));
        assertTrue(tf2.isAdjacentTo(tf1));
        assertFalse(tf1.isAdjacentTo(tf0));
        assertFalse(tf0.isAdjacentTo(tf1));
        assertFalse(tf0.isAdjacentTo(tf0));
        assertFalse(tf1.isAdjacentTo(tf1));
        final Task task0 = createTask(mDisplayContent);
        final Task task1 = createTask(mDisplayContent);
        final Task task2 = createTask(mDisplayContent);
        final TaskFragment.AdjacentSet adjTasks = new TaskFragment.AdjacentSet(task0, task1, task2);
        task0.setAdjacentTaskFragments(adjTasks);

        task0.removeFromAdjacentTaskFragments();

        assertNull(task0.getAdjacentTaskFragments());
        assertSame(adjTasks, task1.getAdjacentTaskFragments());
        assertSame(adjTasks, task2.getAdjacentTaskFragments());
        assertFalse(adjTasks.contains(task0));
        assertTrue(task1.isAdjacentTo(task2));
        assertTrue(task2.isAdjacentTo(task1));
        assertFalse(task1.isAdjacentTo(task0));
        assertFalse(task0.isAdjacentTo(task1));
        assertFalse(task0.isAdjacentTo(task0));
        assertFalse(task1.isAdjacentTo(task1));
    }

    @EnableFlags(Flags.FLAG_ALLOW_MULTIPLE_ADJACENT_TASK_FRAGMENTS)
    @Test
    public void testRemoveFromAdjacentTaskFragmentsWhenRemove() {
        final Task task = createTask(mDisplayContent);
        final TaskFragment tf0 = createTaskFragmentWithActivity(task);
        final TaskFragment tf1 = createTaskFragmentWithActivity(task);
        final TaskFragment tf2 = createTaskFragmentWithActivity(task);
        final TaskFragment.AdjacentSet adjacentTfs = new TaskFragment.AdjacentSet(tf0, tf1, tf2);
        tf0.setAdjacentTaskFragments(adjacentTfs);

        tf0.removeImmediately();

        assertNull(tf0.getAdjacentTaskFragments());
        assertSame(adjacentTfs, tf1.getAdjacentTaskFragments());
        assertSame(adjacentTfs, tf2.getAdjacentTaskFragments());
        assertFalse(adjacentTfs.contains(tf0));
        final Task task0 = createTask(mDisplayContent);
        final Task task1 = createTask(mDisplayContent);
        final Task task2 = createTask(mDisplayContent);
        final TaskFragment.AdjacentSet adjTasks = new TaskFragment.AdjacentSet(task0, task1, task2);
        task0.setAdjacentTaskFragments(adjTasks);

        task0.removeImmediately();

        assertNull(task0.getAdjacentTaskFragments());
        assertSame(adjTasks, task1.getAdjacentTaskFragments());
        assertSame(adjTasks, task2.getAdjacentTaskFragments());
        assertFalse(adjTasks.contains(task0));
    }

    private WindowState createAppWindow(ActivityRecord app, String name) {