summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java63
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java52
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java60
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java80
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt34
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt336
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt77
13 files changed, 626 insertions, 152 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index ee94f30cfa69..b3109388da2c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.desktopmode
-import android.app.ActivityManager
import android.app.ActivityManager.RunningTaskInfo
import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
@@ -202,16 +201,15 @@ class DesktopTasksController(
}
}
-
/**
* Move a task to fullscreen after being dragged from fullscreen and released back into
* status bar area
*/
- fun cancelMoveToFreeform(task: RunningTaskInfo, startPosition: Point) {
+ fun cancelMoveToFreeform(task: RunningTaskInfo, position: Point) {
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, startPosition,
+ enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, position,
mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
@@ -219,13 +217,13 @@ class DesktopTasksController(
}
}
- private fun moveToFullscreenWithAnimation(task: ActivityManager.RunningTaskInfo) {
+ private fun moveToFullscreenWithAnimation(task: RunningTaskInfo, position: Point) {
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
exitDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_EXIT_DESKTOP_MODE, wct, mOnAnimationFinishedCallback)
+ Transitions.TRANSIT_EXIT_DESKTOP_MODE, wct, position, mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
releaseVisualIndicator()
@@ -499,15 +497,15 @@ class DesktopTasksController(
* Perform checks required on drag end. Move to fullscreen if drag ends in status bar area.
*
* @param taskInfo the task being dragged.
- * @param y height of drag, to be checked against status bar height.
+ * @param position position of surface when drag ends
*/
fun onDragPositioningEnd(
taskInfo: RunningTaskInfo,
- y: Float
+ position: Point
) {
val statusBarHeight = getStatusBarHeight(taskInfo)
- if (y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
- moveToFullscreenWithAnimation(taskInfo)
+ if (position.y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
+ moveToFullscreenWithAnimation(taskInfo, position)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index d55fdddf4fea..3733b919e366 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -58,7 +58,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
public static final int FREEFORM_ANIMATION_DURATION = 336;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
- private Point mStartPosition;
+ private Point mPosition;
private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
public EnterDesktopTaskTransitionHandler(
@@ -90,15 +90,15 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
/**
* Starts Transition of type TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
* @param wct WindowContainerTransaction for transition
- * @param startPosition Position of task when transition is triggered
+ * @param position Position of task when transition is triggered
* @param onAnimationEndCallback to be called after animation
*/
public void startCancelMoveToDesktopMode(@NonNull WindowContainerTransaction wct,
- Point startPosition,
+ Point position,
Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
- mStartPosition = startPosition;
+ mPosition = position;
startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct,
- mOnAnimationFinishedCallback);
+ onAnimationEndCallback);
}
@Override
@@ -201,7 +201,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
if (type == Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- && mStartPosition != null) {
+ && mPosition != null) {
// This Transition animates a task to fullscreen after being dragged from the status
// bar and then released back into the status bar area
final SurfaceControl sc = change.getLeash();
@@ -217,7 +217,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
final SurfaceControl.Transaction t = mTransactionSupplier.get();
animator.addUpdateListener(animation -> {
final float scale = (float) animation.getAnimatedValue();
- t.setPosition(sc, mStartPosition.x * (1 - scale), mStartPosition.y * (1 - scale))
+ t.setPosition(sc, mPosition.x * (1 - scale), mPosition.y * (1 - scale))
.setScale(sc, scale, scale)
.show(sc)
.apply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index 160a83d7ed36..3ad5edf0e604 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -57,6 +57,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
private Supplier<SurfaceControl.Transaction> mTransactionSupplier;
+ private Point mPosition;
public ExitDesktopTaskTransitionHandler(
Transitions transitions,
@@ -77,11 +78,13 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
* Starts Transition of a given type
* @param type Transition type
* @param wct WindowContainerTransaction for transition
+ * @param position Position of the task when transition is started
* @param onAnimationEndCallback to be called after animation
*/
public void startTransition(@WindowManager.TransitionType int type,
- @NonNull WindowContainerTransaction wct,
+ @NonNull WindowContainerTransaction wct, Point position,
Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ mPosition = position;
mOnAnimationFinishedCallback = onAnimationEndCallback;
final IBinder token = mTransitions.startTransition(type, wct, this);
mPendingTransitionTokens.add(token);
@@ -143,17 +146,17 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
final ValueAnimator animator = new ValueAnimator();
animator.setFloatValues(0f, 1f);
animator.setDuration(FULLSCREEN_ANIMATION_DURATION);
+ // The start bounds contain the correct dimensions of the task but hold the positioning
+ // before being dragged to the status bar to transition into fullscreen
final Rect startBounds = change.getStartAbsBounds();
final float scaleX = (float) startBounds.width() / screenWidth;
final float scaleY = (float) startBounds.height() / screenHeight;
final SurfaceControl.Transaction t = mTransactionSupplier.get();
- Point startPos = new Point(startBounds.left,
- startBounds.top);
animator.addUpdateListener(animation -> {
float fraction = animation.getAnimatedFraction();
float currentScaleX = scaleX + ((1 - scaleX) * fraction);
float currentScaleY = scaleY + ((1 - scaleY) * fraction);
- t.setPosition(sc, startPos.x * (1 - fraction), startPos.y * (1 - fraction))
+ t.setPosition(sc, mPosition.x * (1 - fraction), mPosition.y * (1 - fraction))
.setScale(sc, currentScaleX, currentScaleY)
.show(sc)
.apply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 212ad9ebceaf..2bb3cceb257f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.util.SparseArray;
@@ -185,18 +186,29 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
mSyncQueue);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
- final FluidResizeTaskPositioner taskPositioner =
- new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration, mDisplayController);
+ final DragPositioningCallback dragPositioningCallback = createDragPositioningCallback(
+ windowDecoration, taskInfo);
final CaptionTouchEventListener touchEventListener =
- new CaptionTouchEventListener(taskInfo, taskPositioner);
+ new CaptionTouchEventListener(taskInfo, dragPositioningCallback);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
- windowDecoration.setDragPositioningCallback(taskPositioner);
+ windowDecoration.setDragPositioningCallback(dragPositioningCallback);
windowDecoration.setDragDetector(touchEventListener.mDragDetector);
windowDecoration.relayout(taskInfo, startT, finishT,
false /* applyStartTransactionOnDraw */);
setupCaptionColor(taskInfo, windowDecoration);
}
+ private FluidResizeTaskPositioner createDragPositioningCallback(
+ CaptionWindowDecoration windowDecoration, RunningTaskInfo taskInfo) {
+ final int screenWidth = mDisplayController.getDisplayLayout(taskInfo.displayId).width();
+ final int statusBarHeight = mDisplayController.getDisplayLayout(taskInfo.displayId)
+ .stableInsets().top;
+ final Rect disallowedAreaForEndBounds = new Rect(0, 0, screenWidth,
+ statusBarHeight);
+ return new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration,
+ mDisplayController, disallowedAreaForEndBounds);
+ }
+
private class CaptionTouchEventListener implements
View.OnClickListener, View.OnTouchListener, DragDetector.MotionEventHandler {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index dffbedd197cf..0b821844e46c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -33,7 +33,6 @@ import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
@@ -41,7 +40,6 @@ import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.util.DisplayMetrics;
import android.util.SparseArray;
import android.view.Choreographer;
import android.view.InputChannel;
@@ -63,6 +61,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopModeStatus;
@@ -392,10 +391,16 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
+ // Position of the task is calculated by subtracting the raw location of the
+ // motion event (the location of the motion relative to the display) by the
+ // location of the motion event relative to the task's bounds
+ final Point position = new Point(
+ (int) (e.getRawX(dragPointerIdx) - e.getX(dragPointerIdx)),
+ (int) (e.getRawY(dragPointerIdx) - e.getY(dragPointerIdx)));
mDragPositioningCallback.onDragPositioningEnd(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
mDesktopTasksController.ifPresent(c -> c.onDragPositioningEnd(taskInfo,
- e.getRawY(dragPointerIdx)));
+ position));
final boolean wasDragging = mIsDragging;
mIsDragging = false;
return wasDragging;
@@ -560,10 +565,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mDragToDesktopAnimationStarted = false;
return;
} else if (mDragToDesktopAnimationStarted) {
- Point startPosition = new Point((int) ev.getX(), (int) ev.getY());
+ Point position = new Point((int) ev.getX(), (int) ev.getY());
mDesktopTasksController.ifPresent(
c -> c.cancelMoveToFreeform(relevantDecor.mTaskInfo,
- startPosition));
+ position));
mDragToDesktopAnimationStarted = false;
return;
}
@@ -615,11 +620,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
* Gets bounds of a scaled window centered relative to the screen bounds
* @param scale the amount to scale to relative to the Screen Bounds
*/
- private Rect calculateFreeformBounds(float scale) {
- final Resources resources = mContext.getResources();
- final DisplayMetrics metrics = resources.getDisplayMetrics();
- final int screenWidth = metrics.widthPixels;
- final int screenHeight = metrics.heightPixels;
+ private Rect calculateFreeformBounds(int displayId, float scale) {
+ final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(displayId);
+ final int screenWidth = displayLayout.width();
+ final int screenHeight = displayLayout.height();
final float adjustmentPercentage = (1f - scale) / 2;
final Rect endBounds = new Rect((int) (screenWidth * adjustmentPercentage),
@@ -648,7 +652,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(FREEFORM_ANIMATION_DURATION);
final SurfaceControl sc = relevantDecor.mTaskSurface;
- final Rect endBounds = calculateFreeformBounds(DRAG_FREEFORM_SCALE);
+ final Rect endBounds = calculateFreeformBounds(ev.getDisplayId(), DRAG_FREEFORM_SCALE);
final Transaction t = mTransactionFactory.get();
final float diffX = endBounds.centerX() - ev.getX();
final float diffY = endBounds.top - ev.getY();
@@ -665,9 +669,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mDesktopTasksController.ifPresent(c ->
- c.onDragPositioningEndThroughStatusBar(relevantDecor.mTaskInfo,
- calculateFreeformBounds(FINAL_FREEFORM_SCALE)));
+ mDesktopTasksController.ifPresent(
+ c -> c.onDragPositioningEndThroughStatusBar(
+ relevantDecor.mTaskInfo,
+ calculateFreeformBounds(ev.getDisplayId(), FINAL_FREEFORM_SCALE)));
}
});
animator.start();
@@ -783,17 +788,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mSyncQueue);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
- final DragPositioningCallback dragPositioningCallback;
- if (!DesktopModeStatus.isVeiledResizeEnabled()) {
- dragPositioningCallback =
- new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration,
- mDisplayController, mDragStartListener);
- } else {
- windowDecoration.createResizeVeil();
- dragPositioningCallback =
- new VeiledResizeTaskPositioner(mTaskOrganizer, windowDecoration,
- mDisplayController, mDragStartListener);
- }
+ final DragPositioningCallback dragPositioningCallback = createDragPositioningCallback(
+ windowDecoration, taskInfo);
final DesktopModeTouchEventListener touchEventListener =
new DesktopModeTouchEventListener(taskInfo, dragPositioningCallback);
@@ -805,7 +801,22 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
false /* applyStartTransactionOnDraw */);
incrementEventReceiverTasks(taskInfo.displayId);
}
-
+ private DragPositioningCallback createDragPositioningCallback(
+ @NonNull DesktopModeWindowDecoration windowDecoration,
+ @NonNull RunningTaskInfo taskInfo) {
+ final int screenWidth = mDisplayController.getDisplayLayout(taskInfo.displayId).width();
+ final Rect disallowedAreaForEndBounds = new Rect(0, 0, screenWidth,
+ getStatusBarHeight(taskInfo.displayId));
+ if (!DesktopModeStatus.isVeiledResizeEnabled()) {
+ return new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration,
+ mDisplayController, disallowedAreaForEndBounds, mDragStartListener,
+ mTransactionFactory);
+ } else {
+ windowDecoration.createResizeVeil();
+ return new VeiledResizeTaskPositioner(mTaskOrganizer, windowDecoration,
+ mDisplayController, disallowedAreaForEndBounds, mDragStartListener);
+ }
+ }
private class DragStartListenerImpl
implements DragPositioningCallbackUtility.DragStartListener {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
index ae93a43f78e9..09e29bcbcf9f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
@@ -25,6 +25,7 @@ import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.DisplayMetrics;
+import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -51,9 +52,9 @@ public class DragPositioningCallbackUtility {
}
/**
- * Based on type of drag and delta provided, calculate the new bounds to display for this task.
+ * Based on type of resize and delta provided, calculate the new bounds to display for this
+ * task.
* @param ctrlType type of drag being performed
- * @param hasMoved whether the current drag has moved on a prior input event
* @param repositionTaskBounds the bounds the task is being repositioned to
* @param taskBoundsAtDragStart the bounds of the task on the first drag input event
* @param stableBounds bounds that represent the resize limit of this task
@@ -62,16 +63,19 @@ public class DragPositioningCallbackUtility {
* @param windowDecoration window decoration of the task being dragged
* @return whether this method changed repositionTaskBounds
*/
- static boolean changeBounds(int ctrlType, boolean hasMoved,
- Rect repositionTaskBounds, Rect taskBoundsAtDragStart, Rect stableBounds,
- PointF delta, DisplayController displayController, WindowDecoration windowDecoration) {
- // |mRepositionTaskBounds| is the bounds last reported if |mHasMoved| is true. If it's not
- // true, we can compare it against |mTaskBoundsAtDragStart|.
- final int oldLeft = hasMoved ? repositionTaskBounds.left : taskBoundsAtDragStart.left;
- final int oldTop = hasMoved ? repositionTaskBounds.top : taskBoundsAtDragStart.top;
- final int oldRight = hasMoved ? repositionTaskBounds.right : taskBoundsAtDragStart.right;
- final int oldBottom =
- hasMoved ? repositionTaskBounds.bottom : taskBoundsAtDragStart.bottom;
+ static boolean changeBounds(int ctrlType, Rect repositionTaskBounds, Rect taskBoundsAtDragStart,
+ Rect stableBounds, PointF delta, DisplayController displayController,
+ WindowDecoration windowDecoration) {
+ // If task is being dragged rather than resized, return since this method only handles
+ // with resizing
+ if (ctrlType == CTRL_TYPE_UNDEFINED) {
+ return false;
+ }
+
+ final int oldLeft = repositionTaskBounds.left;
+ final int oldTop = repositionTaskBounds.top;
+ final int oldRight = repositionTaskBounds.right;
+ final int oldBottom = repositionTaskBounds.bottom;
repositionTaskBounds.set(taskBoundsAtDragStart);
@@ -101,10 +105,6 @@ public class DragPositioningCallbackUtility {
repositionTaskBounds.bottom = (candidateBottom < stableBounds.bottom)
? candidateBottom : oldBottom;
}
- if (ctrlType == CTRL_TYPE_UNDEFINED) {
- repositionTaskBounds.offset((int) delta.x, (int) delta.y);
- }
-
// If width or height are negative or less than the minimum width or height, revert the
// respective bounds to use previous bound dimensions.
if (repositionTaskBounds.width() < getMinWidth(displayController, windowDecoration)) {
@@ -126,8 +126,26 @@ public class DragPositioningCallbackUtility {
}
/**
+ * Set bounds using a {@link SurfaceControl.Transaction}.
+ */
+ static void setPositionOnDrag(WindowDecoration decoration, Rect repositionTaskBounds,
+ Rect taskBoundsAtDragStart, PointF repositionStartPoint, SurfaceControl.Transaction t,
+ float x, float y) {
+ updateTaskBounds(repositionTaskBounds, taskBoundsAtDragStart, repositionStartPoint, x, y);
+ t.setPosition(decoration.mTaskSurface, repositionTaskBounds.left,
+ repositionTaskBounds.top);
+ }
+
+ static void updateTaskBounds(Rect repositionTaskBounds, Rect taskBoundsAtDragStart,
+ PointF repositionStartPoint, float x, float y) {
+ final float deltaX = x - repositionStartPoint.x;
+ final float deltaY = y - repositionStartPoint.y;
+ repositionTaskBounds.set(taskBoundsAtDragStart);
+ repositionTaskBounds.offset((int) deltaX, (int) deltaY);
+ }
+
+ /**
* Apply a bounds change to a task.
- * @param wct provided {@link WindowContainerTransaction} that may contain other changes
* @param windowDecoration decor of task we are changing bounds for
* @param taskBounds new bounds of this task
* @param taskOrganizer applies the provided WindowContainerTransaction
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
index b366c809537f..9bcb77f03abd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
@@ -18,11 +18,14 @@ package com.android.wm.shell.windowdecor;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import java.util.function.Supplier;
+
/**
* A task positioner that resizes/relocates task contents as it is dragged.
* Utilizes {@link DragPositioningCallbackUtility} to determine new task bounds.
@@ -30,27 +33,35 @@ import com.android.wm.shell.common.DisplayController;
class FluidResizeTaskPositioner implements DragPositioningCallback {
private final ShellTaskOrganizer mTaskOrganizer;
private final WindowDecoration mWindowDecoration;
+ private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
private DisplayController mDisplayController;
private DragPositioningCallbackUtility.DragStartListener mDragStartListener;
private final Rect mStableBounds = new Rect();
private final Rect mTaskBoundsAtDragStart = new Rect();
private final PointF mRepositionStartPoint = new PointF();
private final Rect mRepositionTaskBounds = new Rect();
+ // If a task move (not resize) finishes in this region, the positioner will not attempt to
+ // finalize the bounds there using WCT#setBounds
+ private final Rect mDisallowedAreaForEndBounds = new Rect();
+ private boolean mHasDragResized;
private int mCtrlType;
- private boolean mHasMoved;
FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
- DisplayController displayController) {
- this(taskOrganizer, windowDecoration, displayController, dragStartListener -> {});
+ DisplayController displayController, Rect disallowedAreaForEndBounds) {
+ this(taskOrganizer, windowDecoration, displayController, disallowedAreaForEndBounds,
+ dragStartListener -> {}, SurfaceControl.Transaction::new);
}
FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
- DisplayController displayController,
- DragPositioningCallbackUtility.DragStartListener dragStartListener) {
+ DisplayController displayController, Rect disallowedAreaForEndBounds,
+ DragPositioningCallbackUtility.DragStartListener dragStartListener,
+ Supplier<SurfaceControl.Transaction> supplier) {
mTaskOrganizer = taskOrganizer;
mWindowDecoration = windowDecoration;
mDisplayController = displayController;
+ mDisallowedAreaForEndBounds.set(disallowedAreaForEndBounds);
mDragStartListener = dragStartListener;
+ mTransactionSupplier = supplier;
}
@Override
@@ -60,47 +71,66 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
mWindowDecoration.mTaskInfo.configuration.windowConfiguration.getBounds());
mRepositionStartPoint.set(x, y);
mDragStartListener.onDragStart(mWindowDecoration.mTaskInfo.taskId);
+ mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
}
@Override
public void onDragPositioningMove(float x, float y) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint);
- if (DragPositioningCallbackUtility.changeBounds(mCtrlType, mHasMoved,
+ if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType,
mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
mDisplayController, mWindowDecoration)) {
// The task is being resized, send the |dragResizing| hint to core with the first
// bounds-change wct.
- if (!mHasMoved && mCtrlType != CTRL_TYPE_UNDEFINED) {
+ if (!mHasDragResized) {
// This is the first bounds change since drag resize operation started.
wct.setDragResizing(mWindowDecoration.mTaskInfo.token, true /* dragResizing */);
}
DragPositioningCallbackUtility.applyTaskBoundsChange(wct, mWindowDecoration,
mRepositionTaskBounds, mTaskOrganizer);
- mHasMoved = true;
+ mHasDragResized = true;
+ } else if (mCtrlType == CTRL_TYPE_UNDEFINED) {
+ final SurfaceControl.Transaction t = mTransactionSupplier.get();
+ DragPositioningCallbackUtility.setPositionOnDrag(mWindowDecoration,
+ mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t, x, y);
+ t.apply();
}
}
@Override
public void onDragPositioningEnd(float x, float y) {
- // |mHasMoved| being false means there is no real change to the task bounds in WM core, so
- // we don't need a WCT to finish it.
- if (mHasMoved) {
+ // If task has been resized or task was dragged into area outside of
+ // mDisallowedAreaForEndBounds, apply WCT to finish it.
+ if (isResizing() && mHasDragResized) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setDragResizing(mWindowDecoration.mTaskInfo.token, false /* dragResizing */);
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y,
mRepositionStartPoint);
- if (DragPositioningCallbackUtility.changeBounds(mCtrlType, mHasMoved,
- mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
- mDisplayController, mWindowDecoration)) {
+ if (DragPositioningCallbackUtility.changeBounds(mCtrlType, mRepositionTaskBounds,
+ mTaskBoundsAtDragStart, mStableBounds, delta, mDisplayController,
+ mWindowDecoration)) {
wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds);
}
mTaskOrganizer.applyTransaction(wct);
+ } else if (mCtrlType == CTRL_TYPE_UNDEFINED
+ && !mDisallowedAreaForEndBounds.contains((int) x, (int) y)) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ DragPositioningCallbackUtility.updateTaskBounds(mRepositionTaskBounds,
+ mTaskBoundsAtDragStart, mRepositionStartPoint, x, y);
+ wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds);
+ mTaskOrganizer.applyTransaction(wct);
}
mTaskBoundsAtDragStart.setEmpty();
mRepositionStartPoint.set(0, 0);
mCtrlType = CTRL_TYPE_UNDEFINED;
- mHasMoved = false;
+ mHasDragResized = false;
}
+
+ private boolean isResizing() {
+ return (mCtrlType & CTRL_TYPE_TOP) != 0 || (mCtrlType & CTRL_TYPE_BOTTOM) != 0
+ || (mCtrlType & CTRL_TYPE_LEFT) != 0 || (mCtrlType & CTRL_TYPE_RIGHT) != 0;
+ }
+
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index 1d416c65851b..5253fb84a4be 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -18,11 +18,14 @@ package com.android.wm.shell.windowdecor;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import java.util.function.Supplier;
+
/**
* A task positioner that also takes into account resizing a
* {@link com.android.wm.shell.windowdecor.ResizeVeil}.
@@ -39,17 +42,32 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback {
private final Rect mTaskBoundsAtDragStart = new Rect();
private final PointF mRepositionStartPoint = new PointF();
private final Rect mRepositionTaskBounds = new Rect();
+ // If a task move (not resize) finishes in this region, the positioner will not attempt to
+ // finalize the bounds there using WCT#setBounds
+ private final Rect mDisallowedAreaForEndBounds = new Rect();
+ private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
+ private boolean mHasDragResized;
private int mCtrlType;
- private boolean mHasMoved;
-
public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer,
DesktopModeWindowDecoration windowDecoration, DisplayController displayController,
+ Rect disallowedAreaForEndBounds,
DragPositioningCallbackUtility.DragStartListener dragStartListener) {
+ this(taskOrganizer, windowDecoration, displayController, disallowedAreaForEndBounds,
+ dragStartListener, SurfaceControl.Transaction::new);
+ }
+
+ public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer,
+ DesktopModeWindowDecoration windowDecoration, DisplayController displayController,
+ Rect disallowedAreaForEndBounds,
+ DragPositioningCallbackUtility.DragStartListener dragStartListener,
+ Supplier<SurfaceControl.Transaction> supplier) {
mTaskOrganizer = taskOrganizer;
mDesktopWindowDecoration = windowDecoration;
mDisplayController = displayController;
mDragStartListener = dragStartListener;
+ mDisallowedAreaForEndBounds.set(disallowedAreaForEndBounds);
+ mTransactionSupplier = supplier;
}
@Override
@@ -58,27 +76,28 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback {
mTaskBoundsAtDragStart.set(
mDesktopWindowDecoration.mTaskInfo.configuration.windowConfiguration.getBounds());
mRepositionStartPoint.set(x, y);
- if (mCtrlType != CTRL_TYPE_UNDEFINED) {
+ if (isResizing()) {
mDesktopWindowDecoration.showResizeVeil();
}
- mHasMoved = false;
+ mHasDragResized = false;
mDragStartListener.onDragStart(mDesktopWindowDecoration.mTaskInfo.taskId);
+ mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
}
@Override
public void onDragPositioningMove(float x, float y) {
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint);
- if (DragPositioningCallbackUtility.changeBounds(mCtrlType, mHasMoved,
+ if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType,
mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
mDisplayController, mDesktopWindowDecoration)) {
- if (mCtrlType != CTRL_TYPE_UNDEFINED) {
- mDesktopWindowDecoration.updateResizeVeil(mRepositionTaskBounds);
- } else {
- DragPositioningCallbackUtility.applyTaskBoundsChange(
- new WindowContainerTransaction(), mDesktopWindowDecoration,
- mRepositionTaskBounds, mTaskOrganizer);
- }
- mHasMoved = true;
+ mDesktopWindowDecoration.updateResizeVeil(mRepositionTaskBounds);
+ mHasDragResized = true;
+ } else if (mCtrlType == CTRL_TYPE_UNDEFINED) {
+ final SurfaceControl.Transaction t = mTransactionSupplier.get();
+ DragPositioningCallbackUtility.setPositionOnDrag(mDesktopWindowDecoration,
+ mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t,
+ x, y);
+ t.apply();
}
}
@@ -86,22 +105,35 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback {
public void onDragPositioningEnd(float x, float y) {
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y,
mRepositionStartPoint);
- if (mHasMoved) {
- DragPositioningCallbackUtility.changeBounds(mCtrlType, mHasMoved,
- mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
- mDisplayController, mDesktopWindowDecoration);
- DragPositioningCallbackUtility.applyTaskBoundsChange(
- new WindowContainerTransaction(), mDesktopWindowDecoration,
- mRepositionTaskBounds, mTaskOrganizer);
- }
- // TODO: (b/279062291) Synchronize the start of hide to the end of the draw triggered above.
- if (mCtrlType != CTRL_TYPE_UNDEFINED) {
+ if (isResizing()) {
+ if (mHasDragResized) {
+ DragPositioningCallbackUtility.changeBounds(
+ mCtrlType, mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds,
+ delta, mDisplayController, mDesktopWindowDecoration);
+ DragPositioningCallbackUtility.applyTaskBoundsChange(
+ new WindowContainerTransaction(), mDesktopWindowDecoration,
+ mRepositionTaskBounds, mTaskOrganizer);
+ }
+ // TODO: (b/279062291) Synchronize the start of hide to the end of the draw triggered
+ // above.
mDesktopWindowDecoration.updateResizeVeil(mRepositionTaskBounds);
mDesktopWindowDecoration.hideResizeVeil();
+ } else if (!mDisallowedAreaForEndBounds.contains((int) x, (int) y)) {
+ DragPositioningCallbackUtility.updateTaskBounds(mRepositionTaskBounds,
+ mTaskBoundsAtDragStart, mRepositionStartPoint, x, y);
+ DragPositioningCallbackUtility.applyTaskBoundsChange(new WindowContainerTransaction(),
+ mDesktopWindowDecoration, mRepositionTaskBounds, mTaskOrganizer);
}
+
mCtrlType = CTRL_TYPE_UNDEFINED;
mTaskBoundsAtDragStart.setEmpty();
mRepositionStartPoint.set(0, 0);
- mHasMoved = false;
+ mHasDragResized = false;
}
+
+ private boolean isResizing() {
+ return (mCtrlType & CTRL_TYPE_TOP) != 0 || (mCtrlType & CTRL_TYPE_BOTTOM) != 0
+ || (mCtrlType & CTRL_TYPE_LEFT) != 0 || (mCtrlType & CTRL_TYPE_RIGHT) != 0;
+ }
+
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
index 265b10df1945..0d0a08cb0ffb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
@@ -31,6 +31,7 @@ import android.app.ActivityManager;
import android.app.WindowConfiguration;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Point;
import android.os.IBinder;
import android.util.DisplayMetrics;
import android.view.SurfaceControl;
@@ -75,6 +76,7 @@ public class ExitDesktopTaskTransitionHandlerTest extends ShellTestCase {
@Mock
ShellExecutor mExecutor;
+ private Point mPoint;
private ExitDesktopTaskTransitionHandler mExitDesktopTaskTransitionHandler;
@Before
@@ -90,6 +92,7 @@ public class ExitDesktopTaskTransitionHandlerTest extends ShellTestCase {
mExitDesktopTaskTransitionHandler = new ExitDesktopTaskTransitionHandler(mTransitions,
mContext);
+ mPoint = new Point(0, 0);
}
@Test
@@ -100,7 +103,8 @@ public class ExitDesktopTaskTransitionHandlerTest extends ShellTestCase {
doReturn(mToken).when(mTransitions)
.startTransition(transitionType, wct, mExitDesktopTaskTransitionHandler);
- mExitDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
+ mExitDesktopTaskTransitionHandler.startTransition(transitionType, wct, mPoint,
+ null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FULLSCREEN);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
index 9a90996b786c..4c27706a39a3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -29,6 +30,7 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.input.InputManager;
@@ -47,6 +49,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopTasksController;
@@ -68,6 +71,7 @@ import java.util.function.Supplier;
public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
private static final String TAG = "DesktopModeWindowDecorViewModelTests";
+ private static final Rect STABLE_INSETS = new Rect(0, 100, 0, 0);
@Mock private DesktopModeWindowDecoration mDesktopModeWindowDecoration;
@Mock private DesktopModeWindowDecoration.Factory mDesktopModeWindowDecorFactory;
@@ -76,6 +80,7 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
@Mock private Choreographer mMainChoreographer;
@Mock private ShellTaskOrganizer mTaskOrganizer;
@Mock private DisplayController mDisplayController;
+ @Mock private DisplayLayout mDisplayLayout;
@Mock private SplitScreenController mSplitScreenController;
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private DesktopModeController mDesktopModeController;
@@ -113,6 +118,8 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
.when(mDesktopModeWindowDecorFactory)
.create(any(), any(), any(), any(), any(), any(), any(), any());
doReturn(mTransaction).when(mTransactionFactory).get();
+ doReturn(mDisplayLayout).when(mDisplayController).getDisplayLayout(anyInt());
+ doReturn(STABLE_INSETS).when(mDisplayLayout).stableInsets();
when(mMockInputMonitorFactory.create(any(), any())).thenReturn(mInputMonitor);
// InputChannel cannot be mocked because it passes to InputEventReceiver.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
index 348b3659e864..de46b31879ed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -85,7 +85,7 @@ class DragPositioningCallbackUtilityTest {
@Test
fun testChangeBoundsDoesNotChangeHeightWhenLessThanMin() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Resize to width of 95px and height of 5px with min width of 10px
val newX = STARTING_BOUNDS.right.toFloat() - 5
@@ -93,8 +93,8 @@ class DragPositioningCallbackUtilityTest {
val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
- false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
- mockDisplayController, mockWindowDecoration)
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
@@ -105,7 +105,7 @@ class DragPositioningCallbackUtilityTest {
@Test
fun testChangeBoundsDoesNotChangeWidthWhenLessThanMin() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Resize to height of 95px and width of 5px with min width of 10px
val newX = STARTING_BOUNDS.right.toFloat() - 95
@@ -113,8 +113,8 @@ class DragPositioningCallbackUtilityTest {
val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
- false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
- mockDisplayController, mockWindowDecoration)
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top + 5)
@@ -125,7 +125,7 @@ class DragPositioningCallbackUtilityTest {
@Test
fun testChangeBoundsDoesNotChangeHeightWhenNegative() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Resize to width of 95px and width of -5px with minimum of 10px
val newX = STARTING_BOUNDS.right.toFloat() - 5
@@ -133,8 +133,8 @@ class DragPositioningCallbackUtilityTest {
val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
- false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
- mockDisplayController, mockWindowDecoration)
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
@@ -145,7 +145,7 @@ class DragPositioningCallbackUtilityTest {
@Test
fun testChangeBoundsRunsWhenResizeBoundsValid() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Shrink to height 20px and width 20px with both min height/width equal to 10px
val newX = STARTING_BOUNDS.right.toFloat() - 80
@@ -153,7 +153,7 @@ class DragPositioningCallbackUtilityTest {
val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
- false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
mockDisplayController, mockWindowDecoration)
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top + 80)
@@ -164,7 +164,7 @@ class DragPositioningCallbackUtilityTest {
@Test
fun testChangeBoundsDoesNotRunWithNegativeHeightAndWidth() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Shrink to height -5px and width -5px with both min height/width equal to 10px
val newX = STARTING_BOUNDS.right.toFloat() - 105
val newY = STARTING_BOUNDS.top.toFloat() + 105
@@ -172,7 +172,7 @@ class DragPositioningCallbackUtilityTest {
val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
- false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
mockDisplayController, mockWindowDecoration)
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
@@ -185,21 +185,21 @@ class DragPositioningCallbackUtilityTest {
var hasMoved = false
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(),
STARTING_BOUNDS.bottom.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Initial resize to width and height 110px.
var newX = STARTING_BOUNDS.right.toFloat() + 10
var newY = STARTING_BOUNDS.bottom.toFloat() + 10
var delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
assertTrue(DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
- hasMoved, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
- mockDisplayController, mockWindowDecoration))
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration))
hasMoved = true
// Resize width to 120px, height to disallowed area which should not result in a change.
newX += 10
newY = DISALLOWED_RESIZE_AREA.top.toFloat()
delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
assertTrue(DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
- hasMoved, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
mockDisplayController, mockWindowDecoration))
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
index 5bea8f2d1c45..282a19e8e9a5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
@@ -6,14 +6,16 @@ import android.graphics.Rect
import android.os.IBinder
import android.testing.AndroidTestingRunner
import android.view.Display
+import android.view.SurfaceControl
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING
import androidx.test.filters.SmallTest
-import com.android.wm.shell.common.DisplayController
-import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
@@ -21,12 +23,14 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
+import java.util.function.Supplier
+import org.mockito.Mockito.`when` as whenever
/**
* Tests for [FluidResizeTaskPositioner].
@@ -56,6 +60,10 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
private lateinit var mockDisplayLayout: DisplayLayout
@Mock
private lateinit var mockDisplay: Display
+ @Mock
+ private lateinit var mockTransactionFactory: Supplier<SurfaceControl.Transaction>
+ @Mock
+ private lateinit var mockTransaction: SurfaceControl.Transaction
private lateinit var taskPositioner: FluidResizeTaskPositioner
@@ -68,8 +76,10 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
mockShellTaskOrganizer,
mockWindowDecoration,
mockDisplayController,
- mockDragStartListener
- )
+ DISALLOWED_AREA_FOR_END_BOUNDS,
+ mockDragStartListener,
+ mockTransactionFactory
+ )
whenever(taskToken.asBinder()).thenReturn(taskBinder)
whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
@@ -77,6 +87,8 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
(i.arguments.first() as Rect).set(STABLE_BOUNDS)
}
+ `when`(mockDisplayLayout.stableInsets()).thenReturn(STABLE_INSETS)
+ `when`(mockTransactionFactory.get()).thenReturn(mockTransaction)
mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
taskId = TASK_ID
@@ -236,6 +248,318 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
})
}
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenLessThanMin() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to width of 95px and height of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 95
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.top ==
+ STARTING_BOUNDS.top &&
+ change.configuration.windowConfiguration.bounds.bottom ==
+ STARTING_BOUNDS.bottom
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenLessThanMin() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to height of 95px and width of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 95
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.right ==
+ STARTING_BOUNDS.right &&
+ change.configuration.windowConfiguration.bounds.left ==
+ STARTING_BOUNDS.left
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenNegative() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to height of -5px and width of 95px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 105
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.top ==
+ STARTING_BOUNDS.top &&
+ change.configuration.windowConfiguration.bounds.bottom ==
+ STARTING_BOUNDS.bottom
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenNegative() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to width of -5px and height of 95px
+ val newX = STARTING_BOUNDS.right.toFloat() - 105
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.right ==
+ STARTING_BOUNDS.right &&
+ change.configuration.windowConfiguration.bounds.left ==
+ STARTING_BOUNDS.left
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsRunsWhenResizeBoundsValid() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to height 20px and width 20px with both min height/width equal to 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 80
+ val newY = STARTING_BOUNDS.top.toFloat() + 80
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotRunWithNegativeHeightAndWidth() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to height 5px and width 5px with both min height/width equal to 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 95
+ val newY = STARTING_BOUNDS.top.toFloat() + 95
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_useDefaultMinWhenMinWidthInvalid() {
+ mockWindowDecoration.mTaskInfo.minWidth = -1
+
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to width and height of 3px with invalid minWidth = -1 and defaultMinSize = 5px
+ val newX = STARTING_BOUNDS.right.toFloat() - 97
+ val newY = STARTING_BOUNDS.top.toFloat() + 97
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_useMinWidthWhenValid() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to width and height of 7px with valid minWidth = 10px and defaultMinSize = 5px
+ val newX = STARTING_BOUNDS.right.toFloat() - 93
+ val newY = STARTING_BOUNDS.top.toFloat() + 93
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
+ fun testDragResize_toDisallowedBounds_freezesAtLimit() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, // Resize right-bottom corner
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.bottom.toFloat()
+ )
+
+ // Resize the task by 10px to the right and bottom, a valid destination
+ val newBounds = Rect(
+ STARTING_BOUNDS.left,
+ STARTING_BOUNDS.top,
+ STARTING_BOUNDS.right + 10,
+ STARTING_BOUNDS.bottom + 10)
+ taskPositioner.onDragPositioningMove(
+ newBounds.right.toFloat(),
+ newBounds.bottom.toFloat()
+ )
+
+ // Resize the task by another 10px to the right (allowed) and to just in the disallowed
+ // area of the Y coordinate.
+ val newBounds2 = Rect(
+ newBounds.left,
+ newBounds.top,
+ newBounds.right + 10,
+ DISALLOWED_RESIZE_AREA.top
+ )
+ taskPositioner.onDragPositioningMove(
+ newBounds2.right.toFloat(),
+ newBounds2.bottom.toFloat()
+ )
+
+ taskPositioner.onDragPositioningEnd(newBounds2.right.toFloat(), newBounds2.bottom.toFloat())
+
+ // The first resize falls in the allowed area, verify there's a change for it.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(newBounds)
+ }
+ })
+ // The second resize falls in the disallowed area, verify there's no change for it.
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(newBounds2)
+ }
+ })
+ // Instead, there should be a change for its allowed portion (the X movement) with the Y
+ // staying frozen in the last valid resize position.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(
+ Rect(
+ newBounds2.left,
+ newBounds2.top,
+ newBounds2.right,
+ newBounds.bottom // Stayed at the first resize destination.
+ )
+ )
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_drag_setBoundsNotRunIfDragEndsInDisallowedEndArea() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED, // drag
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ val newX = STARTING_BOUNDS.right.toFloat() + 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
private fun WindowContainerTransaction.Change.ofBounds(bounds: Rect): Boolean {
return ((windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) &&
bounds == configuration.windowConfiguration.bounds
@@ -251,6 +575,8 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
private const val NAVBAR_HEIGHT = 50
private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
+ private val STABLE_INSETS = Rect(0, 50, 0, 0)
+ private val DISALLOWED_AREA_FOR_END_BOUNDS = Rect(0, 0, 300, 300)
private val DISALLOWED_RESIZE_AREA = Rect(
DISPLAY_BOUNDS.left,
DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index 498082bd53e5..217bdbb07447 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -21,12 +21,13 @@ import android.graphics.Rect
import android.os.IBinder
import android.testing.AndroidTestingRunner
import android.view.Display
+import android.view.SurfaceControl
import android.window.WindowContainerToken
import androidx.test.filters.SmallTest
-import com.android.wm.shell.common.DisplayController
-import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
@@ -34,13 +35,16 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
+import org.mockito.Mockito.eq
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
+import java.util.function.Supplier
+import org.mockito.Mockito.`when` as whenever
/**
* Tests for [VeiledResizeTaskPositioner].
@@ -70,6 +74,10 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
private lateinit var mockDisplayLayout: DisplayLayout
@Mock
private lateinit var mockDisplay: Display
+ @Mock
+ private lateinit var mockTransactionFactory: Supplier<SurfaceControl.Transaction>
+ @Mock
+ private lateinit var mockTransaction: SurfaceControl.Transaction
private lateinit var taskPositioner: VeiledResizeTaskPositioner
@@ -82,7 +90,9 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
mockShellTaskOrganizer,
mockDesktopWindowDecoration,
mockDisplayController,
- mockDragStartListener
+ DISALLOWED_AREA_FOR_END_BOUNDS,
+ mockDragStartListener,
+ mockTransactionFactory
)
whenever(taskToken.asBinder()).thenReturn(taskBinder)
@@ -91,6 +101,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
(i.arguments.first() as Rect).set(STABLE_BOUNDS)
}
+ `when`(mockTransactionFactory.get()).thenReturn(mockTransaction)
mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
taskId = TASK_ID
@@ -125,36 +136,31 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
fun testDragResize_movesTask_doesNotShowResizeVeil() {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_UNDEFINED,
- STARTING_BOUNDS.left.toFloat() + 50,
+ STARTING_BOUNDS.left.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
taskPositioner.onDragPositioningMove(
STARTING_BOUNDS.left.toFloat() + 60,
- STARTING_BOUNDS.top.toFloat() + 10
+ STARTING_BOUNDS.top.toFloat() + 100
)
val rectAfterMove = Rect(STARTING_BOUNDS)
- rectAfterMove.left += 10
- rectAfterMove.right += 10
- rectAfterMove.top += 10
- rectAfterMove.bottom += 10
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
- change.configuration.windowConfiguration.bounds == rectAfterMove
- }
- })
+ rectAfterMove.left += 60
+ rectAfterMove.right += 60
+ rectAfterMove.top += 100
+ rectAfterMove.bottom += 100
+ verify(mockTransaction).setPosition(any(), eq(rectAfterMove.left.toFloat()),
+ eq(rectAfterMove.top.toFloat()))
taskPositioner.onDragPositioningEnd(
STARTING_BOUNDS.left.toFloat() + 70,
STARTING_BOUNDS.top.toFloat() + 20
)
- val rectAfterEnd = Rect(rectAfterMove)
- rectAfterEnd.left += 10
- rectAfterEnd.top += 10
- rectAfterEnd.right += 10
- rectAfterEnd.bottom += 10
+ val rectAfterEnd = Rect(STARTING_BOUNDS)
+ rectAfterEnd.left += 70
+ rectAfterEnd.right += 70
+ rectAfterEnd.top += 20
+ rectAfterEnd.bottom += 20
verify(mockDesktopWindowDecoration, never()).createResizeVeil()
verify(mockDesktopWindowDecoration, never()).hideResizeVeil()
@@ -239,6 +245,32 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
})
}
+
+ @Test
+ fun testDragResize_drag_setBoundsNotRunIfDragEndsInDisallowedEndArea() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED, // drag
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ val newX = STARTING_BOUNDS.left.toFloat() + 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
companion object {
private const val TASK_ID = 5
private const val MIN_WIDTH = 10
@@ -249,6 +281,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
private const val NAVBAR_HEIGHT = 50
private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
+ private val DISALLOWED_AREA_FOR_END_BOUNDS = Rect(0, 0, 50, 50)
private val STABLE_BOUNDS = Rect(
DISPLAY_BOUNDS.left,
DISPLAY_BOUNDS.top,