Merge "Update positioning during drag using SurfaceControl.Transaction" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
80314dbdcc
@@ -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