Loading services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +41 −22 Original line number Original line Diff line number Diff line Loading @@ -274,7 +274,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } } // Even though we want to keep original bounds, we still don't want it to stomp on // Even though we want to keep original bounds, we still don't want it to stomp on // an existing task. // an existing task. adjustBoundsToAvoidConflict(display, outParams.mBounds); adjustBoundsToAvoidConflictInDisplay(display, outParams.mBounds); } } } else { } else { if (source != null && source.inFreeformWindowingMode() if (source != null && source.inFreeformWindowingMode() Loading Loading @@ -534,7 +534,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } } // Lastly we adjust bounds to avoid conflicts with other tasks as much as possible. // Lastly we adjust bounds to avoid conflicts with other tasks as much as possible. adjustBoundsToAvoidConflict(display, inOutBounds); adjustBoundsToAvoidConflictInDisplay(display, inOutBounds); } } private int convertOrientationToScreenOrientation(int orientation) { private int convertOrientationToScreenOrientation(int orientation) { Loading Loading @@ -678,16 +678,9 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { * @param display the display which tasks are to check * @param display the display which tasks are to check * @param inOutBounds the bounds used to input initial bounds and output result bounds * @param inOutBounds the bounds used to input initial bounds and output result bounds */ */ private void adjustBoundsToAvoidConflict(@NonNull ActivityDisplay display, private void adjustBoundsToAvoidConflictInDisplay(@NonNull ActivityDisplay display, @NonNull Rect inOutBounds) { @NonNull Rect inOutBounds) { final Rect displayBounds = display.getBounds(); final List<Rect> taskBoundsToCheck = new ArrayList<>(); if (!displayBounds.contains(inOutBounds)) { // The initial bounds are already out of display. The scanning algorithm below doesn't // work so well with them. return; } final List<TaskRecord> tasksToCheck = new ArrayList<>(); for (int i = 0; i < display.getChildCount(); ++i) { for (int i = 0; i < display.getChildCount(); ++i) { final ActivityStack stack = display.getChildAt(i); final ActivityStack stack = display.getChildAt(i); if (!stack.inFreeformWindowingMode()) { if (!stack.inFreeformWindowingMode()) { Loading @@ -695,11 +688,35 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } } for (int j = 0; j < stack.getChildCount(); ++j) { for (int j = 0; j < stack.getChildCount(); ++j) { tasksToCheck.add(stack.getChildAt(j)); taskBoundsToCheck.add(stack.getChildAt(j).getBounds()); } } adjustBoundsToAvoidConflict(display.getBounds(), taskBoundsToCheck, inOutBounds); } } /** * Adjusts input bounds to avoid conflict with provided display bounds and list of tasks bounds * for the display. * * Scans the bounds in directions to find a candidate location that does not conflict with the * provided list of task bounds. If starting bounds are outside the display bounds or if no * suitable candidate bounds are found, the method returns the input bounds. * * @param displayBounds display bounds used to restrict the candidate bounds * @param taskBoundsToCheck list of task bounds to check for conflict * @param inOutBounds the bounds used to input initial bounds and output result bounds */ @VisibleForTesting void adjustBoundsToAvoidConflict(@NonNull Rect displayBounds, @NonNull List<Rect> taskBoundsToCheck, @NonNull Rect inOutBounds) { if (!displayBounds.contains(inOutBounds)) { // The initial bounds are already out of display. The scanning algorithm below doesn't // work so well with them. return; } } if (!boundsConflict(tasksToCheck, inOutBounds)) { if (!boundsConflict(taskBoundsToCheck, inOutBounds)) { // Current proposal doesn't conflict with any task. Early return to avoid unnecessary // Current proposal doesn't conflict with any task. Early return to avoid unnecessary // calculation. // calculation. return; return; Loading @@ -713,11 +730,13 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } } mTmpBounds.set(inOutBounds); mTmpBounds.set(inOutBounds); while (boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) { while (boundsConflict(taskBoundsToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) { shiftBounds(direction, displayBounds, mTmpBounds); shiftBounds(direction, displayBounds, mTmpBounds); } } if (!boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) { if (!boundsConflict(taskBoundsToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) { // Found a candidate. Just use this. // Found a candidate. Just use this. inOutBounds.set(mTmpBounds); inOutBounds.set(mTmpBounds); if (DEBUG) appendLog("avoid-bounds-conflict=" + inOutBounds); if (DEBUG) appendLog("avoid-bounds-conflict=" + inOutBounds); Loading Loading @@ -772,16 +791,16 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { mTmpDirections[1] = Gravity.TOP | Gravity.LEFT; mTmpDirections[1] = Gravity.TOP | Gravity.LEFT; } } private boolean boundsConflict(@NonNull List<TaskRecord> tasks, @NonNull Rect bounds) { private boolean boundsConflict(@NonNull List<Rect> taskBoundsToCheck, for (TaskRecord task : tasks) { @NonNull Rect candidateBounds) { final Rect taskBounds = task.getBounds(); for (Rect taskBounds : taskBoundsToCheck) { final boolean leftClose = Math.abs(taskBounds.left - bounds.left) final boolean leftClose = Math.abs(taskBounds.left - candidateBounds.left) < BOUNDS_CONFLICT_THRESHOLD; < BOUNDS_CONFLICT_THRESHOLD; final boolean topClose = Math.abs(taskBounds.top - bounds.top) final boolean topClose = Math.abs(taskBounds.top - candidateBounds.top) < BOUNDS_CONFLICT_THRESHOLD; < BOUNDS_CONFLICT_THRESHOLD; final boolean rightClose = Math.abs(taskBounds.right - bounds.right) final boolean rightClose = Math.abs(taskBounds.right - candidateBounds.right) < BOUNDS_CONFLICT_THRESHOLD; < BOUNDS_CONFLICT_THRESHOLD; final boolean bottomClose = Math.abs(taskBounds.bottom - bounds.bottom) final boolean bottomClose = Math.abs(taskBounds.bottom - candidateBounds.bottom) < BOUNDS_CONFLICT_THRESHOLD; < BOUNDS_CONFLICT_THRESHOLD; if ((leftClose && topClose) || (leftClose && bottomClose) || (rightClose && topClose) if ((leftClose && topClose) || (leftClose && bottomClose) || (rightClose && topClose) Loading services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +19 −0 Original line number Original line Diff line number Diff line Loading @@ -52,6 +52,8 @@ import com.android.server.wm.LaunchParamsController.LaunchParams; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Locale; /** /** Loading Loading @@ -1206,6 +1208,23 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(new Rect(120, 0, 320, 100), mResult.mBounds); assertEquals(new Rect(120, 0, 320, 100), mResult.mBounds); } } @Test public void testAdjustBoundsToAvoidConflictAlwaysExits() { Rect displayBounds = new Rect(0, 0, 40, 40); List<Rect> existingTaskBounds = new ArrayList<>(); for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { int left = i * 5; int top = j * 5; existingTaskBounds.add(new Rect(left, top, left + 20, top + 20)); } } Rect startingBounds = new Rect(0, 0, 20, 20); Rect adjustedBounds = new Rect(startingBounds); mTarget.adjustBoundsToAvoidConflict(displayBounds, existingTaskBounds, adjustedBounds); assertEquals(startingBounds, adjustedBounds); } private TestActivityDisplay createNewActivityDisplay(int windowingMode) { private TestActivityDisplay createNewActivityDisplay(int windowingMode) { final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); display.setWindowingMode(windowingMode); display.setWindowingMode(windowingMode); Loading Loading
services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +41 −22 Original line number Original line Diff line number Diff line Loading @@ -274,7 +274,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } } // Even though we want to keep original bounds, we still don't want it to stomp on // Even though we want to keep original bounds, we still don't want it to stomp on // an existing task. // an existing task. adjustBoundsToAvoidConflict(display, outParams.mBounds); adjustBoundsToAvoidConflictInDisplay(display, outParams.mBounds); } } } else { } else { if (source != null && source.inFreeformWindowingMode() if (source != null && source.inFreeformWindowingMode() Loading Loading @@ -534,7 +534,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } } // Lastly we adjust bounds to avoid conflicts with other tasks as much as possible. // Lastly we adjust bounds to avoid conflicts with other tasks as much as possible. adjustBoundsToAvoidConflict(display, inOutBounds); adjustBoundsToAvoidConflictInDisplay(display, inOutBounds); } } private int convertOrientationToScreenOrientation(int orientation) { private int convertOrientationToScreenOrientation(int orientation) { Loading Loading @@ -678,16 +678,9 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { * @param display the display which tasks are to check * @param display the display which tasks are to check * @param inOutBounds the bounds used to input initial bounds and output result bounds * @param inOutBounds the bounds used to input initial bounds and output result bounds */ */ private void adjustBoundsToAvoidConflict(@NonNull ActivityDisplay display, private void adjustBoundsToAvoidConflictInDisplay(@NonNull ActivityDisplay display, @NonNull Rect inOutBounds) { @NonNull Rect inOutBounds) { final Rect displayBounds = display.getBounds(); final List<Rect> taskBoundsToCheck = new ArrayList<>(); if (!displayBounds.contains(inOutBounds)) { // The initial bounds are already out of display. The scanning algorithm below doesn't // work so well with them. return; } final List<TaskRecord> tasksToCheck = new ArrayList<>(); for (int i = 0; i < display.getChildCount(); ++i) { for (int i = 0; i < display.getChildCount(); ++i) { final ActivityStack stack = display.getChildAt(i); final ActivityStack stack = display.getChildAt(i); if (!stack.inFreeformWindowingMode()) { if (!stack.inFreeformWindowingMode()) { Loading @@ -695,11 +688,35 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } } for (int j = 0; j < stack.getChildCount(); ++j) { for (int j = 0; j < stack.getChildCount(); ++j) { tasksToCheck.add(stack.getChildAt(j)); taskBoundsToCheck.add(stack.getChildAt(j).getBounds()); } } adjustBoundsToAvoidConflict(display.getBounds(), taskBoundsToCheck, inOutBounds); } } /** * Adjusts input bounds to avoid conflict with provided display bounds and list of tasks bounds * for the display. * * Scans the bounds in directions to find a candidate location that does not conflict with the * provided list of task bounds. If starting bounds are outside the display bounds or if no * suitable candidate bounds are found, the method returns the input bounds. * * @param displayBounds display bounds used to restrict the candidate bounds * @param taskBoundsToCheck list of task bounds to check for conflict * @param inOutBounds the bounds used to input initial bounds and output result bounds */ @VisibleForTesting void adjustBoundsToAvoidConflict(@NonNull Rect displayBounds, @NonNull List<Rect> taskBoundsToCheck, @NonNull Rect inOutBounds) { if (!displayBounds.contains(inOutBounds)) { // The initial bounds are already out of display. The scanning algorithm below doesn't // work so well with them. return; } } if (!boundsConflict(tasksToCheck, inOutBounds)) { if (!boundsConflict(taskBoundsToCheck, inOutBounds)) { // Current proposal doesn't conflict with any task. Early return to avoid unnecessary // Current proposal doesn't conflict with any task. Early return to avoid unnecessary // calculation. // calculation. return; return; Loading @@ -713,11 +730,13 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } } mTmpBounds.set(inOutBounds); mTmpBounds.set(inOutBounds); while (boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) { while (boundsConflict(taskBoundsToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) { shiftBounds(direction, displayBounds, mTmpBounds); shiftBounds(direction, displayBounds, mTmpBounds); } } if (!boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) { if (!boundsConflict(taskBoundsToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) { // Found a candidate. Just use this. // Found a candidate. Just use this. inOutBounds.set(mTmpBounds); inOutBounds.set(mTmpBounds); if (DEBUG) appendLog("avoid-bounds-conflict=" + inOutBounds); if (DEBUG) appendLog("avoid-bounds-conflict=" + inOutBounds); Loading Loading @@ -772,16 +791,16 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { mTmpDirections[1] = Gravity.TOP | Gravity.LEFT; mTmpDirections[1] = Gravity.TOP | Gravity.LEFT; } } private boolean boundsConflict(@NonNull List<TaskRecord> tasks, @NonNull Rect bounds) { private boolean boundsConflict(@NonNull List<Rect> taskBoundsToCheck, for (TaskRecord task : tasks) { @NonNull Rect candidateBounds) { final Rect taskBounds = task.getBounds(); for (Rect taskBounds : taskBoundsToCheck) { final boolean leftClose = Math.abs(taskBounds.left - bounds.left) final boolean leftClose = Math.abs(taskBounds.left - candidateBounds.left) < BOUNDS_CONFLICT_THRESHOLD; < BOUNDS_CONFLICT_THRESHOLD; final boolean topClose = Math.abs(taskBounds.top - bounds.top) final boolean topClose = Math.abs(taskBounds.top - candidateBounds.top) < BOUNDS_CONFLICT_THRESHOLD; < BOUNDS_CONFLICT_THRESHOLD; final boolean rightClose = Math.abs(taskBounds.right - bounds.right) final boolean rightClose = Math.abs(taskBounds.right - candidateBounds.right) < BOUNDS_CONFLICT_THRESHOLD; < BOUNDS_CONFLICT_THRESHOLD; final boolean bottomClose = Math.abs(taskBounds.bottom - bounds.bottom) final boolean bottomClose = Math.abs(taskBounds.bottom - candidateBounds.bottom) < BOUNDS_CONFLICT_THRESHOLD; < BOUNDS_CONFLICT_THRESHOLD; if ((leftClose && topClose) || (leftClose && bottomClose) || (rightClose && topClose) if ((leftClose && topClose) || (leftClose && bottomClose) || (rightClose && topClose) Loading
services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +19 −0 Original line number Original line Diff line number Diff line Loading @@ -52,6 +52,8 @@ import com.android.server.wm.LaunchParamsController.LaunchParams; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Locale; /** /** Loading Loading @@ -1206,6 +1208,23 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { assertEquals(new Rect(120, 0, 320, 100), mResult.mBounds); assertEquals(new Rect(120, 0, 320, 100), mResult.mBounds); } } @Test public void testAdjustBoundsToAvoidConflictAlwaysExits() { Rect displayBounds = new Rect(0, 0, 40, 40); List<Rect> existingTaskBounds = new ArrayList<>(); for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { int left = i * 5; int top = j * 5; existingTaskBounds.add(new Rect(left, top, left + 20, top + 20)); } } Rect startingBounds = new Rect(0, 0, 20, 20); Rect adjustedBounds = new Rect(startingBounds); mTarget.adjustBoundsToAvoidConflict(displayBounds, existingTaskBounds, adjustedBounds); assertEquals(startingBounds, adjustedBounds); } private TestActivityDisplay createNewActivityDisplay(int windowingMode) { private TestActivityDisplay createNewActivityDisplay(int windowingMode) { final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP); display.setWindowingMode(windowingMode); display.setWindowingMode(windowingMode); Loading