Fix stack and task size comparison in CTS

1. Added an option not to compare task and stack bounds.
2. Fixed bounds validation in case when task has minimal
   width and/or height set.

Bug: 27785974
Change-Id: If14978219cd9333ce68481110ac18912a417435b
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
index 3de4c0e..d11cdb4 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityAndWindowManagersState.java
@@ -29,6 +29,7 @@
 import java.awt.Rectangle;
 import java.util.Objects;
 
+import static android.server.cts.ActivityManagerTestBase.FREEFORM_WORKSPACE_STACK_ID;
 import static com.android.ddmlib.Log.LogLevel.INFO;
 
 /** Combined state of the activity manager and window manager. */
@@ -38,11 +39,21 @@
     private WindowManagerState mWmState = new WindowManagerState();
 
     void computeState(ITestDevice device, String[] waitForActivitiesVisible) throws Exception {
-        computeState(device, true, waitForActivitiesVisible);
+        computeState(device, waitForActivitiesVisible, true);
+    }
+
+    void computeState(ITestDevice device, String[] waitForActivitiesVisible,
+                      boolean compareTaskAndStackBounds) throws Exception {
+        computeState(device, true, waitForActivitiesVisible, compareTaskAndStackBounds);
     }
 
     void computeState(ITestDevice device, boolean visibleOnly, String[] waitForActivitiesVisible)
             throws Exception {
+        computeState(device, visibleOnly, waitForActivitiesVisible, true);
+    }
+
+    void computeState(ITestDevice device, boolean visibleOnly, String[] waitForActivitiesVisible,
+                      boolean compareTaskAndStackBounds) throws Exception {
         int retriesLeft = 5;
         boolean retry = waitForActivitiesVisible != null && waitForActivitiesVisible.length > 0;
         do {
@@ -62,7 +73,7 @@
         } while (retry && retriesLeft-- > 0);
 
         assertSanity();
-        assertValidBounds();
+        assertValidBounds(compareTaskAndStackBounds);
     }
 
     private boolean shouldRetry(String[] waitForActivitiesVisible) {
@@ -227,7 +238,7 @@
         return true;
     }
 
-    void assertValidBounds() {
+    void assertValidBounds(boolean compareTaskAndStackBounds) {
         for (ActivityStack aStack : mAmState.getStacks()) {
             final int stackId = aStack.mStackId;
             final WindowStack wStack = mWmState.getStack(stackId);
@@ -255,10 +266,12 @@
                 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);
+                        + ", stackId=" + stackId, aTaskIsFullscreen, wTaskIsFullscreen);
 
                 final Rectangle aTaskBounds = aTask.getBounds();
                 final Rectangle wTaskBounds = wTask.getBounds();
+                final int aTaskMinWidth = aTask.getMinimalWidth();
+                final int aTaskMinHeight = aTask.getMinimalHeight();
 
                 if (aTaskIsFullscreen) {
                     assertNull("Task bounds in AM must be null for fullscreen taskId=" + taskId,
@@ -266,6 +279,28 @@
                 } else {
                     assertEquals("Task bounds in AM and WM must be equal taskId=" + taskId
                             + ", stackId=" + stackId, aTaskBounds, wTaskBounds);
+
+                    if (compareTaskAndStackBounds && stackId != FREEFORM_WORKSPACE_STACK_ID) {
+                        if (aTaskMinWidth == -1 && aTaskMinHeight == -1) {
+                            // Minimal size not set for task - checking for equality of bounds with
+                            // stack.
+                            assertEquals("Task bounds must be equal to stack bounds taskId="
+                                    + taskId + ", stackId=" + stackId, aStackBounds, wTaskBounds);
+                        } else {
+                            // Minimal width and/or height set for task - bounds of task and stack
+                            // can be different.
+                            int targetWidth = aTaskMinWidth == -1
+                                    ? (int) aStackBounds.getWidth()
+                                    : (int) Math.max(aTaskMinWidth, aStackBounds.getWidth());
+                            int targetHeight = aTaskMinHeight == -1
+                                    ? (int) aStackBounds.getHeight()
+                                    : (int) Math.max(aTaskMinHeight, aStackBounds.getHeight());
+                            final Rectangle targetBounds = new Rectangle((int) aStackBounds.getX(),
+                                    (int) aStackBounds.getY(), targetWidth, targetHeight);
+                            assertEquals("Task bounds must be set according to minimal size taskId="
+                                    + taskId + ", stackId=" + stackId, targetBounds, wTaskBounds);
+                        }
+                    }
                 }
             }
         }
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
index 58a7ae6..258911c 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
@@ -137,7 +137,8 @@
         mDevice.executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME));
         launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
         resizeDockedStack(STACK_SIZE, STACK_SIZE, TASK_SIZE, TASK_SIZE);
-        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME});
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME},
+                false /* compareTaskAndStackBounds */);
         mAmWmState.assertContainsStack("Must contain docked stack", DOCKED_STACK_ID);
         mAmWmState.assertContainsStack("Must contain fullscreen stack",
                 FULLSCREEN_WORKSPACE_STACK_ID);
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java
index 9b3957d..cb3ed3e 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerState.java
@@ -405,6 +405,10 @@
                     continue;
                 }
 
+                if (extractMinimalSize(line)) {
+                    continue;
+                }
+
                 Matcher matcher = TASK_RECORD_PATTERN.matcher(line);
                 if (matcher.matches()) {
                     CLog.logAndDisplay(INFO, line);
@@ -515,9 +519,15 @@
         protected static final Pattern FULLSCREEN_PATTERN = Pattern.compile("mFullscreen=(\\S+)");
         protected static final Pattern BOUNDS_PATTERN =
                 Pattern.compile("mBounds=Rect\\((\\d+), (\\d+) - (\\d+), (\\d+)\\)");
+        protected static final Pattern MINIMAL_WIDTH_PATTERN =
+                Pattern.compile("mMinimalWidth=(\\d+)");
+        protected static final Pattern MINIMAL_HEIGHT_PATTERN =
+                Pattern.compile("mMinimalHeight=(\\d+)");
 
         protected boolean mFullscreen;
         protected Rectangle mBounds;
+        protected int mMinimalWidth = -1;
+        protected int mMinimalHeight = -1;
 
         boolean extractFullscreen(String line) {
             final Matcher matcher = FULLSCREEN_PATTERN.matcher(line);
@@ -552,6 +562,22 @@
             return rect;
         }
 
+        boolean extractMinimalSize(String line) {
+            final Matcher minWidthMatcher = MINIMAL_WIDTH_PATTERN.matcher(line);
+            final Matcher minHeightMatcher = MINIMAL_HEIGHT_PATTERN.matcher(line);
+
+            if (minWidthMatcher.matches()) {
+                CLog.logAndDisplay(INFO, line);
+                mMinimalWidth = Integer.valueOf(minWidthMatcher.group(1));
+            } else if (minHeightMatcher.matches()) {
+                CLog.logAndDisplay(INFO, line);
+                mMinimalHeight = Integer.valueOf(minHeightMatcher.group(1));
+            } else {
+                return false;
+            }
+            return true;
+        }
+
         Rectangle getBounds() {
             return mBounds;
         }
@@ -559,6 +585,14 @@
         boolean isFullscreen() {
             return mFullscreen;
         }
+
+        int getMinimalWidth() {
+            return mMinimalWidth;
+        }
+
+        int getMinimalHeight() {
+            return mMinimalHeight;
+        }
     }
 
     static boolean doneExtracting(LinkedList<String> dump, Pattern[] exitPatterns) {