Loading services/core/java/com/android/server/wm/TaskRecord.java +25 −30 Original line number Diff line number Diff line Loading @@ -202,13 +202,6 @@ class TaskRecord extends ConfigurationContainer { // Do not move the stack as a part of reparenting static final int REPARENT_LEAVE_STACK_IN_PLACE = 2; // The height/width divide used when fitting a task within a bounds with method // {@link #fitWithinBounds}. // We always want the task to to be visible in the bounds without affecting its size when // fitting. To make sure this is the case, we don't adjust the task left or top side pass // the input bounds right or bottom side minus the width or height divided by this value. private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3; /** * The factory used to create {@link TaskRecord}. This allows OEM subclass {@link TaskRecord}. */ Loading Loading @@ -1932,35 +1925,33 @@ class TaskRecord extends ConfigurationContainer { * * @param bounds Bounds to be adjusted. * @param stackBounds Bounds within which the other bounds should remain. * @param overlapPxX The amount of px required to be visible in the X dimension. * @param overlapPxY The amount of px required to be visible in the Y dimension. */ private static void fitWithinBounds(Rect bounds, Rect stackBounds) { private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX, int overlapPxY) { if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) { return; } if (bounds.left < stackBounds.left || bounds.right > stackBounds.right) { final int maxRight = stackBounds.right - (stackBounds.width() / FIT_WITHIN_BOUNDS_DIVIDER); int horizontalDiff = stackBounds.left - bounds.left; if ((horizontalDiff < 0 && bounds.left >= maxRight) || (bounds.left + horizontalDiff >= maxRight)) { horizontalDiff = maxRight - bounds.left; } bounds.left += horizontalDiff; bounds.right += horizontalDiff; // For each side of the parent (eg. left), check if the opposing side of the window (eg. // right) is at least overlap pixels away. If less, offset the window by that difference. int horizontalDiff = 0; // If window is smaller than overlap, use it's smallest dimension instead int overlapLR = Math.min(overlapPxX, bounds.width()); if (bounds.right < (stackBounds.left + overlapLR)) { horizontalDiff = overlapLR - (bounds.right - stackBounds.left); } else if (bounds.left > (stackBounds.right - overlapLR)) { horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left)); } if (bounds.top < stackBounds.top || bounds.bottom > stackBounds.bottom) { final int maxBottom = stackBounds.bottom - (stackBounds.height() / FIT_WITHIN_BOUNDS_DIVIDER); int verticalDiff = stackBounds.top - bounds.top; if ((verticalDiff < 0 && bounds.top >= maxBottom) || (bounds.top + verticalDiff >= maxBottom)) { verticalDiff = maxBottom - bounds.top; } bounds.top += verticalDiff; bounds.bottom += verticalDiff; int verticalDiff = 0; int overlapTB = Math.min(overlapPxY, bounds.width()); if (bounds.bottom < (stackBounds.top + overlapTB)) { verticalDiff = overlapTB - (bounds.bottom - stackBounds.top); } else if (bounds.top > (stackBounds.bottom - overlapTB)) { verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top)); } bounds.offset(horizontalDiff, verticalDiff); } /** Loading Loading @@ -2230,7 +2221,11 @@ class TaskRecord extends ConfigurationContainer { adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds); if (windowingMode == WINDOWING_MODE_FREEFORM) { // by policy, make sure the window remains within parent somewhere fitWithinBounds(outOverrideBounds, newParentConfig.windowConfiguration.getBounds()); final float density = ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT; fitWithinBounds(outOverrideBounds, newParentConfig.windowConfiguration.getBounds(), (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP), (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP)); } computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig); } Loading services/core/java/com/android/server/wm/WindowState.java +1 −21 Original line number Diff line number Diff line Loading @@ -942,26 +942,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Make sure the content and visible frames are inside of the // final window frame. if (windowsAreFloating && !mWindowFrames.mFrame.isEmpty()) { // For pinned workspace the frame isn't limited in any particular // way since SystemUI controls the bounds. For freeform however // we want to keep things inside the content frame. final Rect limitFrame = task.inPinnedWindowingMode() ? mWindowFrames.mFrame : mWindowFrames.mContentFrame; // Keep the frame out of the blocked system area, limit it in size to the content area // and make sure that there is always a minimum visible so that the user can drag it // into a usable area.. final int height = Math.min(mWindowFrames.mFrame.height(), limitFrame.height()); final int width = Math.min(limitFrame.width(), mWindowFrames.mFrame.width()); final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics(); final int minVisibleHeight = Math.min(height, WindowManagerService.dipToPixel( MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics)); final int minVisibleWidth = Math.min(width, WindowManagerService.dipToPixel( MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics)); final int top = Math.max(limitFrame.top, Math.min( mWindowFrames.mFrame.top, limitFrame.bottom - minVisibleHeight)); final int left = Math.max(limitFrame.left + minVisibleWidth - width, Math.min( mWindowFrames.mFrame.left, limitFrame.right - minVisibleWidth)); mWindowFrames.mFrame.set(left, top, left + width, top + height); final int visBottom = mWindowFrames.mVisibleFrame.bottom; final int contentBottom = mWindowFrames.mContentFrame.bottom; mWindowFrames.mContentFrame.set(mWindowFrames.mFrame); Loading services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +39 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.service.voice.IVoiceInteractionSession; import android.util.DisplayMetrics; import android.util.Xml; import android.view.DisplayInfo; Loading Loading @@ -166,6 +167,44 @@ public class TaskRecordTests extends ActivityTestsBase { WINDOWING_MODE_FREEFORM, mParentBounds, insetBounds, insetBounds); } @Test public void testFitWithinBounds() { final Rect parentBounds = new Rect(10, 10, 200, 200); ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay(); ActivityStack stack = display.createStack(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build(); final Configuration parentConfig = stack.getConfiguration(); parentConfig.windowConfiguration.setBounds(parentBounds); parentConfig.densityDpi = DisplayMetrics.DENSITY_DEFAULT; // check top and left Rect reqBounds = new Rect(-190, -190, 0, 0); task.setBounds(reqBounds); // Make sure part of it is exposed assertTrue(task.getBounds().right > parentBounds.left); assertTrue(task.getBounds().bottom > parentBounds.top); // Should still be more-or-less in that corner assertTrue(task.getBounds().left <= parentBounds.left); assertTrue(task.getBounds().top <= parentBounds.top); assertEquals(reqBounds.width(), task.getBounds().width()); assertEquals(reqBounds.height(), task.getBounds().height()); // check bottom and right reqBounds = new Rect(210, 210, 400, 400); task.setBounds(reqBounds); // Make sure part of it is exposed assertTrue(task.getBounds().left < parentBounds.right); assertTrue(task.getBounds().top < parentBounds.bottom); // Should still be more-or-less in that corner assertTrue(task.getBounds().right >= parentBounds.right); assertTrue(task.getBounds().bottom >= parentBounds.bottom); assertEquals(reqBounds.width(), task.getBounds().width()); assertEquals(reqBounds.height(), task.getBounds().height()); } /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */ @Test public void testBoundsOnModeChangeFreeformToFullscreen() { Loading Loading
services/core/java/com/android/server/wm/TaskRecord.java +25 −30 Original line number Diff line number Diff line Loading @@ -202,13 +202,6 @@ class TaskRecord extends ConfigurationContainer { // Do not move the stack as a part of reparenting static final int REPARENT_LEAVE_STACK_IN_PLACE = 2; // The height/width divide used when fitting a task within a bounds with method // {@link #fitWithinBounds}. // We always want the task to to be visible in the bounds without affecting its size when // fitting. To make sure this is the case, we don't adjust the task left or top side pass // the input bounds right or bottom side minus the width or height divided by this value. private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3; /** * The factory used to create {@link TaskRecord}. This allows OEM subclass {@link TaskRecord}. */ Loading Loading @@ -1932,35 +1925,33 @@ class TaskRecord extends ConfigurationContainer { * * @param bounds Bounds to be adjusted. * @param stackBounds Bounds within which the other bounds should remain. * @param overlapPxX The amount of px required to be visible in the X dimension. * @param overlapPxY The amount of px required to be visible in the Y dimension. */ private static void fitWithinBounds(Rect bounds, Rect stackBounds) { private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX, int overlapPxY) { if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) { return; } if (bounds.left < stackBounds.left || bounds.right > stackBounds.right) { final int maxRight = stackBounds.right - (stackBounds.width() / FIT_WITHIN_BOUNDS_DIVIDER); int horizontalDiff = stackBounds.left - bounds.left; if ((horizontalDiff < 0 && bounds.left >= maxRight) || (bounds.left + horizontalDiff >= maxRight)) { horizontalDiff = maxRight - bounds.left; } bounds.left += horizontalDiff; bounds.right += horizontalDiff; // For each side of the parent (eg. left), check if the opposing side of the window (eg. // right) is at least overlap pixels away. If less, offset the window by that difference. int horizontalDiff = 0; // If window is smaller than overlap, use it's smallest dimension instead int overlapLR = Math.min(overlapPxX, bounds.width()); if (bounds.right < (stackBounds.left + overlapLR)) { horizontalDiff = overlapLR - (bounds.right - stackBounds.left); } else if (bounds.left > (stackBounds.right - overlapLR)) { horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left)); } if (bounds.top < stackBounds.top || bounds.bottom > stackBounds.bottom) { final int maxBottom = stackBounds.bottom - (stackBounds.height() / FIT_WITHIN_BOUNDS_DIVIDER); int verticalDiff = stackBounds.top - bounds.top; if ((verticalDiff < 0 && bounds.top >= maxBottom) || (bounds.top + verticalDiff >= maxBottom)) { verticalDiff = maxBottom - bounds.top; } bounds.top += verticalDiff; bounds.bottom += verticalDiff; int verticalDiff = 0; int overlapTB = Math.min(overlapPxY, bounds.width()); if (bounds.bottom < (stackBounds.top + overlapTB)) { verticalDiff = overlapTB - (bounds.bottom - stackBounds.top); } else if (bounds.top > (stackBounds.bottom - overlapTB)) { verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top)); } bounds.offset(horizontalDiff, verticalDiff); } /** Loading Loading @@ -2230,7 +2221,11 @@ class TaskRecord extends ConfigurationContainer { adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds); if (windowingMode == WINDOWING_MODE_FREEFORM) { // by policy, make sure the window remains within parent somewhere fitWithinBounds(outOverrideBounds, newParentConfig.windowConfiguration.getBounds()); final float density = ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT; fitWithinBounds(outOverrideBounds, newParentConfig.windowConfiguration.getBounds(), (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP), (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP)); } computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig); } Loading
services/core/java/com/android/server/wm/WindowState.java +1 −21 Original line number Diff line number Diff line Loading @@ -942,26 +942,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Make sure the content and visible frames are inside of the // final window frame. if (windowsAreFloating && !mWindowFrames.mFrame.isEmpty()) { // For pinned workspace the frame isn't limited in any particular // way since SystemUI controls the bounds. For freeform however // we want to keep things inside the content frame. final Rect limitFrame = task.inPinnedWindowingMode() ? mWindowFrames.mFrame : mWindowFrames.mContentFrame; // Keep the frame out of the blocked system area, limit it in size to the content area // and make sure that there is always a minimum visible so that the user can drag it // into a usable area.. final int height = Math.min(mWindowFrames.mFrame.height(), limitFrame.height()); final int width = Math.min(limitFrame.width(), mWindowFrames.mFrame.width()); final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics(); final int minVisibleHeight = Math.min(height, WindowManagerService.dipToPixel( MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics)); final int minVisibleWidth = Math.min(width, WindowManagerService.dipToPixel( MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics)); final int top = Math.max(limitFrame.top, Math.min( mWindowFrames.mFrame.top, limitFrame.bottom - minVisibleHeight)); final int left = Math.max(limitFrame.left + minVisibleWidth - width, Math.min( mWindowFrames.mFrame.left, limitFrame.right - minVisibleWidth)); mWindowFrames.mFrame.set(left, top, left + width, top + height); final int visBottom = mWindowFrames.mVisibleFrame.bottom; final int contentBottom = mWindowFrames.mContentFrame.bottom; mWindowFrames.mContentFrame.set(mWindowFrames.mFrame); Loading
services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +39 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.service.voice.IVoiceInteractionSession; import android.util.DisplayMetrics; import android.util.Xml; import android.view.DisplayInfo; Loading Loading @@ -166,6 +167,44 @@ public class TaskRecordTests extends ActivityTestsBase { WINDOWING_MODE_FREEFORM, mParentBounds, insetBounds, insetBounds); } @Test public void testFitWithinBounds() { final Rect parentBounds = new Rect(10, 10, 200, 200); ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay(); ActivityStack stack = display.createStack(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build(); final Configuration parentConfig = stack.getConfiguration(); parentConfig.windowConfiguration.setBounds(parentBounds); parentConfig.densityDpi = DisplayMetrics.DENSITY_DEFAULT; // check top and left Rect reqBounds = new Rect(-190, -190, 0, 0); task.setBounds(reqBounds); // Make sure part of it is exposed assertTrue(task.getBounds().right > parentBounds.left); assertTrue(task.getBounds().bottom > parentBounds.top); // Should still be more-or-less in that corner assertTrue(task.getBounds().left <= parentBounds.left); assertTrue(task.getBounds().top <= parentBounds.top); assertEquals(reqBounds.width(), task.getBounds().width()); assertEquals(reqBounds.height(), task.getBounds().height()); // check bottom and right reqBounds = new Rect(210, 210, 400, 400); task.setBounds(reqBounds); // Make sure part of it is exposed assertTrue(task.getBounds().left < parentBounds.right); assertTrue(task.getBounds().top < parentBounds.bottom); // Should still be more-or-less in that corner assertTrue(task.getBounds().right >= parentBounds.right); assertTrue(task.getBounds().bottom >= parentBounds.bottom); assertEquals(reqBounds.width(), task.getBounds().width()); assertEquals(reqBounds.height(), task.getBounds().height()); } /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */ @Test public void testBoundsOnModeChangeFreeformToFullscreen() { Loading