diff options
| author | Louis Chang <louischang@google.com> | 2021-07-14 11:15:00 +0800 |
|---|---|---|
| committer | Louis Chang <louischang@google.com> | 2021-07-20 22:07:57 +0800 |
| commit | 69fd1625a15dfa19ae83a9616f23fe0cdb3ebe7c (patch) | |
| tree | ea181f4369fc0a5eae8f1aa41b52140148a063f0 | |
| parent | f335f847421d17ebff70c8e1ef5c97ab6090beae (diff) | |
Perform the minimal dimension restrictions on leaf Task
The minimal dimension restrictions ensure the leaf task fragment
won't be displayed too small to manipulate. However, the out bounds
was exceed the parent task bounds and resulted in wrong inset
calculation while layouting the window.
Restore performing the minimal dimension restrictions in leaf tasks
(the behavior before f562315).
Bug: 193493038
Test: wm presubmit
Change-Id: Ide7ef2ee0b5fd2d6de353a1e9365a7120b2ab0d3
| -rw-r--r-- | services/core/java/com/android/server/wm/Task.java | 151 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/TaskFragment.java | 154 |
2 files changed, 155 insertions, 150 deletions
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index e8b696708ea6..deb8d6eca5e1 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -150,6 +150,7 @@ import android.app.IActivityController; import android.app.PictureInPictureParams; import android.app.RemoteAction; import android.app.TaskInfo; +import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -2039,6 +2040,156 @@ class Task extends TaskFragment { } } + void resolveLeafTaskOnlyOverrideConfigs(Configuration newParentConfig, Rect previousBounds) { + if (!isLeafTask()) { + return; + } + + int windowingMode = + getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); + if (windowingMode == WINDOWING_MODE_UNDEFINED) { + windowingMode = newParentConfig.windowConfiguration.getWindowingMode(); + } + // Commit the resolved windowing mode so the canSpecifyOrientation won't get the old + // mode that may cause the bounds to be miscalculated, e.g. letterboxed. + getConfiguration().windowConfiguration.setWindowingMode(windowingMode); + Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds(); + + if (windowingMode == WINDOWING_MODE_FULLSCREEN) { + // Use empty bounds to indicate "fill parent". + outOverrideBounds.setEmpty(); + // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if + // the parent or display is smaller than the size, the content may be cropped. + return; + } + + adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig); + if (windowingMode == WINDOWING_MODE_FREEFORM) { + computeFreeformBounds(outOverrideBounds, newParentConfig); + return; + } + } + + void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds, + @NonNull Configuration parentConfig) { + int minWidth = mMinWidth; + int minHeight = mMinHeight; + // If the task has no requested minimal size, we'd like to enforce a minimal size + // so that the user can not render the task fragment too small to manipulate. We don't need + // to do this for the root pinned task as the bounds are controlled by the system. + if (!inPinnedWindowingMode()) { + final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp; + final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT; + final int defaultMinSize = (int) (defaultMinSizeDp * density); + + if (minWidth == INVALID_MIN_SIZE) { + minWidth = defaultMinSize; + } + if (minHeight == INVALID_MIN_SIZE) { + minHeight = defaultMinSize; + } + } + if (bounds.isEmpty()) { + // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they + // do, we can just skip. + final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); + if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) { + return; + } + bounds.set(parentBounds); + } + final boolean adjustWidth = minWidth > bounds.width(); + final boolean adjustHeight = minHeight > bounds.height(); + if (!(adjustWidth || adjustHeight)) { + return; + } + + if (adjustWidth) { + if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) { + bounds.left = bounds.right - minWidth; + } else { + // Either left bounds match, or neither match, or the previous bounds were + // fullscreen and we default to keeping left. + bounds.right = bounds.left + minWidth; + } + } + if (adjustHeight) { + if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) { + bounds.top = bounds.bottom - minHeight; + } else { + // Either top bounds match, or neither match, or the previous bounds were + // fullscreen and we default to keeping top. + bounds.bottom = bounds.top + minHeight; + } + } + } + + /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */ + private void computeFreeformBounds(@NonNull Rect outBounds, + @NonNull Configuration newParentConfig) { + // by policy, make sure the window remains within parent somewhere + final float density = + ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT; + final Rect parentBounds = + new Rect(newParentConfig.windowConfiguration.getBounds()); + final DisplayContent display = getDisplayContent(); + if (display != null) { + // If a freeform window moves below system bar, there is no way to move it again + // by touch. Because its caption is covered by system bar. So we exclude them + // from root task bounds. and then caption will be shown inside stable area. + final Rect stableBounds = new Rect(); + display.getStableRect(stableBounds); + parentBounds.intersect(stableBounds); + } + + fitWithinBounds(outBounds, parentBounds, + (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP), + (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP)); + + // Prevent to overlap caption with stable insets. + final int offsetTop = parentBounds.top - outBounds.top; + if (offsetTop > 0) { + outBounds.offset(0, offsetTop); + } + } + + /** + * Adjusts bounds to stay within root task bounds. + * + * Since bounds might be outside of root task bounds, this method tries to move the bounds in + * a way that keep them unchanged, but be contained within the root task bounds. + * + * @param bounds Bounds to be adjusted. + * @param rootTaskBounds 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 rootTaskBounds, int overlapPxX, + int overlapPxY) { + if (rootTaskBounds == null || rootTaskBounds.isEmpty() || rootTaskBounds.contains(bounds)) { + return; + } + + // 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 < (rootTaskBounds.left + overlapLR)) { + horizontalDiff = overlapLR - (bounds.right - rootTaskBounds.left); + } else if (bounds.left > (rootTaskBounds.right - overlapLR)) { + horizontalDiff = -(overlapLR - (rootTaskBounds.right - bounds.left)); + } + int verticalDiff = 0; + int overlapTB = Math.min(overlapPxY, bounds.width()); + if (bounds.bottom < (rootTaskBounds.top + overlapTB)) { + verticalDiff = overlapTB - (bounds.bottom - rootTaskBounds.top); + } else if (bounds.top > (rootTaskBounds.bottom - overlapTB)) { + verticalDiff = -(overlapTB - (rootTaskBounds.bottom - bounds.top)); + } + bounds.offset(horizontalDiff, verticalDiff); + } + /** * Initializes a change transition. See {@link SurfaceFreezer} for more information. */ diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 12ad634fb6b8..1d1c8b380597 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -1500,8 +1500,10 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } - if (isLeafTaskFragment()) { - resolveLeafOnlyOverrideConfigs(newParentConfig, mTmpBounds /* previousBounds */); + final Task thisTask = asTask(); + if (thisTask != null) { + thisTask.resolveLeafTaskOnlyOverrideConfigs(newParentConfig, + mTmpBounds /* previousBounds */); } computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig); } @@ -1539,100 +1541,6 @@ class TaskFragment extends WindowContainer<WindowContainer> { return getTask() != null ? getTask().mTaskId : INVALID_TASK_ID; } - private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig, - Rect previousBounds) { - - int windowingMode = - getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode(); - if (windowingMode == WINDOWING_MODE_UNDEFINED) { - windowingMode = newParentConfig.windowConfiguration.getWindowingMode(); - } - // Commit the resolved windowing mode so the canSpecifyOrientation won't get the old - // mode that may cause the bounds to be miscalculated, e.g. letterboxed. - getConfiguration().windowConfiguration.setWindowingMode(windowingMode); - Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds(); - - if (windowingMode == WINDOWING_MODE_FULLSCREEN) { - // Use empty bounds to indicate "fill parent". - outOverrideBounds.setEmpty(); - // The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if - // the parent or display is smaller than the size, the content may be cropped. - return; - } - - adjustForMinimalTaskDimensions(outOverrideBounds, previousBounds, newParentConfig); - if (windowingMode == WINDOWING_MODE_FREEFORM) { - computeFreeformBounds(outOverrideBounds, newParentConfig); - return; - } - } - - /** Computes bounds for {@link WindowConfiguration#WINDOWING_MODE_FREEFORM}. */ - private void computeFreeformBounds(@NonNull Rect outBounds, - @NonNull Configuration newParentConfig) { - // by policy, make sure the window remains within parent somewhere - final float density = - ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT; - final Rect parentBounds = - new Rect(newParentConfig.windowConfiguration.getBounds()); - final DisplayContent display = getDisplayContent(); - if (display != null) { - // If a freeform window moves below system bar, there is no way to move it again - // by touch. Because its caption is covered by system bar. So we exclude them - // from root task bounds. and then caption will be shown inside stable area. - final Rect stableBounds = new Rect(); - display.getStableRect(stableBounds); - parentBounds.intersect(stableBounds); - } - - fitWithinBounds(outBounds, parentBounds, - (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP), - (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP)); - - // Prevent to overlap caption with stable insets. - final int offsetTop = parentBounds.top - outBounds.top; - if (offsetTop > 0) { - outBounds.offset(0, offsetTop); - } - } - - /** - * Adjusts bounds to stay within root task bounds. - * - * Since bounds might be outside of root task bounds, this method tries to move the bounds in - * a way that keep them unchanged, but be contained within the root task bounds. - * - * @param bounds Bounds to be adjusted. - * @param rootTaskBounds 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 rootTaskBounds, int overlapPxX, - int overlapPxY) { - if (rootTaskBounds == null || rootTaskBounds.isEmpty() || rootTaskBounds.contains(bounds)) { - return; - } - - // 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 < (rootTaskBounds.left + overlapLR)) { - horizontalDiff = overlapLR - (bounds.right - rootTaskBounds.left); - } else if (bounds.left > (rootTaskBounds.right - overlapLR)) { - horizontalDiff = -(overlapLR - (rootTaskBounds.right - bounds.left)); - } - int verticalDiff = 0; - int overlapTB = Math.min(overlapPxY, bounds.width()); - if (bounds.bottom < (rootTaskBounds.top + overlapTB)) { - verticalDiff = overlapTB - (bounds.bottom - rootTaskBounds.top); - } else if (bounds.top > (rootTaskBounds.bottom - overlapTB)) { - verticalDiff = -(overlapTB - (rootTaskBounds.bottom - bounds.top)); - } - bounds.offset(horizontalDiff, verticalDiff); - } - /** * Ensures all visible activities at or below the input activity have the right configuration. */ @@ -1640,60 +1548,6 @@ class TaskFragment extends WindowContainer<WindowContainer> { mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow); } - void adjustForMinimalTaskDimensions(@NonNull Rect bounds, @NonNull Rect previousBounds, - @NonNull Configuration parentConfig) { - int minWidth = mMinWidth; - int minHeight = mMinHeight; - // If the task has no requested minimal size, we'd like to enforce a minimal size - // so that the user can not render the task fragment too small to manipulate. We don't need - // to do this for the root pinned task as the bounds are controlled by the system. - if (!inPinnedWindowingMode()) { - final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp; - final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT; - final int defaultMinSize = (int) (defaultMinSizeDp * density); - - if (minWidth == INVALID_MIN_SIZE) { - minWidth = defaultMinSize; - } - if (minHeight == INVALID_MIN_SIZE) { - minHeight = defaultMinSize; - } - } - if (bounds.isEmpty()) { - // If inheriting parent bounds, check if parent bounds adhere to minimum size. If they - // do, we can just skip. - final Rect parentBounds = parentConfig.windowConfiguration.getBounds(); - if (parentBounds.width() >= minWidth && parentBounds.height() >= minHeight) { - return; - } - bounds.set(parentBounds); - } - final boolean adjustWidth = minWidth > bounds.width(); - final boolean adjustHeight = minHeight > bounds.height(); - if (!(adjustWidth || adjustHeight)) { - return; - } - - if (adjustWidth) { - if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) { - bounds.left = bounds.right - minWidth; - } else { - // Either left bounds match, or neither match, or the previous bounds were - // fullscreen and we default to keeping left. - bounds.right = bounds.left + minWidth; - } - } - if (adjustHeight) { - if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) { - bounds.top = bounds.bottom - minHeight; - } else { - // Either top bounds match, or neither match, or the previous bounds were - // fullscreen and we default to keeping top. - bounds.bottom = bounds.top + minHeight; - } - } - } - void computeConfigResourceOverrides(@NonNull Configuration inOutConfig, @NonNull Configuration parentConfig) { computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */, |
