diff options
| author | Ben Lin <linben@google.com> | 2020-02-03 14:23:57 -0800 |
|---|---|---|
| committer | Ben Lin <linben@google.com> | 2020-02-07 10:27:30 -0800 |
| commit | 2e306af24102236eb5835da7fa0c19f007a826c9 (patch) | |
| tree | 0f8dc99d8087f888c1830ca2107f03591f08c2c5 /core/java | |
| parent | 1059d5a169cc03ce733d446d91e9fe8f4f21c138 (diff) | |
Refactor TaskPositioner resizing logic into a shareable class.
So this can be used by other resizing not done by the framework (e.g.
PIP resizing done via SysUI).
Bug: 147361175
Test: Compile
Change-Id: I0010b292af5ea48e4303a4faaf9c0bbe49d5d64f
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/com/android/internal/policy/TaskResizingAlgorithm.java | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/core/java/com/android/internal/policy/TaskResizingAlgorithm.java b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java new file mode 100644 index 000000000000..1fce098fb93e --- /dev/null +++ b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.policy; + +import android.annotation.IntDef; +import android.graphics.Point; +import android.graphics.Rect; + +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Given a move coordinate (x, y), the original taks bounds and relevant details, calculate the new + * bounds. + * + * @hide + */ +public class TaskResizingAlgorithm { + + @IntDef(flag = true, + value = { + CTRL_NONE, + CTRL_LEFT, + CTRL_RIGHT, + CTRL_TOP, + CTRL_BOTTOM + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CtrlType {} + + public static final int CTRL_NONE = 0x0; + public static final int CTRL_LEFT = 0x1; + public static final int CTRL_RIGHT = 0x2; + public static final int CTRL_TOP = 0x4; + public static final int CTRL_BOTTOM = 0x8; + + // The minimal aspect ratio which needs to be met to count as landscape (or 1/.. for portrait). + // Note: We do not use the 1.33 from the CDD here since the user is allowed to use what ever + // aspect he desires. + @VisibleForTesting + public static final float MIN_ASPECT = 1.2f; + + /** + * Given a (x, y) point and its original starting down point and its original bounds, calculate + * and return a new resized bound. + * @param x the new moved X point. + * @param y the new moved Y point. + * @param startDragX the original starting X point. + * @param startDragY the original starting Y point. + * @param originalBounds the original bound before resize. + * @param ctrlType The type of resize operation. + * @param minVisibleWidth The minimal width required for the new size. + * @param minVisibleHeight The minimal height required for the new size. + * @param maxVisibleSize The maximum size allowed. + * @param preserveOrientation + * @param startOrientationWasLandscape + * @return + */ + public static Rect resizeDrag(float x, float y, float startDragX, float startDragY, + Rect originalBounds, int ctrlType, int minVisibleWidth, int minVisibleHeight, + Point maxVisibleSize, boolean preserveOrientation, + boolean startOrientationWasLandscape) { + // This is a resizing operation. + // We need to keep various constraints: + // 1. mMinVisible[Width/Height] <= [width/height] <= mMaxVisibleSize.[x/y] + // 2. The orientation is kept - if required. + final int deltaX = Math.round(x - startDragX); + final int deltaY = Math.round(y - startDragY); + int left = originalBounds.left; + int top = originalBounds.top; + int right = originalBounds.right; + int bottom = originalBounds.bottom; + + // Calculate the resulting width and height of the drag operation. + int width = right - left; + int height = bottom - top; + if ((ctrlType & CTRL_LEFT) != 0) { + width = Math.max(minVisibleWidth, width - deltaX); + } else if ((ctrlType & CTRL_RIGHT) != 0) { + width = Math.max(minVisibleWidth, width + deltaX); + } + if ((ctrlType & CTRL_TOP) != 0) { + height = Math.max(minVisibleHeight, height - deltaY); + } else if ((ctrlType & CTRL_BOTTOM) != 0) { + height = Math.max(minVisibleHeight, height + deltaY); + } + + // If we have to preserve the orientation - check that we are doing so. + final float aspect = (float) width / (float) height; + if (preserveOrientation && ((startOrientationWasLandscape && aspect < MIN_ASPECT) + || (!startOrientationWasLandscape && aspect > (1.0 / MIN_ASPECT)))) { + // Calculate 2 rectangles fulfilling all requirements for either X or Y being the major + // drag axis. What ever is producing the bigger rectangle will be chosen. + int width1; + int width2; + int height1; + int height2; + if (startOrientationWasLandscape) { + // Assuming that the width is our target we calculate the height. + width1 = Math.max(minVisibleWidth, Math.min(maxVisibleSize.x, width)); + height1 = Math.min(height, Math.round((float) width1 / MIN_ASPECT)); + if (height1 < minVisibleHeight) { + // If the resulting height is too small we adjust to the minimal size. + height1 = minVisibleHeight; + width1 = Math.max(minVisibleWidth, + Math.min(maxVisibleSize.x, Math.round((float) height1 * MIN_ASPECT))); + } + // Assuming that the height is our target we calculate the width. + height2 = Math.max(minVisibleHeight, Math.min(maxVisibleSize.y, height)); + width2 = Math.max(width, Math.round((float) height2 * MIN_ASPECT)); + if (width2 < minVisibleWidth) { + // If the resulting width is too small we adjust to the minimal size. + width2 = minVisibleWidth; + height2 = Math.max(minVisibleHeight, + Math.min(maxVisibleSize.y, Math.round((float) width2 / MIN_ASPECT))); + } + } else { + // Assuming that the width is our target we calculate the height. + width1 = Math.max(minVisibleWidth, Math.min(maxVisibleSize.x, width)); + height1 = Math.max(height, Math.round((float) width1 * MIN_ASPECT)); + if (height1 < minVisibleHeight) { + // If the resulting height is too small we adjust to the minimal size. + height1 = minVisibleHeight; + width1 = Math.max(minVisibleWidth, + Math.min(maxVisibleSize.x, Math.round((float) height1 / MIN_ASPECT))); + } + // Assuming that the height is our target we calculate the width. + height2 = Math.max(minVisibleHeight, Math.min(maxVisibleSize.y, height)); + width2 = Math.min(width, Math.round((float) height2 / MIN_ASPECT)); + if (width2 < minVisibleWidth) { + // If the resulting width is too small we adjust to the minimal size. + width2 = minVisibleWidth; + height2 = Math.max(minVisibleHeight, + Math.min(maxVisibleSize.y, Math.round((float) width2 * MIN_ASPECT))); + } + } + + // Use the bigger of the two rectangles if the major change was positive, otherwise + // do the opposite. + final boolean grows = width > (right - left) || height > (bottom - top); + if (grows == (width1 * height1 > width2 * height2)) { + width = width1; + height = height1; + } else { + width = width2; + height = height2; + } + } + + // Generate the final bounds by keeping the opposite drag edge constant. + if ((ctrlType & CTRL_LEFT) != 0) { + left = right - width; + } else { // Note: The right might have changed - if we pulled at the right or not. + right = left + width; + } + if ((ctrlType & CTRL_TOP) != 0) { + top = bottom - height; + } else { // Note: The height might have changed - if we pulled at the bottom or not. + bottom = top + height; + } + return new Rect(left, top, right, bottom); + } +} |
