blob: 9f4cf6c6d3470ca0d3ef44e857c758e7f6f10b6e [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 android.server.cts;
import static android.server.cts.ActivityManagerState.RESIZE_MODE_RESIZEABLE;
import static android.server.cts.ActivityManagerTestBase.DOCKED_STACK_ID;
import static android.server.cts.ActivityManagerTestBase.FREEFORM_WORKSPACE_STACK_ID;
import static android.server.cts.ActivityManagerTestBase.HOME_STACK_ID;
import static android.server.cts.ActivityManagerTestBase.PINNED_STACK_ID;
import static android.server.cts.ActivityManagerTestBase.componentName;
import static android.server.cts.StateLogger.log;
import android.server.cts.ActivityManagerState.ActivityStack;
import android.server.cts.ActivityManagerState.ActivityTask;
import android.server.cts.WindowManagerState.WindowStack;
import android.server.cts.WindowManagerState.WindowState;
import android.server.cts.WindowManagerState.WindowTask;
import com.android.tradefed.device.ITestDevice;
import junit.framework.Assert;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
/** Combined state of the activity manager and window manager. */
public class ActivityAndWindowManagersState extends Assert {
// Clone of android DisplayMetrics.DENSITY_DEFAULT (DENSITY_MEDIUM)
// (Needed in host-side tests to convert dp to px.)
private static final int DISPLAY_DENSITY_DEFAULT = 160;
public static final int DEFAULT_DISPLAY_ID = 0;
// Default minimal size of resizable task, used if none is set explicitly.
// Must be kept in sync with 'default_minimal_size_resizable_task' dimen from frameworks/base.
private static final int DEFAULT_RESIZABLE_TASK_SIZE_DP = 220;
// Default minimal size of a resizable PiP task, used if none is set explicitly.
// Must be kept in sync with 'default_minimal_size_pip_resizable_task' dimen from
// frameworks/base.
private static final int DEFAULT_PIP_RESIZABLE_TASK_SIZE_DP = 108;
private ActivityManagerState mAmState = new ActivityManagerState();
private WindowManagerState mWmState = new WindowManagerState();
private final List<WindowManagerState.WindowState> mTempWindowList = new ArrayList<>();
private boolean mUseActivityNames = true;
/**
* Compute AM and WM state of device, check sanity and bounds.
* WM state will include only visible windows, stack and task bounds will be compared.
*
* @param device test device.
* @param waitForActivitiesVisible array of activity names to wait for.
*/
public void computeState(ITestDevice device, String[] waitForActivitiesVisible)
throws Exception {
computeState(device, waitForActivitiesVisible, true);
}
/**
* Compute AM and WM state of device, check sanity and bounds.
*
* @param device test device.
* @param waitForActivitiesVisible array of activity names to wait for.
* @param compareTaskAndStackBounds pass 'true' if stack and task bounds should be compared,
* 'false' otherwise.
*/
void computeState(ITestDevice device, String[] waitForActivitiesVisible,
boolean compareTaskAndStackBounds) throws Exception {
waitForValidState(device, waitForActivitiesVisible, null /* stackIds */,
compareTaskAndStackBounds);
assertSanity();
assertValidBounds(compareTaskAndStackBounds);
}
/**
* By default computeState allows you to pass only the activity name it and
* it will generate the full window name for the main activity window. In the
* case of secondary application windows though this isn't helpful, as they
* may follow a different format, so this method lets you disable that behavior,
* prior to calling a computeState variant
*/
void setUseActivityNamesForWindowNames(boolean useActivityNames) {
mUseActivityNames = useActivityNames;
}
/**
* Compute AM and WM state of device, wait for the activity records to be added, and
* wait for debugger window to show up.
*
* This should only be used when starting with -D (debugger) option, where we pop up the
* waiting-for-debugger window, but real activity window won't show up since we're waiting
* for debugger.
*/
void waitForDebuggerWindowVisible(
ITestDevice device, String[] waitForActivityRecords) throws Exception {
int retriesLeft = 5;
do {
mAmState.computeState(device);
mWmState.computeState(device);
if (shouldWaitForDebuggerWindow() ||
shouldWaitForActivityRecords(waitForActivityRecords)) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log(e.toString());
// Well I guess we are not waiting...
}
} else {
break;
}
} while (retriesLeft-- > 0);
}
/**
* Wait for the activity to appear and for valid state in AM and WM.
*
* @param device test device.
* @param waitForActivityVisible name of activity to wait for.
*/
void waitForValidState(ITestDevice device, String waitForActivityVisible)
throws Exception {
waitForValidState(device, new String[]{waitForActivityVisible}, null /* stackIds */,
false /* compareTaskAndStackBounds */);
}
/**
* Wait for the activity to appear in proper stack and for valid state in AM and WM.
*
* @param device test device.
* @param waitForActivityVisible name of activity to wait for.
* @param stackId id of the stack where provided activity should be found.
*/
void waitForValidState(ITestDevice device, String waitForActivityVisible, int stackId)
throws Exception {
waitForValidState(device, new String[]{waitForActivityVisible}, new int[]{stackId},
false /* compareTaskAndStackBounds */);
}
/**
* Wait for the activities to appear in proper stacks and for valid state in AM and WM.
*
* @param device test device.
* @param waitForActivitiesVisible array of activity names to wait for.
* @param stackIds ids of stack where provided activities should be found.
* Pass null to skip this check.
* @param compareTaskAndStackBounds flag indicating if we should compare task and stack bounds
* for equality.
*/
void waitForValidState(ITestDevice device, String[] waitForActivitiesVisible, int[] stackIds,
boolean compareTaskAndStackBounds) throws Exception {
waitForValidState(device, waitForActivitiesVisible, stackIds, compareTaskAndStackBounds,
componentName);
}
/**
* Wait for the activities to appear in proper stacks and for valid state in AM and WM.
*
* @param device test device.
* @param waitForActivitiesVisible array of activity names to wait for.
* @param stackIds ids of stack where provided activities should be found.
* Pass null to skip this check.
* @param compareTaskAndStackBounds flag indicating if we should compare task and stack bounds
* for equality.
* @param packageName name of the package of activities that we're waiting for.
*/
void waitForValidState(ITestDevice device, String[] waitForActivitiesVisible, int[] stackIds,
boolean compareTaskAndStackBounds, String packageName) throws Exception {
int retriesLeft = 5;
do {
// TODO: Get state of AM and WM at the same time to avoid mismatches caused by
// requesting dump in some intermediate state.
mAmState.computeState(device);
mWmState.computeState(device);
if (shouldWaitForValidStacks(compareTaskAndStackBounds)
|| shouldWaitForActivities(waitForActivitiesVisible, stackIds, packageName)
|| shouldWaitForWindows()) {
log("***Waiting for valid stacks and activities states...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log(e.toString());
// Well I guess we are not waiting...
}
} else {
break;
}
} while (retriesLeft-- > 0);
}
void waitForHomeActivityVisible(ITestDevice device) throws Exception {
waitForWithAmState(device, ActivityManagerState::isHomeActivityVisible,
"***Waiting for home activity to be visible...");
}
void waitForKeyguardShowingAndNotOccluded(ITestDevice device) throws Exception {
waitForWithAmState(device, state -> state.getKeyguardControllerState().keyguardShowing
&& !state.getKeyguardControllerState().keyguardOccluded,
"***Waiting for Keyguard showing...");
}
void waitForKeyguardShowingAndOccluded(ITestDevice device) throws Exception {
waitForWithAmState(device, state -> state.getKeyguardControllerState().keyguardShowing
&& state.getKeyguardControllerState().keyguardOccluded,
"***Waiting for Keyguard showing and occluded...");
}
void waitForKeyguardGone(ITestDevice device) throws Exception {
waitForWithAmState(device, state -> !state.getKeyguardControllerState().keyguardShowing,
"***Waiting for Keyguard gone...");
}
void waitForRotation(ITestDevice device, int rotation) throws Exception {
waitForWithWmState(device, state -> state.getRotation() == rotation,
"***Waiting for Rotation: " + rotation);
}
void waitForDisplayUnfrozen(ITestDevice device) throws Exception {
waitForWithWmState(device, state -> !state.isDisplayFrozen(),
"***Waiting for Display unfrozen");
}
void waitForActivityState(ITestDevice device, String activityName, String activityState)
throws Exception {
waitForWithAmState(device, state -> state.hasActivityState(activityName, activityState),
"***Waiting for Activity State: " + activityState);
}
void waitForFocusedStack(ITestDevice device, int stackId) throws Exception {
waitForWithAmState(device, state -> state.getFocusedStackId() == stackId,
"***Waiting for focused stack...");
}
void waitForAppTransitionIdle(ITestDevice device) throws Exception {
waitForWithWmState(device,
state -> WindowManagerState.APP_STATE_IDLE.equals(state.getAppTransitionState()),
"***Waiting for app transition idle...");
}
void waitForWithAmState(ITestDevice device, Predicate<ActivityManagerState> waitCondition,
String message) throws Exception{
waitFor(device, (amState, wmState) -> waitCondition.test(amState), message);
}
void waitForWithWmState(ITestDevice device, Predicate<WindowManagerState> waitCondition,
String message) throws Exception{
waitFor(device, (amState, wmState) -> waitCondition.test(wmState), message);
}
void waitFor(ITestDevice device,
BiPredicate<ActivityManagerState, WindowManagerState> waitCondition, String message)
throws Exception {
int retriesLeft = 5;
do {
mAmState.computeState(device);
mWmState.computeState(device);
if (!waitCondition.test(mAmState, mWmState)) {
log(message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log(e.toString());
// Well I guess we are not waiting...
}
} else {
break;
}
} while (retriesLeft-- > 0);
}
/** @return true if should wait for valid stacks state. */
private boolean shouldWaitForValidStacks(boolean compareTaskAndStackBounds) {
if (!taskListsInAmAndWmAreEqual()) {
// We want to wait for equal task lists in AM and WM in case we caught them in the
// middle of some state change operations.
log("***taskListsInAmAndWmAreEqual=false");
return true;
}
if (!stackBoundsInAMAndWMAreEqual()) {
// We want to wait a little for the stacks in AM and WM to have equal bounds as there
// might be a transition animation ongoing when we got the states from WM AM separately.
log("***stackBoundsInAMAndWMAreEqual=false");
return true;
}
try {
// Temporary fix to avoid catching intermediate state with different task bounds in AM
// and WM.
assertValidBounds(compareTaskAndStackBounds);
} catch (AssertionError e) {
log("***taskBoundsInAMAndWMAreEqual=false : " + e.getMessage());
return true;
}
final int stackCount = mAmState.getStackCount();
if (stackCount == 0) {
log("***stackCount=" + stackCount);
return true;
}
final int resumedActivitiesCount = mAmState.getResumedActivitiesCount();
if (!mAmState.getKeyguardControllerState().keyguardShowing && resumedActivitiesCount != 1) {
log("***resumedActivitiesCount=" + resumedActivitiesCount);
return true;
}
if (mAmState.getFocusedActivity() == null) {
log("***focusedActivity=null");
return true;
}
return false;
}
/** @return true if should wait for some activities to become visible. */
private boolean shouldWaitForActivities(String[] waitForActivitiesVisible, int[] stackIds,
String packageName) {
if (waitForActivitiesVisible == null || waitForActivitiesVisible.length == 0) {
return false;
}
// If the caller is interested in us waiting for some particular activity windows to be
// visible before compute the state. Check for the visibility of those activity windows
// and for placing them in correct stacks (if requested).
boolean allActivityWindowsVisible = true;
boolean tasksInCorrectStacks = true;
List<WindowManagerState.WindowState> matchingWindowStates = new ArrayList<>();
for (int i = 0; i < waitForActivitiesVisible.length; i++) {
// Check if window is visible - it should be represented as one of the window states.
final String windowName = mUseActivityNames ?
ActivityManagerTestBase.getWindowName(packageName, waitForActivitiesVisible[i])
: waitForActivitiesVisible[i];
final String activityComponentName =
ActivityManagerTestBase.getActivityComponentName(packageName,
waitForActivitiesVisible[i]);
mWmState.getMatchingVisibleWindowState(windowName, matchingWindowStates);
boolean activityWindowVisible = !matchingWindowStates.isEmpty();
if (!activityWindowVisible) {
log("Activity window not visible: " + windowName);
allActivityWindowsVisible = false;
} else if (!mAmState.isActivityVisible(activityComponentName)) {
log("Activity not visible: " + activityComponentName);
allActivityWindowsVisible = false;
} else if (stackIds != null) {
// Check if window is already in stack requested by test.
boolean windowInCorrectStack = false;
for (WindowManagerState.WindowState ws : matchingWindowStates) {
if (ws.getStackId() == stackIds[i]) {
windowInCorrectStack = true;
break;
}
}
if (!windowInCorrectStack) {
log("Window in incorrect stack: " + waitForActivitiesVisible[i]);
tasksInCorrectStacks = false;
}
}
}
return !allActivityWindowsVisible || !tasksInCorrectStacks;
}
/** @return true if should wait valid windows state. */
private boolean shouldWaitForWindows() {
if (mWmState.getFrontWindow() == null) {
log("***frontWindow=null");
return true;
}
if (mWmState.getFocusedWindow() == null) {
log("***focusedWindow=null");
return true;
}
if (mWmState.getFocusedApp() == null) {
log("***focusedApp=null");
return true;
}
return false;
}
private boolean shouldWaitForDebuggerWindow() {
List<WindowManagerState.WindowState> matchingWindowStates = new ArrayList<>();
mWmState.getMatchingVisibleWindowState("android.server.cts", matchingWindowStates);
for (WindowState ws : matchingWindowStates) {
if (ws.isDebuggerWindow()) {
return false;
}
}
log("Debugger window not available yet");
return true;
}
private boolean shouldWaitForActivityRecords(String[] waitForActivityRecords) {
if (waitForActivityRecords == null || waitForActivityRecords.length == 0) {
return false;
}
// Check if the activity records we're looking for is already added.
for (int i = 0; i < waitForActivityRecords.length; i++) {
if (!mAmState.isActivityVisible(waitForActivityRecords[i])) {
log("ActivityRecord " + waitForActivityRecords[i] + " not visible yet");
return true;
}
}
return false;
}
ActivityManagerState getAmState() {
return mAmState;
}
public WindowManagerState getWmState() {
return mWmState;
}
void assertSanity() throws Exception {
assertTrue("Must have stacks", mAmState.getStackCount() > 0);
if (!mAmState.getKeyguardControllerState().keyguardShowing) {
assertEquals("There should be one and only one resumed activity in the system.",
1, mAmState.getResumedActivitiesCount());
}
assertNotNull("Must have focus activity.", mAmState.getFocusedActivity());
for (ActivityStack aStack : mAmState.getStacks()) {
final int stackId = aStack.mStackId;
for (ActivityTask aTask : aStack.getTasks()) {
assertEquals("Stack can only contain its own tasks", stackId, aTask.mStackId);
}
}
assertNotNull("Must have front window.", mWmState.getFrontWindow());
assertNotNull("Must have focused window.", mWmState.getFocusedWindow());
assertNotNull("Must have app.", mWmState.getFocusedApp());
}
void assertContainsStack(String msg, int stackId) throws Exception {
assertTrue(msg, mAmState.containsStack(stackId));
assertTrue(msg, mWmState.containsStack(stackId));
}
void assertDoesNotContainStack(String msg, int stackId) throws Exception {
assertFalse(msg, mAmState.containsStack(stackId));
assertFalse(msg, mWmState.containsStack(stackId));
}
void assertFrontStack(String msg, int stackId) throws Exception {
assertEquals(msg, stackId, mAmState.getFrontStackId(DEFAULT_DISPLAY_ID));
assertEquals(msg, stackId, mWmState.getFrontStackId(DEFAULT_DISPLAY_ID));
}
void assertFocusedStack(String msg, int stackId) throws Exception {
assertEquals(msg, stackId, mAmState.getFocusedStackId());
}
void assertNotFocusedStack(String msg, int stackId) throws Exception {
if (stackId == mAmState.getFocusedStackId()) {
failNotEquals(msg, stackId, mAmState.getFocusedStackId());
}
}
void assertFocusedActivity(String msg, String activityName) throws Exception {
assertFocusedActivity(msg, componentName, activityName);
}
void assertFocusedActivity(String msg, String packageName, String activityName)
throws Exception {
final String componentName = ActivityManagerTestBase.getActivityComponentName(packageName,
activityName);
assertEquals(msg, componentName, mAmState.getFocusedActivity());
assertEquals(msg, componentName, mWmState.getFocusedApp());
}
void assertNotFocusedActivity(String msg, String activityName) throws Exception {
final String componentName = ActivityManagerTestBase.getActivityComponentName(activityName);
if (mAmState.getFocusedActivity().equals(componentName)) {
failNotEquals(msg, mAmState.getFocusedActivity(), componentName);
}
if (mWmState.getFocusedApp().equals(componentName)) {
failNotEquals(msg, mWmState.getFocusedApp(), componentName);
}
}
void assertResumedActivity(String msg, String activityName) throws Exception {
final String componentName = ActivityManagerTestBase.getActivityComponentName(activityName);
assertEquals(msg, componentName, mAmState.getResumedActivity());
}
void assertNotResumedActivity(String msg, String activityName) throws Exception {
final String componentName = ActivityManagerTestBase.getActivityComponentName(activityName);
if (mAmState.getResumedActivity().equals(componentName)) {
failNotEquals(msg, mAmState.getResumedActivity(), componentName);
}
}
void assertFocusedWindow(String msg, String windowName) {
assertEquals(msg, windowName, mWmState.getFocusedWindow());
}
void assertNotFocusedWindow(String msg, String windowName) {
if (mWmState.getFocusedWindow().equals(windowName)) {
failNotEquals(msg, mWmState.getFocusedWindow(), windowName);
}
}
void assertFrontWindow(String msg, String windowName) {
assertEquals(msg, windowName, mWmState.getFrontWindow());
}
void assertVisibility(String activityName, boolean visible) {
final String activityComponentName =
ActivityManagerTestBase.getActivityComponentName(activityName);
final String windowName =
ActivityManagerTestBase.getWindowName(activityName);
assertVisibility(activityComponentName, windowName, visible);
}
private void assertVisibility(String activityComponentName, String windowName,
boolean visible) {
final boolean activityVisible = mAmState.isActivityVisible(activityComponentName);
final boolean windowVisible = mWmState.isWindowVisible(windowName);
if (visible) {
assertTrue("Activity=" + activityComponentName + " must be visible.", activityVisible);
assertTrue("Window=" + windowName + " must be visible.", windowVisible);
} else {
assertFalse("Activity=" + activityComponentName + " must NOT be visible.",
activityVisible);
assertFalse("Window=" + windowName + " must NOT be visible.", windowVisible);
}
}
void assertHomeActivityVisible(boolean visible) {
String name = mAmState.getHomeActivityName();
assertNotNull(name);
assertVisibility(name, getWindowNameForActivityName(name), visible);
}
private String getWindowNameForActivityName(String activityName) {
return activityName.replaceAll("(.*)\\/\\.", "$1/$1.");
}
boolean taskListsInAmAndWmAreEqual() {
for (ActivityStack aStack : mAmState.getStacks()) {
final int stackId = aStack.mStackId;
final WindowStack wStack = mWmState.getStack(stackId);
if (wStack == null) {
log("Waiting for stack setup in WM, stackId=" + stackId);
return false;
}
for (ActivityTask aTask : aStack.getTasks()) {
if (wStack.getTask(aTask.mTaskId) == null) {
log("Task is in AM but not in WM, waiting for it to settle, taskId="
+ aTask.mTaskId);
return false;
}
}
for (WindowTask wTask : wStack.mTasks) {
if (aStack.getTask(wTask.mTaskId) == null) {
log("Task is in WM but not in AM, waiting for it to settle, taskId="
+ wTask.mTaskId);
return false;
}
}
}
return true;
}
int getStackPosition(int stackId) {
int wmStackIndex = mWmState.getStackPosition(stackId);
int amStackIndex = mAmState.getStackPosition(stackId);
assertEquals("Window and activity manager must have the same stack position index",
amStackIndex, wmStackIndex);
return wmStackIndex;
}
boolean stackBoundsInAMAndWMAreEqual() {
for (ActivityStack aStack : mAmState.getStacks()) {
final int stackId = aStack.mStackId;
final WindowStack wStack = mWmState.getStack(stackId);
if (aStack.isFullscreen() != wStack.isFullscreen()) {
log("Waiting for correct fullscreen state, stackId=" + stackId);
return false;
}
final Rectangle aStackBounds = aStack.getBounds();
final Rectangle wStackBounds = wStack.getBounds();
if (aStack.isFullscreen()) {
if (aStackBounds != null) {
log("Waiting for correct stack state in AM, stackId=" + stackId);
return false;
}
} else if (!Objects.equals(aStackBounds, wStackBounds)) {
// If stack is not fullscreen - comparing bounds. Not doing it always because
// for fullscreen stack bounds in WM can be either null or equal to display size.
log("Waiting for stack bound equality in AM and WM, stackId=" + stackId);
return false;
}
}
return true;
}
/** Check task bounds when docked to top/left. */
void assertDockedTaskBounds(int taskWidth, int taskHeight, String activityName) {
// Task size can be affected by default minimal size.
int defaultMinimalTaskSize = defaultMinimalTaskSize(
mAmState.getStackById(ActivityManagerTestBase.DOCKED_STACK_ID).mDisplayId);
int targetWidth = Math.max(taskWidth, defaultMinimalTaskSize);
int targetHeight = Math.max(taskHeight, defaultMinimalTaskSize);
assertEquals(new Rectangle(0, 0, targetWidth, targetHeight),
mAmState.getTaskByActivityName(activityName).getBounds());
}
void assertValidBounds(boolean compareTaskAndStackBounds) {
// Cycle through the stacks and tasks to figure out if the home stack is resizable
final ActivityTask homeTask = mAmState.getHomeTask();
final boolean homeStackIsResizable = homeTask != null
&& homeTask.getResizeMode().equals(RESIZE_MODE_RESIZEABLE);
for (ActivityStack aStack : mAmState.getStacks()) {
final int stackId = aStack.mStackId;
final WindowStack wStack = mWmState.getStack(stackId);
assertNotNull("stackId=" + stackId + " in AM but not in WM?", wStack);
assertEquals("Stack fullscreen state in AM and WM must be equal stackId=" + stackId,
aStack.isFullscreen(), wStack.isFullscreen());
final Rectangle aStackBounds = aStack.getBounds();
final Rectangle wStackBounds = wStack.getBounds();
if (aStack.isFullscreen()) {
assertNull("Stack bounds in AM must be null stackId=" + stackId, aStackBounds);
} else {
assertEquals("Stack bounds in AM and WM must be equal stackId=" + stackId,
aStackBounds, wStackBounds);
}
for (ActivityTask aTask : aStack.getTasks()) {
final int taskId = aTask.mTaskId;
final WindowTask wTask = wStack.getTask(taskId);
assertNotNull(
"taskId=" + taskId + " in AM but not in WM? stackId=" + stackId, wTask);
final boolean aTaskIsFullscreen = aTask.isFullscreen();
final boolean wTaskIsFullscreen = wTask.isFullscreen();
assertEquals("Task fullscreen state in AM and WM must be equal taskId=" + taskId
+ ", stackId=" + stackId, aTaskIsFullscreen, wTaskIsFullscreen);
final Rectangle aTaskBounds = aTask.getBounds();
final Rectangle wTaskBounds = wTask.getBounds();
final Rectangle displayRect = mWmState.getDisplay(aStack.mDisplayId)
.getDisplayRect();
if (aTaskIsFullscreen) {
assertNull("Task bounds in AM must be null for fullscreen taskId=" + taskId,
aTaskBounds);
} else if (!homeStackIsResizable && mWmState.isDockedStackMinimized()
&& displayRect.getWidth() > displayRect.getHeight()) {
// When minimized using non-resizable launcher in landscape mode, it will move
// the task offscreen in the negative x direction unlike portrait that crops.
// The x value in the task bounds will not match the stack bounds since the
// only the task was moved.
assertEquals("Task bounds in AM and WM must match width taskId=" + taskId
+ ", stackId" + stackId, aTaskBounds.getWidth(),
wTaskBounds.getWidth());
assertEquals("Task bounds in AM and WM must match height taskId=" + taskId
+ ", stackId" + stackId, aTaskBounds.getHeight(),
wTaskBounds.getHeight());
assertEquals("Task bounds must match stack bounds y taskId=" + taskId
+ ", stackId" + stackId, aTaskBounds.getY(),
wTaskBounds.getY());
assertEquals("Task and stack bounds must match width taskId=" + taskId
+ ", stackId" + stackId, aStackBounds.getWidth(),
wTaskBounds.getWidth());
assertEquals("Task and stack bounds must match height taskId=" + taskId
+ ", stackId" + stackId, aStackBounds.getHeight(),
wTaskBounds.getHeight());
assertEquals("Task and stack bounds must match y taskId=" + taskId
+ ", stackId" + stackId, aStackBounds.getY(),
wTaskBounds.getY());
} else {
assertEquals("Task bounds in AM and WM must be equal taskId=" + taskId
+ ", stackId=" + stackId, aTaskBounds, wTaskBounds);
if (compareTaskAndStackBounds && stackId != FREEFORM_WORKSPACE_STACK_ID) {
int aTaskMinWidth = aTask.getMinWidth();
int aTaskMinHeight = aTask.getMinHeight();
if (aTaskMinWidth == -1 || aTaskMinHeight == -1) {
// Minimal dimension(s) not set for task - it should be using defaults.
int defaultMinimalSize = (stackId == PINNED_STACK_ID)
? defaultMinimalPinnedTaskSize(aStack.mDisplayId)
: defaultMinimalTaskSize(aStack.mDisplayId);
if (aTaskMinWidth == -1) {
aTaskMinWidth = defaultMinimalSize;
}
if (aTaskMinHeight == -1) {
aTaskMinHeight = defaultMinimalSize;
}
}
if (aStackBounds.getWidth() >= aTaskMinWidth
&& aStackBounds.getHeight() >= aTaskMinHeight
|| stackId == PINNED_STACK_ID) {
// Bounds are not smaller then minimal possible, so stack and task
// bounds must be equal.
assertEquals("Task bounds must be equal to stack bounds taskId="
+ taskId + ", stackId=" + stackId, aStackBounds, wTaskBounds);
} else if (stackId == DOCKED_STACK_ID && homeStackIsResizable
&& mWmState.isDockedStackMinimized()) {
// Portrait if the display height is larger than the width
if (displayRect.getHeight() > displayRect.getWidth()) {
assertEquals("Task width must be equal to stack width taskId="
+ taskId + ", stackId=" + stackId,
aStackBounds.getWidth(), wTaskBounds.getWidth());
assertTrue("Task height must be greater than stack height "
+ "taskId=" + taskId + ", stackId=" + stackId,
aStackBounds.getHeight() < wTaskBounds.getHeight());
assertEquals("Task and stack x position must be equal taskId="
+ taskId + ", stackId=" + stackId,
wTaskBounds.getX(), wStackBounds.getX());
} else {
assertTrue("Task width must be greater than stack width taskId="
+ taskId + ", stackId=" + stackId,
aStackBounds.getWidth() < wTaskBounds.getWidth());
assertEquals("Task height must be equal to stack height taskId="
+ taskId + ", stackId=" + stackId,
aStackBounds.getHeight(), wTaskBounds.getHeight());
assertEquals("Task and stack y position must be equal taskId="
+ taskId + ", stackId=" + stackId, wTaskBounds.getY(),
wStackBounds.getY());
}
} else {
// Minimal dimensions affect task size, so bounds of task and stack must
// be different - will compare dimensions instead.
int targetWidth = (int) Math.max(aTaskMinWidth,
aStackBounds.getWidth());
assertEquals("Task width must be set according to minimal width"
+ " taskId=" + taskId + ", stackId=" + stackId,
targetWidth, (int) wTaskBounds.getWidth());
int targetHeight = (int) Math.max(aTaskMinHeight,
aStackBounds.getHeight());
assertEquals("Task height must be set according to minimal height"
+ " taskId=" + taskId + ", stackId=" + stackId,
targetHeight, (int) wTaskBounds.getHeight());
}
}
}
}
}
}
static int dpToPx(float dp, int densityDpi){
return (int) (dp * densityDpi / DISPLAY_DENSITY_DEFAULT + 0.5f);
}
private int defaultMinimalTaskSize(int displayId) {
return dpToPx(DEFAULT_RESIZABLE_TASK_SIZE_DP, mWmState.getDisplay(displayId).getDpi());
}
private int defaultMinimalPinnedTaskSize(int displayId) {
return dpToPx(DEFAULT_PIP_RESIZABLE_TASK_SIZE_DP, mWmState.getDisplay(displayId).getDpi());
}
}