Update positioning during drag using SurfaceControl.Transaction
When the bounds are updated pixel by pixel using a WCT in task positioner, it updates mLastNonFullscreenBounds. So, when the task is dragged to the top to transition into fullscreen, mLastNonFullscreenBounds is updated, and, when we transition back to freeform using the handle menu, the positioning of the task is at the top. By using SurfaceControl.Transactions to update the positioning, mLastNonFullscreenBounds is left untouched when transitioning to fullscreen via dragging. Bug: 277137896 Test: Drag task from freeform to fullscreen and then transition task back to freeform using handle menu. Task should be in positiom before drag. Change-Id: Idba8523e3c8851b30ef5938b921e9b4ed23bcefa
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)) {
|
||||
@@ -125,9 +125,27 @@ public class DragPositioningCallbackUtility {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user