Loading services/core/java/com/android/server/wm/TaskPositioner.java +42 −64 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP; import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP; import android.annotation.NonNull; import android.app.IActivityTaskManager; import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; Loading @@ -48,7 +47,6 @@ import android.util.DisplayMetrics; import android.util.Slog; import android.view.BatchedInputEventReceiver; import android.view.Choreographer; import android.view.Display; import android.view.InputApplicationHandle; import android.view.InputChannel; import android.view.InputDevice; Loading @@ -75,10 +73,8 @@ class TaskPositioner implements IBinder.DeathRecipient { public static final int RESIZING_HINT_DURATION_MS = 0; private final WindowManagerService mService; private final IActivityTaskManager mActivityManager; private WindowPositionerEventReceiver mInputEventReceiver; private DisplayContent mDisplayContent; private final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); private Rect mTmpRect = new Rect(); private int mMinVisibleWidth; private int mMinVisibleHeight; Loading Loading @@ -151,11 +147,8 @@ class TaskPositioner implements IBinder.DeathRecipient { if (!mTmpRect.equals(mWindowDragBounds)) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.TaskPositioner.resizeTask"); try { mActivityManager.resizeTask( mService.mAtmService.resizeTask( mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER); } catch (RemoteException e) { } Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } } break; Loading @@ -181,14 +174,12 @@ class TaskPositioner implements IBinder.DeathRecipient { endDragLocked(); mTask.getDimBounds(mTmpRect); } try { if (wasResizing && !mTmpRect.equals(mWindowDragBounds)) { // We were using fullscreen surface during resizing. Request // resizeTask() one last time to restore surface to window size. mActivityManager.resizeTask( mService.mAtmService.resizeTask( mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED); } } catch(RemoteException e) {} // Post back to WM to handle clean-ups. We still need the input // event handler for the last finishInputEvent()! Loading @@ -203,15 +194,10 @@ class TaskPositioner implements IBinder.DeathRecipient { } } /** Use {@link #create(WindowManagerService)} instead. */ @VisibleForTesting TaskPositioner(WindowManagerService service, IActivityTaskManager activityManager) { mService = service; mActivityManager = activityManager; } /** Use {@link #create(WindowManagerService)} instead **/ TaskPositioner(WindowManagerService service) { this(service, service.mActivityTaskManager); mService = service; } @VisibleForTesting Loading @@ -224,8 +210,6 @@ class TaskPositioner implements IBinder.DeathRecipient { * @param win The window which will be dragged. */ void register(DisplayContent displayContent, @NonNull WindowState win) { final Display display = displayContent.getDisplay(); if (DEBUG_TASK_POSITIONING) { Slog.d(TAG, "Registering task positioner"); } Loading @@ -236,7 +220,6 @@ class TaskPositioner implements IBinder.DeathRecipient { } mDisplayContent = displayContent; display.getMetrics(mDisplayMetrics); final InputChannel[] channels = InputChannel.openInputChannelPair(TAG); mServerChannel = channels[0]; mClientChannel = channels[1]; Loading @@ -251,7 +234,8 @@ class TaskPositioner implements IBinder.DeathRecipient { mDragApplicationHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, display.getDisplayId()); mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, displayContent.getDisplayId()); mDragWindowHandle.name = TAG; mDragWindowHandle.token = mServerChannel.getToken(); mDragWindowHandle.layoutParamsFlags = 0; Loading @@ -271,13 +255,13 @@ class TaskPositioner implements IBinder.DeathRecipient { // The drag window cannot receive new touches. mDragWindowHandle.touchableRegion.setEmpty(); // The drag window covers the entire display mDragWindowHandle.frameLeft = 0; mDragWindowHandle.frameTop = 0; final Point p = new Point(); display.getRealSize(p); mDragWindowHandle.frameRight = p.x; mDragWindowHandle.frameBottom = p.y; // The drag window covers the entire display. final Rect displayBounds = mTmpRect; displayContent.getBounds(mTmpRect); mDragWindowHandle.frameLeft = displayBounds.left; mDragWindowHandle.frameTop = displayBounds.top; mDragWindowHandle.frameRight = displayBounds.right; mDragWindowHandle.frameBottom = displayBounds.bottom; // Pause rotations before a drag. ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during re-position"); Loading @@ -287,9 +271,10 @@ class TaskPositioner implements IBinder.DeathRecipient { mDisplayContent.getInputMonitor().updateInputWindowsImmediately(); new SurfaceControl.Transaction().syncInputWindows().apply(true); mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics); display.getRealSize(mMaxVisibleSize); final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics(); mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics); mMaxVisibleSize.set(displayBounds.width(), displayBounds.height()); mDragEnded = false; Loading Loading @@ -341,8 +326,11 @@ class TaskPositioner implements IBinder.DeathRecipient { mWindow = null; } void startDrag(boolean resize, boolean preserveOrientation, float startX, float startY) { /** * Starts moving or resizing the task. This method should be only called from * {@link TaskPositioningController#startPositioningLocked} or unit tests. */ void startDrag(boolean resize, boolean preserveOrientation, float startX, float startY) { if (DEBUG_TASK_POSITIONING) { Slog.d(TAG, "startDrag: win=" + mWindow + ", resize=" + resize + ", preserveOrientation=" + preserveOrientation + ", {" + startX + ", " Loading @@ -351,12 +339,9 @@ class TaskPositioner implements IBinder.DeathRecipient { // Use the bounds of the task which accounts for // multiple app windows. Don't use any bounds from win itself as it // may not be the same size as the task. mTask.getBounds(mTmpRect); startDrag(resize, preserveOrientation, startX, startY, mTmpRect); } final Rect startBounds = mTmpRect; mTask.getBounds(startBounds); protected void startDrag(boolean resize, boolean preserveOrientation, float startX, float startY, Rect startBounds) { mCtrlType = CTRL_NONE; mStartDragX = startX; mStartDragY = startY; Loading Loading @@ -389,20 +374,13 @@ class TaskPositioner implements IBinder.DeathRecipient { // bounds yet. This will guarantee that the app starts the backdrop renderer before // configuration changes which could cause an activity restart. if (mResizing) { synchronized (mService.mGlobalLock) { notifyMoveLocked(startX, startY); } // Perform the resize on the WMS handler thread when we don't have the WMS lock held // to ensure that we don't deadlock WMS and AMS. Note that WindowPositionerEventReceiver // callbacks are delivered on the same handler so this initial resize is always // guaranteed to happen before subsequent drag resizes. // The WindowPositionerEventReceiver callbacks are delivered on the same handler so this // initial resize is always guaranteed to happen before subsequent drag resizes. mService.mH.post(() -> { try { mActivityManager.resizeTask( mService.mAtmService.resizeTask( mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED); } catch (RemoteException e) { } }); } Loading @@ -417,7 +395,8 @@ class TaskPositioner implements IBinder.DeathRecipient { } /** Returns true if the move operation should be ended. */ private boolean notifyMoveLocked(float x, float y) { @VisibleForTesting boolean notifyMoveLocked(float x, float y) { if (DEBUG_TASK_POSITIONING) { Slog.d(TAG, "notifyMoveLocked: {" + x + "," + y + "}"); } Loading @@ -429,12 +408,11 @@ class TaskPositioner implements IBinder.DeathRecipient { } // This is a moving or scrolling operation. mTask.getStack().getDimBounds(mTmpRect); // If a target window is covered by system bar, there is no way to move it again by touch. // So we exclude them from stack bounds. and then it will be shown inside stable area. Rect stableBounds = new Rect(); mDisplayContent.getStableRect(stableBounds); mTmpRect.intersect(stableBounds); // Only allow to move in stable area so the target window won't be covered by system bar. // Though {@link Task#resolveOverrideConfiguration} should also avoid the case. mDisplayContent.getStableRect(mTmpRect); // The task may be put in a limited display area. mTmpRect.intersect(mTask.getRootTask().getParent().getBounds()); int nX = (int) x; int nY = (int) y; Loading services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +4 −0 Original line number Diff line number Diff line Loading @@ -234,6 +234,10 @@ class ActivityTestsBase extends SystemServiceTestsBase { mTask = new TaskBuilder(mService.mStackSupervisor) .setComponent(mComponent) .setStack(mStack).build(); } else if (mTask == null && mStack != null && DisplayContent.alwaysCreateStack( mStack.getWindowingMode(), mStack.getActivityType())) { // The stack can be the task root. mTask = mStack; } Intent intent = new Intent(); Loading services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java +31 −7 Original line number Diff line number Diff line Loading @@ -36,7 +36,6 @@ import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; Loading Loading @@ -71,18 +70,21 @@ public class TaskPositionerTests extends WindowTestsBase { public void setUp() { TaskPositioner.setFactory(null); final Display display = mDisplayContent.getDisplay(); final DisplayMetrics dm = new DisplayMetrics(); display.getMetrics(dm); final DisplayMetrics dm = mDisplayContent.getDisplayMetrics(); // This should be the same calculation as the TaskPositioner uses. mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm); removeGlobalMinSizeRestriction(); WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "window"); mPositioner = new TaskPositioner(mWm, mWm.mAtmService); final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService) .setStack(stack) // In real case, there is no additional level for freeform mode. .setCreateTask(false) .build(); final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "window"); mPositioner = new TaskPositioner(mWm); mPositioner.register(mDisplayContent, win); win.getRootTask().setWindowingMode(WINDOWING_MODE_FREEFORM); Loading @@ -109,6 +111,28 @@ public class TaskPositionerTests extends WindowTestsBase { assertTrue(created[0]); } /** This tests that the window can move in all directions. */ @Test public void testMoveWindow() { final Rect displayBounds = mDisplayContent.getBounds(); final int windowSize = Math.min(displayBounds.width(), displayBounds.height()) / 2; final int left = displayBounds.centerX() - windowSize / 2; final int top = displayBounds.centerY() - windowSize / 2; final Rect r = new Rect(left, top, left + windowSize, top + windowSize); mPositioner.mTask.setBounds(r); mPositioner.startDrag(false /* resizing */, false /* preserveOrientation */, left, top); // Move upper left. mPositioner.notifyMoveLocked(left - MOUSE_DELTA_X, top - MOUSE_DELTA_Y); r.offset(-MOUSE_DELTA_X, -MOUSE_DELTA_Y); assertBoundsEquals(r, mPositioner.getWindowDragBounds()); // Move bottom right. mPositioner.notifyMoveLocked(left, top); r.offset(MOUSE_DELTA_X, MOUSE_DELTA_Y); assertBoundsEquals(r, mPositioner.getWindowDragBounds()); } /** * This tests that free resizing will allow to change the orientation as well * as does some basic tests (e.g. dragging in Y only will keep X stable). Loading Loading
services/core/java/com/android/server/wm/TaskPositioner.java +42 −64 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP; import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP; import android.annotation.NonNull; import android.app.IActivityTaskManager; import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; Loading @@ -48,7 +47,6 @@ import android.util.DisplayMetrics; import android.util.Slog; import android.view.BatchedInputEventReceiver; import android.view.Choreographer; import android.view.Display; import android.view.InputApplicationHandle; import android.view.InputChannel; import android.view.InputDevice; Loading @@ -75,10 +73,8 @@ class TaskPositioner implements IBinder.DeathRecipient { public static final int RESIZING_HINT_DURATION_MS = 0; private final WindowManagerService mService; private final IActivityTaskManager mActivityManager; private WindowPositionerEventReceiver mInputEventReceiver; private DisplayContent mDisplayContent; private final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); private Rect mTmpRect = new Rect(); private int mMinVisibleWidth; private int mMinVisibleHeight; Loading Loading @@ -151,11 +147,8 @@ class TaskPositioner implements IBinder.DeathRecipient { if (!mTmpRect.equals(mWindowDragBounds)) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.TaskPositioner.resizeTask"); try { mActivityManager.resizeTask( mService.mAtmService.resizeTask( mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER); } catch (RemoteException e) { } Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } } break; Loading @@ -181,14 +174,12 @@ class TaskPositioner implements IBinder.DeathRecipient { endDragLocked(); mTask.getDimBounds(mTmpRect); } try { if (wasResizing && !mTmpRect.equals(mWindowDragBounds)) { // We were using fullscreen surface during resizing. Request // resizeTask() one last time to restore surface to window size. mActivityManager.resizeTask( mService.mAtmService.resizeTask( mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED); } } catch(RemoteException e) {} // Post back to WM to handle clean-ups. We still need the input // event handler for the last finishInputEvent()! Loading @@ -203,15 +194,10 @@ class TaskPositioner implements IBinder.DeathRecipient { } } /** Use {@link #create(WindowManagerService)} instead. */ @VisibleForTesting TaskPositioner(WindowManagerService service, IActivityTaskManager activityManager) { mService = service; mActivityManager = activityManager; } /** Use {@link #create(WindowManagerService)} instead **/ TaskPositioner(WindowManagerService service) { this(service, service.mActivityTaskManager); mService = service; } @VisibleForTesting Loading @@ -224,8 +210,6 @@ class TaskPositioner implements IBinder.DeathRecipient { * @param win The window which will be dragged. */ void register(DisplayContent displayContent, @NonNull WindowState win) { final Display display = displayContent.getDisplay(); if (DEBUG_TASK_POSITIONING) { Slog.d(TAG, "Registering task positioner"); } Loading @@ -236,7 +220,6 @@ class TaskPositioner implements IBinder.DeathRecipient { } mDisplayContent = displayContent; display.getMetrics(mDisplayMetrics); final InputChannel[] channels = InputChannel.openInputChannelPair(TAG); mServerChannel = channels[0]; mClientChannel = channels[1]; Loading @@ -251,7 +234,8 @@ class TaskPositioner implements IBinder.DeathRecipient { mDragApplicationHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, display.getDisplayId()); mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, displayContent.getDisplayId()); mDragWindowHandle.name = TAG; mDragWindowHandle.token = mServerChannel.getToken(); mDragWindowHandle.layoutParamsFlags = 0; Loading @@ -271,13 +255,13 @@ class TaskPositioner implements IBinder.DeathRecipient { // The drag window cannot receive new touches. mDragWindowHandle.touchableRegion.setEmpty(); // The drag window covers the entire display mDragWindowHandle.frameLeft = 0; mDragWindowHandle.frameTop = 0; final Point p = new Point(); display.getRealSize(p); mDragWindowHandle.frameRight = p.x; mDragWindowHandle.frameBottom = p.y; // The drag window covers the entire display. final Rect displayBounds = mTmpRect; displayContent.getBounds(mTmpRect); mDragWindowHandle.frameLeft = displayBounds.left; mDragWindowHandle.frameTop = displayBounds.top; mDragWindowHandle.frameRight = displayBounds.right; mDragWindowHandle.frameBottom = displayBounds.bottom; // Pause rotations before a drag. ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during re-position"); Loading @@ -287,9 +271,10 @@ class TaskPositioner implements IBinder.DeathRecipient { mDisplayContent.getInputMonitor().updateInputWindowsImmediately(); new SurfaceControl.Transaction().syncInputWindows().apply(true); mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics); display.getRealSize(mMaxVisibleSize); final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics(); mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics); mMaxVisibleSize.set(displayBounds.width(), displayBounds.height()); mDragEnded = false; Loading Loading @@ -341,8 +326,11 @@ class TaskPositioner implements IBinder.DeathRecipient { mWindow = null; } void startDrag(boolean resize, boolean preserveOrientation, float startX, float startY) { /** * Starts moving or resizing the task. This method should be only called from * {@link TaskPositioningController#startPositioningLocked} or unit tests. */ void startDrag(boolean resize, boolean preserveOrientation, float startX, float startY) { if (DEBUG_TASK_POSITIONING) { Slog.d(TAG, "startDrag: win=" + mWindow + ", resize=" + resize + ", preserveOrientation=" + preserveOrientation + ", {" + startX + ", " Loading @@ -351,12 +339,9 @@ class TaskPositioner implements IBinder.DeathRecipient { // Use the bounds of the task which accounts for // multiple app windows. Don't use any bounds from win itself as it // may not be the same size as the task. mTask.getBounds(mTmpRect); startDrag(resize, preserveOrientation, startX, startY, mTmpRect); } final Rect startBounds = mTmpRect; mTask.getBounds(startBounds); protected void startDrag(boolean resize, boolean preserveOrientation, float startX, float startY, Rect startBounds) { mCtrlType = CTRL_NONE; mStartDragX = startX; mStartDragY = startY; Loading Loading @@ -389,20 +374,13 @@ class TaskPositioner implements IBinder.DeathRecipient { // bounds yet. This will guarantee that the app starts the backdrop renderer before // configuration changes which could cause an activity restart. if (mResizing) { synchronized (mService.mGlobalLock) { notifyMoveLocked(startX, startY); } // Perform the resize on the WMS handler thread when we don't have the WMS lock held // to ensure that we don't deadlock WMS and AMS. Note that WindowPositionerEventReceiver // callbacks are delivered on the same handler so this initial resize is always // guaranteed to happen before subsequent drag resizes. // The WindowPositionerEventReceiver callbacks are delivered on the same handler so this // initial resize is always guaranteed to happen before subsequent drag resizes. mService.mH.post(() -> { try { mActivityManager.resizeTask( mService.mAtmService.resizeTask( mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED); } catch (RemoteException e) { } }); } Loading @@ -417,7 +395,8 @@ class TaskPositioner implements IBinder.DeathRecipient { } /** Returns true if the move operation should be ended. */ private boolean notifyMoveLocked(float x, float y) { @VisibleForTesting boolean notifyMoveLocked(float x, float y) { if (DEBUG_TASK_POSITIONING) { Slog.d(TAG, "notifyMoveLocked: {" + x + "," + y + "}"); } Loading @@ -429,12 +408,11 @@ class TaskPositioner implements IBinder.DeathRecipient { } // This is a moving or scrolling operation. mTask.getStack().getDimBounds(mTmpRect); // If a target window is covered by system bar, there is no way to move it again by touch. // So we exclude them from stack bounds. and then it will be shown inside stable area. Rect stableBounds = new Rect(); mDisplayContent.getStableRect(stableBounds); mTmpRect.intersect(stableBounds); // Only allow to move in stable area so the target window won't be covered by system bar. // Though {@link Task#resolveOverrideConfiguration} should also avoid the case. mDisplayContent.getStableRect(mTmpRect); // The task may be put in a limited display area. mTmpRect.intersect(mTask.getRootTask().getParent().getBounds()); int nX = (int) x; int nY = (int) y; Loading
services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +4 −0 Original line number Diff line number Diff line Loading @@ -234,6 +234,10 @@ class ActivityTestsBase extends SystemServiceTestsBase { mTask = new TaskBuilder(mService.mStackSupervisor) .setComponent(mComponent) .setStack(mStack).build(); } else if (mTask == null && mStack != null && DisplayContent.alwaysCreateStack( mStack.getWindowingMode(), mStack.getActivityType())) { // The stack can be the task root. mTask = mStack; } Intent intent = new Intent(); Loading
services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java +31 −7 Original line number Diff line number Diff line Loading @@ -36,7 +36,6 @@ import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; Loading Loading @@ -71,18 +70,21 @@ public class TaskPositionerTests extends WindowTestsBase { public void setUp() { TaskPositioner.setFactory(null); final Display display = mDisplayContent.getDisplay(); final DisplayMetrics dm = new DisplayMetrics(); display.getMetrics(dm); final DisplayMetrics dm = mDisplayContent.getDisplayMetrics(); // This should be the same calculation as the TaskPositioner uses. mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm); removeGlobalMinSizeRestriction(); WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "window"); mPositioner = new TaskPositioner(mWm, mWm.mAtmService); final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService) .setStack(stack) // In real case, there is no additional level for freeform mode. .setCreateTask(false) .build(); final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "window"); mPositioner = new TaskPositioner(mWm); mPositioner.register(mDisplayContent, win); win.getRootTask().setWindowingMode(WINDOWING_MODE_FREEFORM); Loading @@ -109,6 +111,28 @@ public class TaskPositionerTests extends WindowTestsBase { assertTrue(created[0]); } /** This tests that the window can move in all directions. */ @Test public void testMoveWindow() { final Rect displayBounds = mDisplayContent.getBounds(); final int windowSize = Math.min(displayBounds.width(), displayBounds.height()) / 2; final int left = displayBounds.centerX() - windowSize / 2; final int top = displayBounds.centerY() - windowSize / 2; final Rect r = new Rect(left, top, left + windowSize, top + windowSize); mPositioner.mTask.setBounds(r); mPositioner.startDrag(false /* resizing */, false /* preserveOrientation */, left, top); // Move upper left. mPositioner.notifyMoveLocked(left - MOUSE_DELTA_X, top - MOUSE_DELTA_Y); r.offset(-MOUSE_DELTA_X, -MOUSE_DELTA_Y); assertBoundsEquals(r, mPositioner.getWindowDragBounds()); // Move bottom right. mPositioner.notifyMoveLocked(left, top); r.offset(MOUSE_DELTA_X, MOUSE_DELTA_Y); assertBoundsEquals(r, mPositioner.getWindowDragBounds()); } /** * This tests that free resizing will allow to change the orientation as well * as does some basic tests (e.g. dragging in Y only will keep X stable). Loading