diff options
| author | 2024-12-23 21:18:20 -0800 | |
|---|---|---|
| committer | 2024-12-23 21:18:20 -0800 | |
| commit | b012242117fc852069753b404c59dcfd32133694 (patch) | |
| tree | f22d0f04594f2d456296767fb9ab00f788d32287 | |
| parent | 33b821c22d95b1007e40a668894ecf4480de1c99 (diff) | |
| parent | 6d95ffe00fc0b208e0aa1bc8e4b22880700459d2 (diff) | |
Merge "Allow multiple adjacent TFs (5/n)" into main
3 files changed, 146 insertions, 87 deletions
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index cb6b69072e14..7b7b3eb17ddd 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -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) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 793f18992109..965b22473a2c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -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,21 +9529,41 @@ public class WindowManagerService extends IWindowManager.Stub return focusedActivity; } - final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment(); - final ActivityRecord adjacentTopActivity = - adjacentTaskFragment != null ? adjacentTaskFragment.topRunningActivity() : null; - if (adjacentTopActivity == null) { - // Return if no adjacent activity. + if (!taskFragment.hasAdjacentTaskFragment()) { return focusedActivity; } - if (adjacentTopActivity.getLastWindowCreateTime() - < focusedActivity.getLastWindowCreateTime()) { - // Return if the current focus activity has more recently active window. - return focusedActivity; + if (!Flags.allowMultipleAdjacentTaskFragments()) { + final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment(); + final ActivityRecord adjacentTopActivity = adjacentTaskFragment.topRunningActivity(); + if (adjacentTopActivity == null) { + // Return if no adjacent activity. + return focusedActivity; + } + + if (adjacentTopActivity.getLastWindowCreateTime() + < focusedActivity.getLastWindowCreateTime()) { + // Return if the current focus activity has more recently active window. + return focusedActivity; + } + + return adjacentTopActivity; } - 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 @@ -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; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index 35a2546fca1a..c0f251e06d17 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -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) { |