summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Evan Rosky <erosky@google.com> 2019-02-01 10:58:38 -0800
committer Evan Rosky <erosky@google.com> 2019-03-04 12:39:57 -0800
commit60dba2f3a01abc736fa40bbc6bb42b0bc3ee3695 (patch)
treed6364355826937588bb6e580818929ed3a07bb4e
parent6ce9003ef0c28c3ea9de43550dfa36e3d067c1d5 (diff)
Ensure freeform windows always have a visible portion on screen
There was already code attempting to do this, but it wasn't correct and was causing windows to pop to top or left. This basically ensures that a fixed amount of dp in each linear direction is visible on the screen for a given window. Since this is handled in policy, it doesn't need to be enforced during computeFrame anymore. Bug: 123757388 Test: drag freeform to right or bottom, atest TaskRecordTests WindowFrameTests Change-Id: I23c690a5efe06c77caa14ecc8e30a30cd42c23c4
-rw-r--r--services/core/java/com/android/server/wm/TaskRecord.java55
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java22
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java39
3 files changed, 65 insertions, 51 deletions
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 1392762fca66..4fd84896e101 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -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}.
*/
@@ -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);
}
/**
@@ -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);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d5a6f00ff30d..20cca66d8a52 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -942,29 +942,9 @@ 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);
+ mWindowFrames.mContentFrame.set(mWindowFrames.mFrame);
mWindowFrames.mVisibleFrame.set(mWindowFrames.mContentFrame);
mWindowFrames.mStableFrame.set(mWindowFrames.mContentFrame);
if (isImeTarget && inFreeformWindowingMode()) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 5d0788881704..dc307b547a63 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -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;
@@ -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() {