Loading services/core/java/com/android/server/wm/TaskFragment.java +20 −7 Original line number Diff line number Diff line Loading @@ -1407,14 +1407,22 @@ class TaskFragment extends WindowContainer<WindowContainer> { final TaskFragment otherTaskFrag = other.asTaskFragment(); if (otherTaskFrag != null && otherTaskFrag.hasAdjacentTaskFragment()) { // For adjacent TaskFragments, we have assumptions that: // 1. A set of adjacent TaskFragments always cover the entire Task window, so that // if this TaskFragment is behind a set of opaque TaskFragments, then this // TaskFragment is invisible. // 2. Adjacent TaskFragments do not overlap, so that if this TaskFragment is behind // any translucent TaskFragment in the adjacent set, then this TaskFragment is // visible behind translucent. if (Flags.allowMultipleAdjacentTaskFragments()) { final boolean hasTraversedAdj = otherTaskFrag.forOtherAdjacentTaskFragments( adjacentTaskFragments::contains); if (hasTraversedAdj) { final boolean isTranslucent = otherTaskFrag.isTranslucent(starting) || otherTaskFrag.forOtherAdjacentTaskFragments(adjacentTf -> { return adjacentTf.isTranslucent(starting); }); final boolean isTranslucent = isBehindTransparentTaskFragment(otherTaskFrag, starting) || otherTaskFrag.forOtherAdjacentTaskFragments( (Predicate<TaskFragment>) tf -> isBehindTransparentTaskFragment(tf, starting)); if (isTranslucent) { // Can be visible behind a translucent adjacent TaskFragments. gotTranslucentFullscreen = true; Loading @@ -1426,8 +1434,9 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } else { if (adjacentTaskFragments.contains(otherTaskFrag.mAdjacentTaskFragment)) { if (otherTaskFrag.isTranslucent(starting) || otherTaskFrag.mAdjacentTaskFragment.isTranslucent(starting)) { if (isBehindTransparentTaskFragment(otherTaskFrag, starting) || isBehindTransparentTaskFragment( otherTaskFrag.mAdjacentTaskFragment, starting)) { // Can be visible behind a translucent adjacent TaskFragments. gotTranslucentFullscreen = true; gotTranslucentAdjacent = true; Loading @@ -1439,7 +1448,6 @@ class TaskFragment extends WindowContainer<WindowContainer> { } adjacentTaskFragments.add(otherTaskFrag); } } if (!shouldBeVisible) { Loading @@ -1452,6 +1460,11 @@ class TaskFragment extends WindowContainer<WindowContainer> { : TASK_FRAGMENT_VISIBILITY_VISIBLE; } private boolean isBehindTransparentTaskFragment( @NonNull TaskFragment otherTf, @Nullable ActivityRecord starting) { return otherTf.isTranslucent(starting) && getBounds().intersect(otherTf.getBounds()); } private static boolean hasRunningActivity(WindowContainer wc) { if (wc.asTaskFragment() != null) { return wc.asTaskFragment().topRunningActivity() != null; Loading services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +71 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,9 @@ import static com.android.server.wm.TaskFragment.EMBEDDED_DIM_AREA_PARENT_TASK; import static com.android.server.wm.TaskFragment.EMBEDDED_DIM_AREA_TASK_FRAGMENT; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_INVISIBLE; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.junit.Assert.assertEquals; Loading Loading @@ -254,6 +257,74 @@ public class TaskFragmentTest extends WindowTestsBase { assertEquals(true, activityBelow.isVisibleRequested()); } @Test public void testVisibilityBehindOpaqueTaskFragment_withTranslucentTaskFragmentInTask() { final Task topTask = createTask(mDisplayContent); final Rect top = new Rect(); final Rect bottom = new Rect(); topTask.getBounds().splitVertically(top, bottom); final TaskFragment taskFragmentA = createTaskFragmentWithActivity(topTask); final TaskFragment taskFragmentB = createTaskFragmentWithActivity(topTask); final TaskFragment taskFragmentC = createTaskFragmentWithActivity(topTask); // B and C split the task window. A is behind B. C is translucent. taskFragmentA.setBounds(top); taskFragmentB.setBounds(top); taskFragmentC.setBounds(bottom); taskFragmentA.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentB.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentC.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentB.setAdjacentTaskFragments( new TaskFragment.AdjacentSet(taskFragmentB, taskFragmentC)); doReturn(true).when(taskFragmentC).isTranslucent(any()); // Ensure the activity below is visible topTask.ensureActivitiesVisible(null /* starting */); // B and C should be visible. A should be invisible. assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE, taskFragmentA.getVisibility(null /* starting */)); assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE, taskFragmentB.getVisibility(null /* starting */)); assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE, taskFragmentC.getVisibility(null /* starting */)); } @Test public void testVisibilityBehindTranslucentTaskFragment() { final Task topTask = createTask(mDisplayContent); final Rect top = new Rect(); final Rect bottom = new Rect(); topTask.getBounds().splitVertically(top, bottom); final TaskFragment taskFragmentA = createTaskFragmentWithActivity(topTask); final TaskFragment taskFragmentB = createTaskFragmentWithActivity(topTask); final TaskFragment taskFragmentC = createTaskFragmentWithActivity(topTask); // B and C split the task window. A is behind B. B is translucent. taskFragmentA.setBounds(top); taskFragmentB.setBounds(top); taskFragmentC.setBounds(bottom); taskFragmentA.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentB.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentC.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentB.setAdjacentTaskFragments( new TaskFragment.AdjacentSet(taskFragmentB, taskFragmentC)); doReturn(true).when(taskFragmentB).isTranslucent(any()); // Ensure the activity below is visible topTask.ensureActivitiesVisible(null /* starting */); // A, B and C should be visible. assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE, taskFragmentC.getVisibility(null /* starting */)); assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE, taskFragmentB.getVisibility(null /* starting */)); assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, taskFragmentA.getVisibility(null /* starting */)); } @Test public void testFindTopNonFinishingActivity_ignoresLaunchedFromBubbleActivities() { final ActivityOptions opts = ActivityOptions.makeBasic(); Loading Loading
services/core/java/com/android/server/wm/TaskFragment.java +20 −7 Original line number Diff line number Diff line Loading @@ -1407,14 +1407,22 @@ class TaskFragment extends WindowContainer<WindowContainer> { final TaskFragment otherTaskFrag = other.asTaskFragment(); if (otherTaskFrag != null && otherTaskFrag.hasAdjacentTaskFragment()) { // For adjacent TaskFragments, we have assumptions that: // 1. A set of adjacent TaskFragments always cover the entire Task window, so that // if this TaskFragment is behind a set of opaque TaskFragments, then this // TaskFragment is invisible. // 2. Adjacent TaskFragments do not overlap, so that if this TaskFragment is behind // any translucent TaskFragment in the adjacent set, then this TaskFragment is // visible behind translucent. if (Flags.allowMultipleAdjacentTaskFragments()) { final boolean hasTraversedAdj = otherTaskFrag.forOtherAdjacentTaskFragments( adjacentTaskFragments::contains); if (hasTraversedAdj) { final boolean isTranslucent = otherTaskFrag.isTranslucent(starting) || otherTaskFrag.forOtherAdjacentTaskFragments(adjacentTf -> { return adjacentTf.isTranslucent(starting); }); final boolean isTranslucent = isBehindTransparentTaskFragment(otherTaskFrag, starting) || otherTaskFrag.forOtherAdjacentTaskFragments( (Predicate<TaskFragment>) tf -> isBehindTransparentTaskFragment(tf, starting)); if (isTranslucent) { // Can be visible behind a translucent adjacent TaskFragments. gotTranslucentFullscreen = true; Loading @@ -1426,8 +1434,9 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } else { if (adjacentTaskFragments.contains(otherTaskFrag.mAdjacentTaskFragment)) { if (otherTaskFrag.isTranslucent(starting) || otherTaskFrag.mAdjacentTaskFragment.isTranslucent(starting)) { if (isBehindTransparentTaskFragment(otherTaskFrag, starting) || isBehindTransparentTaskFragment( otherTaskFrag.mAdjacentTaskFragment, starting)) { // Can be visible behind a translucent adjacent TaskFragments. gotTranslucentFullscreen = true; gotTranslucentAdjacent = true; Loading @@ -1439,7 +1448,6 @@ class TaskFragment extends WindowContainer<WindowContainer> { } adjacentTaskFragments.add(otherTaskFrag); } } if (!shouldBeVisible) { Loading @@ -1452,6 +1460,11 @@ class TaskFragment extends WindowContainer<WindowContainer> { : TASK_FRAGMENT_VISIBILITY_VISIBLE; } private boolean isBehindTransparentTaskFragment( @NonNull TaskFragment otherTf, @Nullable ActivityRecord starting) { return otherTf.isTranslucent(starting) && getBounds().intersect(otherTf.getBounds()); } private static boolean hasRunningActivity(WindowContainer wc) { if (wc.asTaskFragment() != null) { return wc.asTaskFragment().topRunningActivity() != null; Loading
services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +71 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,9 @@ import static com.android.server.wm.TaskFragment.EMBEDDED_DIM_AREA_PARENT_TASK; import static com.android.server.wm.TaskFragment.EMBEDDED_DIM_AREA_TASK_FRAGMENT; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_INVISIBLE; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.junit.Assert.assertEquals; Loading Loading @@ -254,6 +257,74 @@ public class TaskFragmentTest extends WindowTestsBase { assertEquals(true, activityBelow.isVisibleRequested()); } @Test public void testVisibilityBehindOpaqueTaskFragment_withTranslucentTaskFragmentInTask() { final Task topTask = createTask(mDisplayContent); final Rect top = new Rect(); final Rect bottom = new Rect(); topTask.getBounds().splitVertically(top, bottom); final TaskFragment taskFragmentA = createTaskFragmentWithActivity(topTask); final TaskFragment taskFragmentB = createTaskFragmentWithActivity(topTask); final TaskFragment taskFragmentC = createTaskFragmentWithActivity(topTask); // B and C split the task window. A is behind B. C is translucent. taskFragmentA.setBounds(top); taskFragmentB.setBounds(top); taskFragmentC.setBounds(bottom); taskFragmentA.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentB.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentC.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentB.setAdjacentTaskFragments( new TaskFragment.AdjacentSet(taskFragmentB, taskFragmentC)); doReturn(true).when(taskFragmentC).isTranslucent(any()); // Ensure the activity below is visible topTask.ensureActivitiesVisible(null /* starting */); // B and C should be visible. A should be invisible. assertEquals(TASK_FRAGMENT_VISIBILITY_INVISIBLE, taskFragmentA.getVisibility(null /* starting */)); assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE, taskFragmentB.getVisibility(null /* starting */)); assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE, taskFragmentC.getVisibility(null /* starting */)); } @Test public void testVisibilityBehindTranslucentTaskFragment() { final Task topTask = createTask(mDisplayContent); final Rect top = new Rect(); final Rect bottom = new Rect(); topTask.getBounds().splitVertically(top, bottom); final TaskFragment taskFragmentA = createTaskFragmentWithActivity(topTask); final TaskFragment taskFragmentB = createTaskFragmentWithActivity(topTask); final TaskFragment taskFragmentC = createTaskFragmentWithActivity(topTask); // B and C split the task window. A is behind B. B is translucent. taskFragmentA.setBounds(top); taskFragmentB.setBounds(top); taskFragmentC.setBounds(bottom); taskFragmentA.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentB.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentC.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); taskFragmentB.setAdjacentTaskFragments( new TaskFragment.AdjacentSet(taskFragmentB, taskFragmentC)); doReturn(true).when(taskFragmentB).isTranslucent(any()); // Ensure the activity below is visible topTask.ensureActivitiesVisible(null /* starting */); // A, B and C should be visible. assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE, taskFragmentC.getVisibility(null /* starting */)); assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE, taskFragmentB.getVisibility(null /* starting */)); assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT, taskFragmentA.getVisibility(null /* starting */)); } @Test public void testFindTopNonFinishingActivity_ignoresLaunchedFromBubbleActivities() { final ActivityOptions opts = ActivityOptions.makeBasic(); Loading