summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorBen Lin <linben@google.com>2020-02-03 14:23:57 -0800
committerBen Lin <linben@google.com>2020-02-07 10:27:30 -0800
commit2e306af24102236eb5835da7fa0c19f007a826c9 (patch)
tree0f8dc99d8087f888c1830ca2107f03591f08c2c5 /core/java
parent1059d5a169cc03ce733d446d91e9fe8f4f21c138 (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.java179
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);
+ }
+}