blob: 3d323f0eb783af0a555e6e96b30638d73aeb1442 [file] [log] [blame]
/*
* Copyright (C) 2017 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.am;
import android.content.pm.ActivityInfo.WindowLayout;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.Gravity;
import org.junit.runner.RunWith;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.doAnswer;
import static org.junit.Assert.assertEquals;
/**
* Tests for exercising resizing task bounds.
*
* Build/Install/Run:
* atest FrameworksServicesTests:TaskLaunchParamsModifierTests
*/
@MediumTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
private final static int STACK_WIDTH = 100;
private final static int STACK_HEIGHT = 200;
private final static Rect STACK_BOUNDS = new Rect(0, 0, STACK_WIDTH, STACK_HEIGHT);
private ActivityManagerService mService;
private ActivityStack mStack;
private TaskRecord mTask;
private TaskLaunchParamsModifier mPositioner;
private LaunchParamsController.LaunchParams mCurrent;
private LaunchParamsController.LaunchParams mResult;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
mService = createActivityManagerService();
mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
mStack.requestResize(STACK_BOUNDS);
// We must create the task after resizing to make sure it does not inherit the stack
// dimensions on resize.
mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
mPositioner = new TaskLaunchParamsModifier();
mResult = new LaunchParamsController.LaunchParams();
mCurrent = new LaunchParamsController.LaunchParams();
}
/**
* Ensures that the setup bounds are set as expected with the stack bounds set and the task
* bounds still {@code null}.
* @throws Exception
*/
@Test
public void testInitialBounds() throws Exception {
assertEquals(mStack.getOverrideBounds(), STACK_BOUNDS);
assertEquals(mTask.getOverrideBounds(), new Rect());
}
/**
* Ensures that a task positioned with no {@link WindowLayout} receives the default launch
* position.
* @throws Exception
*/
@Test
public void testLaunchNoWindowLayout() throws Exception {
assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask, null /*layout*/,
null /*record*/, null /*source*/, null /*options*/, mCurrent, mResult));
assertEquals(getDefaultBounds(Gravity.NO_GRAVITY), mResult.mBounds);
}
/**
* Ensures that a task positioned with an empty {@link WindowLayout} receives the default launch
* position.
* @throws Exception
*/
@Test
public void testlaunchEmptyWindowLayout() throws Exception {
assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
new WindowLayout(0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0), null /*activity*/,
null /*source*/, null /*options*/, mCurrent, mResult));
assertEquals(mResult.mBounds, getDefaultBounds(Gravity.NO_GRAVITY));
}
/**
* Ensures that a task positioned with a {@link WindowLayout} gravity specified is positioned
* according to specification.
* @throws Exception
*/
@Test
public void testlaunchWindowLayoutGravity() throws Exception {
// Unspecified gravity should be ignored
testGravity(Gravity.NO_GRAVITY);
// Unsupported gravity should be ignored
testGravity(Gravity.LEFT);
testGravity(Gravity.RIGHT);
// Test defaults for vertical gravities
testGravity(Gravity.TOP);
testGravity(Gravity.BOTTOM);
// Test corners
testGravity(Gravity.TOP | Gravity.LEFT);
testGravity(Gravity.TOP | Gravity.RIGHT);
testGravity(Gravity.BOTTOM | Gravity.LEFT);
testGravity(Gravity.BOTTOM | Gravity.RIGHT);
}
private void testGravity(int gravity) {
try {
assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
new WindowLayout(0, 0, 0, 0, gravity, 0, 0), null /*activity*/,
null /*source*/, null /*options*/, mCurrent, mResult));
assertEquals(mResult.mBounds, getDefaultBounds(gravity));
} finally {
mCurrent.reset();
mResult.reset();
}
}
/**
* Ensures that a task which causes a conflict with another task when positioned is adjusted as
* expected.
* @throws Exception
*/
@Test
public void testLaunchWindowCenterConflict() throws Exception {
testConflict(Gravity.NO_GRAVITY);
testConflict(Gravity.TOP);
testConflict(Gravity.BOTTOM);
testConflict(Gravity.TOP | Gravity.LEFT);
testConflict(Gravity.TOP | Gravity.RIGHT);
testConflict(Gravity.BOTTOM | Gravity.LEFT);
testConflict(Gravity.BOTTOM | Gravity.RIGHT);
}
private void testConflict(int gravity) {
final WindowLayout layout = new WindowLayout(0, 0, 0, 0, gravity, 0, 0);
// layout first task
mService.mStackSupervisor.getLaunchParamsController().layoutTask(mTask, layout);
// Second task will be laid out on top of the first so starting bounds is the same.
final Rect expectedBounds = new Rect(mTask.getOverrideBounds());
ActivityRecord activity = null;
TaskRecord secondTask = null;
// wrap with try/finally to ensure cleanup of activity/stack.
try {
// empty tasks are ignored in conflicts
activity = new ActivityBuilder(mService).setTask(mTask).build();
// Create secondary task
secondTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
// layout second task
assertEquals(RESULT_CONTINUE,
mPositioner.onCalculate(secondTask, layout, null /*activity*/,
null /*source*/, null /*options*/, mCurrent, mResult));
if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)
|| (gravity & (Gravity.BOTTOM | Gravity.RIGHT))
== (Gravity.BOTTOM | Gravity.RIGHT)) {
expectedBounds.offset(-TaskLaunchParamsModifier.getHorizontalStep(
mStack.getOverrideBounds()), 0);
} else if ((gravity & Gravity.TOP) == Gravity.TOP
|| (gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
expectedBounds.offset(
TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()), 0);
} else {
expectedBounds.offset(
TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()),
TaskLaunchParamsModifier.getVerticalStep(mStack.getOverrideBounds()));
}
assertEquals(mResult.mBounds, expectedBounds);
} finally {
// Remove task and activity to prevent influencing future tests
if (activity != null) {
mTask.removeActivity(activity);
}
if (secondTask != null) {
mStack.removeTask(secondTask, "cleanup", ActivityStack.REMOVE_TASK_MODE_DESTROYING);
}
}
}
private Rect getDefaultBounds(int gravity) {
final Rect bounds = new Rect();
bounds.set(mStack.getOverrideBounds());
final int verticalInset =
TaskLaunchParamsModifier.getFreeformStartTop(mStack.getOverrideBounds());
final int horizontalInset =
TaskLaunchParamsModifier.getFreeformStartLeft(mStack.getOverrideBounds());
bounds.inset(horizontalInset, verticalInset);
if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)) {
bounds.offsetTo(horizontalInset * 2, 0);
} else if ((gravity & Gravity.TOP) == Gravity.TOP) {
bounds.offsetTo(0, 0);
} else if ((gravity & (Gravity.BOTTOM | Gravity.RIGHT))
== (Gravity.BOTTOM | Gravity.RIGHT)) {
bounds.offsetTo(horizontalInset * 2, verticalInset * 2);
} else if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
bounds.offsetTo(0, verticalInset * 2);
}
return bounds;
}
}