blob: 7abe3698a99c198638f0a51b12acb1d8134edb26 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.internal.policy.TaskResizingAlgorithm.MIN_ASPECT;
import static com.android.server.wm.WindowManagerService.dipToPixel;
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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.util.Log;
import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Tests for the {@link TaskPositioner} class.
*
* Build/Install/Run:
* atest WmTests:TaskPositionerTests
*/
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
public class TaskPositionerTests extends WindowTestsBase {
private static final boolean DEBUGGING = false;
private static final String TAG = "TaskPositionerTest";
private static final int MOUSE_DELTA_X = 5;
private static final int MOUSE_DELTA_Y = 5;
private int mMinVisibleWidth;
private int mMinVisibleHeight;
private TaskPositioner mPositioner;
@Before
public void setUp() {
TaskPositioner.setFactory(null);
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();
final ActivityRecord activity = new ActivityBuilder(mAtm)
.setCreateTask(true)
.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);
}
@After
public void tearDown() {
mPositioner = null;
}
@Test
public void testOverrideFactory() {
final boolean[] created = new boolean[1];
created[0] = false;
TaskPositioner.setFactory(new TaskPositioner.Factory() {
@Override
public TaskPositioner create(WindowManagerService service) {
created[0] = true;
return null;
}
});
assertNull(TaskPositioner.create(mWm));
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).
*/
@Test
public void testBasicFreeWindowResizing() {
final Rect r = new Rect(100, 220, 700, 520);
final int midY = (r.top + r.bottom) / 2;
mPositioner.mTask.setBounds(r, true);
// Start a drag resize starting upper left.
mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
assertBoundsEquals(r, mPositioner.getWindowDragBounds());
// Drag to a good landscape size.
mPositioner.resizeDrag(0.0f, 0.0f);
assertBoundsEquals(new Rect(MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to a good portrait size.
mPositioner.resizeDrag(400.0f, 0.0f);
assertBoundsEquals(new Rect(400 + MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to a too small size for the width.
mPositioner.resizeDrag(2000.0f, r.top);
assertBoundsEquals(
new Rect(r.right - mMinVisibleWidth, r.top + MOUSE_DELTA_Y, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to a too small size for the height.
mPositioner.resizeDrag(r.left, 2000.0f);
assertBoundsEquals(
new Rect(r.left + MOUSE_DELTA_X, r.bottom - mMinVisibleHeight, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Start a drag resize left and see that only the left coord changes..
mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
r.left - MOUSE_DELTA_X, midY);
// Drag to the left.
mPositioner.resizeDrag(0.0f, midY);
assertBoundsEquals(new Rect(MOUSE_DELTA_X, r.top, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the right.
mPositioner.resizeDrag(200.0f, midY);
assertBoundsEquals(new Rect(200 + MOUSE_DELTA_X, r.top, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the top
mPositioner.resizeDrag(r.left, 0.0f);
assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the bottom
mPositioner.resizeDrag(r.left, 1000.0f);
assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
mPositioner.getWindowDragBounds());
}
/**
* This tests that by dragging any edge, the fixed / opposite edge(s) remains anchored.
*/
@Test
public void testFreeWindowResizingTestAllEdges() {
final Rect r = new Rect(100, 220, 700, 520);
final int midX = (r.left + r.right) / 2;
final int midY = (r.top + r.bottom) / 2;
mPositioner.mTask.setBounds(r, true);
// Drag upper left.
mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
mPositioner.resizeDrag(0.0f, 0.0f);
assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
assertEquals(r.right, mPositioner.getWindowDragBounds().right);
assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
// Drag upper.
mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */, midX,
r.top - MOUSE_DELTA_Y);
mPositioner.resizeDrag(0.0f, 0.0f);
assertEquals(r.left, mPositioner.getWindowDragBounds().left);
assertEquals(r.right, mPositioner.getWindowDragBounds().right);
assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
// Drag upper right.
mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
mPositioner.resizeDrag(r.right + 100, 0.0f);
assertEquals(r.left, mPositioner.getWindowDragBounds().left);
assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
// Drag right.
mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
r.right + MOUSE_DELTA_X, midY);
mPositioner.resizeDrag(r.right + 100, 0.0f);
assertEquals(r.left, mPositioner.getWindowDragBounds().left);
assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
assertEquals(r.top, mPositioner.getWindowDragBounds().top);
assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
// Drag bottom right.
mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
r.right + MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
assertEquals(r.left, mPositioner.getWindowDragBounds().left);
assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
assertEquals(r.top, mPositioner.getWindowDragBounds().top);
assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
// Drag bottom.
mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */, midX,
r.bottom + MOUSE_DELTA_Y);
mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
assertEquals(r.left, mPositioner.getWindowDragBounds().left);
assertEquals(r.right, mPositioner.getWindowDragBounds().right);
assertEquals(r.top, mPositioner.getWindowDragBounds().top);
assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
// Drag bottom left.
mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
mPositioner.resizeDrag(0.0f, r.bottom + 100);
assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
assertEquals(r.right, mPositioner.getWindowDragBounds().right);
assertEquals(r.top, mPositioner.getWindowDragBounds().top);
assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
// Drag left.
mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
r.left - MOUSE_DELTA_X, midY);
mPositioner.resizeDrag(0.0f, r.bottom + 100);
assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
assertEquals(r.right, mPositioner.getWindowDragBounds().right);
assertEquals(r.top, mPositioner.getWindowDragBounds().top);
assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
}
/**
* This tests that a constrained landscape window will keep the aspect and do the
* right things upon resizing when dragged from the top left corner.
*/
@Test
public void testLandscapePreservedWindowResizingDragTopLeft() {
final Rect r = new Rect(100, 220, 700, 520);
mPositioner.mTask.setBounds(r, true);
mPositioner.startDrag(true /* resizing */, true /* preserveOrientation */,
r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
assertBoundsEquals(r, mPositioner.getWindowDragBounds());
// Drag to a good landscape size.
mPositioner.resizeDrag(0.0f, 0.0f);
assertBoundsEquals(new Rect(MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to a good portrait size.
mPositioner.resizeDrag(400.0f, 0.0f);
int width = Math.round((float) (r.bottom - MOUSE_DELTA_Y) * MIN_ASPECT);
assertBoundsEquals(new Rect(r.right - width, MOUSE_DELTA_Y, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to a too small size for the width.
mPositioner.resizeDrag(2000.0f, r.top);
final int w = mMinVisibleWidth;
final int h = Math.round(w / MIN_ASPECT);
assertBoundsEquals(new Rect(r.right - w, r.bottom - h, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to a too small size for the height.
mPositioner.resizeDrag(r.left, 2000.0f);
assertBoundsEquals(
new Rect(r.left + MOUSE_DELTA_X, r.bottom - mMinVisibleHeight, r.right, r.bottom),
mPositioner.getWindowDragBounds());
}
/**
* This tests that a constrained landscape window will keep the aspect and do the
* right things upon resizing when dragged from the left corner.
*/
@Test
public void testLandscapePreservedWindowResizingDragLeft() {
final Rect r = new Rect(100, 220, 700, 520);
final int midY = (r.top + r.bottom) / 2;
mPositioner.mTask.setBounds(r, true);
mPositioner.startDrag(true /* resizing */, true /* preserveOrientation */,
r.left - MOUSE_DELTA_X, midY);
// Drag to the left.
mPositioner.resizeDrag(0.0f, midY);
assertBoundsEquals(new Rect(MOUSE_DELTA_X, r.top, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the right.
mPositioner.resizeDrag(200.0f, midY);
assertBoundsEquals(new Rect(200 + MOUSE_DELTA_X, r.top, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag all the way to the right and see the height also shrinking.
mPositioner.resizeDrag(2000.0f, midY);
final int w = mMinVisibleWidth;
final int h = Math.round((float) w / MIN_ASPECT);
assertBoundsEquals(new Rect(r.right - w, r.top, r.right, r.top + h),
mPositioner.getWindowDragBounds());
// Drag to the top.
mPositioner.resizeDrag(r.left, 0.0f);
assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the bottom.
mPositioner.resizeDrag(r.left, 1000.0f);
assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
mPositioner.getWindowDragBounds());
}
/**
* This tests that a constrained landscape window will keep the aspect and do the
* right things upon resizing when dragged from the top corner.
*/
@Test
public void testLandscapePreservedWindowResizingDragTop() {
final Rect r = new Rect(100, 220, 700, 520);
final int midX = (r.left + r.right) / 2;
mPositioner.mTask.setBounds(r, true);
mPositioner.startDrag(true /*resizing*/, true /*preserveOrientation*/, midX,
r.top - MOUSE_DELTA_Y);
// Drag to the left (no change).
mPositioner.resizeDrag(0.0f, r.top);
assertBoundsEquals(new Rect(r.left, r.top + MOUSE_DELTA_Y, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the right (no change).
mPositioner.resizeDrag(2000.0f, r.top);
assertBoundsEquals(new Rect(r.left , r.top + MOUSE_DELTA_Y, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the top.
mPositioner.resizeDrag(300.0f, 0.0f);
int h = r.bottom - MOUSE_DELTA_Y;
int w = Math.max(r.right - r.left, Math.round(h * MIN_ASPECT));
assertBoundsEquals(new Rect(r.left, MOUSE_DELTA_Y, r.left + w, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the bottom.
mPositioner.resizeDrag(r.left, 1000.0f);
h = mMinVisibleHeight;
assertBoundsEquals(new Rect(r.left, r.bottom - h, r.right, r.bottom),
mPositioner.getWindowDragBounds());
}
/**
* This tests that a constrained portrait window will keep the aspect and do the
* right things upon resizing when dragged from the top left corner.
*/
@Test
public void testPortraitPreservedWindowResizingDragTopLeft() {
final Rect r = new Rect(330, 100, 630, 600);
mPositioner.mTask.setBounds(r, true);
mPositioner.startDrag(true /*resizing*/, true /*preserveOrientation*/,
r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
assertBoundsEquals(r, mPositioner.getWindowDragBounds());
// Drag to a good landscape size.
mPositioner.resizeDrag(0.0f, 0.0f);
int height = Math.round((float) (r.right - MOUSE_DELTA_X) * MIN_ASPECT);
assertBoundsEquals(new Rect(MOUSE_DELTA_X, r.bottom - height, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to a good portrait size.
mPositioner.resizeDrag(400.0f, 0.0f);
assertBoundsEquals(new Rect(400 + MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to a too small size for the height and the the width shrinking.
mPositioner.resizeDrag(r.left + MOUSE_DELTA_X, 2000.0f);
final int w = Math.max(mMinVisibleWidth, Math.round(mMinVisibleHeight / MIN_ASPECT));
final int h = Math.max(mMinVisibleHeight, Math.round(w * MIN_ASPECT));
assertBoundsEquals(
new Rect(r.right - w, r.bottom - h, r.right, r.bottom),
mPositioner.getWindowDragBounds());
}
/**
* This tests that a constrained portrait window will keep the aspect and do the
* right things upon resizing when dragged from the left corner.
*/
@Test
public void testPortraitPreservedWindowResizingDragLeft() {
final Rect r = new Rect(330, 100, 630, 600);
final int midY = (r.top + r.bottom) / 2;
mPositioner.mTask.setBounds(r, true);
mPositioner.startDrag(true /* resizing */, true /* preserveOrientation */,
r.left - MOUSE_DELTA_X, midY);
// Drag to the left.
mPositioner.resizeDrag(0.0f, midY);
int w = r.right - MOUSE_DELTA_X;
int h = Math.round(w * MIN_ASPECT);
assertBoundsEquals(new Rect(MOUSE_DELTA_X, r.top, r.right, r.top + h),
mPositioner.getWindowDragBounds());
// Drag to the right.
mPositioner.resizeDrag(450.0f, midY);
assertBoundsEquals(new Rect(450 + MOUSE_DELTA_X, r.top, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag all the way to the right.
mPositioner.resizeDrag(2000.0f, midY);
w = mMinVisibleWidth;
h = Math.max(Math.round((float) w * MIN_ASPECT), r.height());
assertBoundsEquals(new Rect(r.right - w, r.top, r.right, r.top + h),
mPositioner.getWindowDragBounds());
// Drag to the top.
mPositioner.resizeDrag(r.left, 0.0f);
assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the bottom.
mPositioner.resizeDrag(r.left, 1000.0f);
assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
mPositioner.getWindowDragBounds());
}
/**
* This tests that a constrained portrait window will keep the aspect and do the
* right things upon resizing when dragged from the top corner.
*/
@Test
public void testPortraitPreservedWindowResizingDragTop() {
final Rect r = new Rect(330, 100, 630, 600);
final int midX = (r.left + r.right) / 2;
mPositioner.mTask.setBounds(r, true);
mPositioner.startDrag(true /* resizing */, true /* preserveOrientation */, midX,
r.top - MOUSE_DELTA_Y);
// Drag to the left (no change).
mPositioner.resizeDrag(0.0f, r.top);
assertBoundsEquals(new Rect(r.left, r.top + MOUSE_DELTA_Y, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the right (no change).
mPositioner.resizeDrag(2000.0f, r.top);
assertBoundsEquals(new Rect(r.left , r.top + MOUSE_DELTA_Y, r.right, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the top.
mPositioner.resizeDrag(300.0f, 0.0f);
int h = r.bottom - MOUSE_DELTA_Y;
int w = Math.min(r.width(), Math.round(h / MIN_ASPECT));
assertBoundsEquals(new Rect(r.left, MOUSE_DELTA_Y, r.left + w, r.bottom),
mPositioner.getWindowDragBounds());
// Drag to the bottom.
mPositioner.resizeDrag(r.left, 1000.0f);
h = Math.max(mMinVisibleHeight, Math.round(mMinVisibleWidth * MIN_ASPECT));
w = Math.round(h / MIN_ASPECT);
assertBoundsEquals(new Rect(r.left, r.bottom - h, r.left + w, r.bottom),
mPositioner.getWindowDragBounds());
}
private static void assertBoundsEquals(Rect expected, Rect actual) {
if (DEBUGGING) {
if (!expected.equals(actual)) {
Log.e(TAG, "rect(" + actual.toString() + ") != isRect(" + actual.toString()
+ ") " + Log.getStackTraceString(new Throwable()));
}
}
assertEquals(expected, actual);
}
@Test
public void testFinishingMovingWhenBinderDied() {
spyOn(mWm.mTaskPositioningController);
mPositioner.startDrag(false, false, 0 /* startX */, 0 /* startY */);
verify(mWm.mTaskPositioningController, never()).finishTaskPositioning();
mPositioner.binderDied();
verify(mWm.mTaskPositioningController).finishTaskPositioning();
}
}