Create unit tests and unit test utils for desktop

To simulate desktop windowing in WMCore introduce a new utility class
that can create freeform tasks. Add some Activity tests that cover same
cases as split screen.

Test: atest ActivityStarterTests
Bug: 316318069
Bug: 316316775
Change-Id: I2c7f40ebf168f1453f1542c48665152ddc01bdfe
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index c82f751..2f7e182 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -132,8 +132,10 @@
 import org.mockito.MockitoSession;
 import org.mockito.quality.Strictness;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -557,6 +559,86 @@
         return Pair.create(splitPrimaryActivity, splitSecondActivity);
     }
 
+    /**
+     * This test ensures that if the intent is being delivered to a desktop mode unfocused task
+     * while it is already on top, reports it as delivering to top.
+     */
+    @Test
+    public void testDesktopModeDeliverToTop() {
+        final ActivityStarter starter = prepareStarter(
+                FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP,
+                false /* mockGetRootTask */);
+        final List<ActivityRecord> activities = createActivitiesInDesktopMode();
+
+        // Set focus back to the first task.
+        activities.get(0).moveFocusableActivityToTop("testDesktopModeDeliverToTop");
+
+        // Start activity and delivered new intent.
+        starter.getIntent().setComponent(activities.get(3).mActivityComponent);
+        doReturn(activities.get(3)).when(mRootWindowContainer).findTask(any(), any());
+        final int result = starter.setReason("testDesktopModeDeliverToTop").execute();
+
+        // Ensure result is delivering intent to top.
+        assertEquals(START_DELIVERED_TO_TOP, result);
+    }
+
+    /**
+     * This test ensures that if the intent is being delivered to a desktop mode unfocused task
+     * reports it is brought to front instead of delivering to top.
+     */
+    @Test
+    public void testDesktopModeTaskToFront() {
+        final ActivityStarter starter = prepareStarter(
+                FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
+        final List<ActivityRecord> activities = createActivitiesInDesktopMode();
+        final ActivityRecord desktopModeFocusActivity = activities.get(0);
+        final ActivityRecord desktopModeReusableActivity = activities.get(1);
+        final ActivityRecord desktopModeTopActivity = new ActivityBuilder(mAtm).setCreateTask(true)
+                .setParentTask(desktopModeReusableActivity.getRootTask()).build();
+        assertTrue(desktopModeTopActivity.inMultiWindowMode());
+
+        // Let first stack has focus.
+        desktopModeFocusActivity.moveFocusableActivityToTop("testDesktopModeTaskToFront");
+
+        // Start activity and delivered new intent.
+        starter.getIntent().setComponent(desktopModeReusableActivity.mActivityComponent);
+        doReturn(desktopModeReusableActivity).when(mRootWindowContainer).findTask(any(), any());
+        final int result = starter.setReason("testDesktopModeMoveToFront").execute();
+
+        // Ensure result is moving task to front.
+        assertEquals(START_TASK_TO_FRONT, result);
+    }
+
+    /** Returns 4 activities. */
+    private List<ActivityRecord> createActivitiesInDesktopMode() {
+        final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm);
+        List<ActivityRecord> activityRecords = new ArrayList<>();
+
+        for (int i = 0; i < 4; i++) {
+            Rect bounds = new Rect(desktopOrganizer.getDefaultDesktopTaskBounds());
+            bounds.offset(20 * i, 20 * i);
+            desktopOrganizer.createTask(bounds);
+        }
+
+        for (int i = 0; i < 4; i++) {
+            activityRecords.add(new TaskBuilder(mSupervisor)
+                    .setParentTask(desktopOrganizer.mTasks.get(i))
+                    .setCreateActivity(true)
+                    .build()
+                    .getTopMostActivity());
+        }
+
+        for (int i = 0; i < 4; i++) {
+            activityRecords.get(i).setVisibleRequested(true);
+        }
+
+        for (int i = 0; i < 4; i++) {
+            assertEquals(desktopOrganizer.mTasks.get(i), activityRecords.get(i).getRootTask());
+        }
+
+        return activityRecords;
+    }
+
     @Test
     public void testMoveVisibleTaskToFront() {
         final ActivityRecord activity = new TaskBuilder(mSupervisor)
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 7ae5a11..b53cf5d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -20,6 +20,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -132,7 +133,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 /** Common base class for window manager unit test classes. */
 class WindowTestsBase extends SystemServiceTestsBase {
@@ -1879,6 +1882,55 @@
         }
     }
 
+    static class TestDesktopOrganizer extends WindowOrganizerTests.StubOrganizer {
+        final int mDesktopModeDefaultWidthDp = 840;
+        final int mDesktopModeDefaultHeightDp = 630;
+        final int mDesktopDensity = 284;
+
+        final ActivityTaskManagerService mService;
+        final TaskDisplayArea mDefaultTDA;
+        List<Task> mTasks;
+        final DisplayContent mDisplay;
+        Rect mStableBounds;
+
+        TestDesktopOrganizer(ActivityTaskManagerService service, DisplayContent display) {
+            mService = service;
+            mDefaultTDA = display.getDefaultTaskDisplayArea();
+            mDisplay = display;
+            mService.mTaskOrganizerController.registerTaskOrganizer(this);
+            mTasks = new ArrayList<>();
+            mStableBounds = display.getBounds();
+        }
+
+        TestDesktopOrganizer(ActivityTaskManagerService service) {
+            this(service, service.mTaskSupervisor.mRootWindowContainer.getDefaultDisplay());
+        }
+
+        public Task createTask(Rect bounds) {
+            Task task = mService.mTaskOrganizerController.createRootTask(
+                    mDisplay, WINDOWING_MODE_FREEFORM, null);
+            task.setBounds(bounds);
+            mTasks.add(task);
+            spyOn(task);
+            return task;
+        }
+
+        public Rect getDefaultDesktopTaskBounds() {
+            int width = (int) (mDesktopModeDefaultWidthDp * mDesktopDensity + 0.5f);
+            int height = (int) (mDesktopModeDefaultHeightDp * mDesktopDensity + 0.5f);
+            Rect outBounds = new Rect();
+
+            outBounds.set(0, 0, width, height);
+            // Center the task in stable bounds
+            outBounds.offset(
+                    mStableBounds.centerX() - outBounds.centerX(),
+                    mStableBounds.centerY() - outBounds.centerY()
+            );
+            return outBounds;
+        }
+
+    }
+
     static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
         return createTestWindowToken(type, dc, false /* persistOnEmpty */);
     }