Merge "Adding support to add icons in the workspace for tests" into tm-qpr-dev
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java b/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
index 3ca05bc..a32ce3c 100644
--- a/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
+++ b/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
@@ -30,39 +30,117 @@
 
 public class CellLayoutBoard {
 
+    public static class CellType {
+        // The cells marked by this will be filled by 1x1 widgets and will be ignored when
+        // validating
+        public static final char IGNORE = 'x';
+        // The cells marked by this will be filled by app icons
+        public static final char ICON = 'i';
+        // Empty space
+        public static final char EMPTY = '-';
+        // Widget that will be saved as "main widget" for easier retrieval
+        public static final char MAIN_WIDGET = 'm';
+        // Everything else will be consider a widget
+    }
+
+    public static class WidgetRect {
+        public char mType;
+        public Rect mBounds;
+
+        WidgetRect(char type, Rect bounds) {
+            this.mType = type;
+            this.mBounds = bounds;
+        }
+
+        int getSpanX() {
+            return mBounds.right - mBounds.left + 1;
+        }
+
+        int getSpanY() {
+            return mBounds.top - mBounds.bottom + 1;
+        }
+
+        int getCellX() {
+            return mBounds.left;
+        }
+
+        int getCellY() {
+            return mBounds.bottom;
+        }
+
+        boolean shouldIgnore() {
+            return this.mType == CellType.IGNORE;
+        }
+
+        @Override
+        public String toString() {
+            return "WidgetRect type = " + mType + " bounds = " + mBounds.toString();
+        }
+    }
+
+    public static class IconPoint {
+        public Point coord;
+        public char mType;
+
+        public IconPoint(Point coord, char type) {
+            this.coord = coord;
+            mType = type;
+        }
+
+        public char getType() {
+            return mType;
+        }
+
+        public void setType(char type) {
+            mType = type;
+        }
+
+        public Point getCoord() {
+            return coord;
+        }
+
+        public void setCoord(Point coord) {
+            this.coord = coord;
+        }
+    }
+
     static final int INFINITE = 99999;
 
-    char[][] mBoard = new char[30][30];
+    char[][] mWidget = new char[30][30];
 
-    List<TestBoardWidget> mWidgetsRects = new ArrayList<>();
-    Map<Character, TestBoardWidget> mWidgetsMap = new HashMap<>();
+    List<WidgetRect> mWidgetsRects = new ArrayList<>();
+    Map<Character, WidgetRect> mWidgetsMap = new HashMap<>();
 
-    List<TestBoardAppIcon> mIconPoints = new ArrayList<>();
-    Map<Character, TestBoardAppIcon> mIconsMap = new HashMap<>();
+    List<IconPoint> mIconPoints = new ArrayList<>();
+    Map<Character, IconPoint> mIconsMap = new HashMap<>();
 
     Point mMain = new Point();
 
     CellLayoutBoard() {
-        for (int x = 0; x < mBoard.length; x++) {
-            for (int y = 0; y < mBoard[0].length; y++) {
-                mBoard[x][y] = '-';
+        for (int x = 0; x < mWidget.length; x++) {
+            for (int y = 0; y < mWidget[0].length; y++) {
+                mWidget[x][y] = CellType.EMPTY;
             }
         }
     }
 
-    public List<TestBoardWidget> getWidgets() {
+    public List<WidgetRect> getWidgets() {
         return mWidgetsRects;
     }
 
+    public List<IconPoint> getIcons() {
+        return mIconPoints;
+    }
+
     public Point getMain() {
         return mMain;
     }
 
-    public TestBoardWidget getWidgetRect(char c) {
+    public WidgetRect getWidgetRect(char c) {
         return mWidgetsMap.get(c);
     }
 
-    public static TestBoardWidget getWidgetRect(int x, int y, Set<Point> used, char[][] board) {
+    public static WidgetRect getWidgetRect(int x, int y, Set<Point> used, char[][] board) {
         char type = board[x][y];
         Queue<Point> search = new ArrayDeque<Point>();
         Point current = new Point(x, y);
@@ -91,20 +169,20 @@
                 }
             }
         }
-        return new TestBoardWidget(type, widgetRect);
+        return new WidgetRect(type, widgetRect);
     }
 
     public static boolean isWidget(char type) {
-        return type != 'i' && type != '-';
+        return type != CellType.ICON && type != CellType.EMPTY;
     }
 
     public static boolean isIcon(char type) {
-        return type == 'i';
+        return type == CellType.ICON;
     }
 
-    private static List<TestBoardWidget> getRects(char[][] board) {
+    private static List<WidgetRect> getRects(char[][] board) {
         Set<Point> used = new HashSet<>();
-        List<TestBoardWidget> widgetsRects = new ArrayList<>();
+        List<WidgetRect> widgetsRects = new ArrayList<>();
         for (int x = 0; x < board.length; x++) {
             for (int y = 0; y < board[0].length; y++) {
                 if (!used.contains(new Point(x, y)) && isWidget(board[x][y])) {
@@ -115,12 +193,12 @@
         return widgetsRects;
     }
 
-    private static List<TestBoardAppIcon> getIconPoints(char[][] board) {
-        List<TestBoardAppIcon> iconPoints = new ArrayList<>();
+    private static List<IconPoint> getIconPoints(char[][] board) {
+        List<IconPoint> iconPoints = new ArrayList<>();
         for (int x = 0; x < board.length; x++) {
             for (int y = 0; y < board[0].length; y++) {
                 if (isIcon(board[x][y])) {
-                    iconPoints.add(new TestBoardAppIcon(new Point(x, y), board[x][y]));
+                    iconPoints.add(new IconPoint(new Point(x, y), board[x][y]));
                 }
             }
         }
@@ -135,18 +213,18 @@
             String line = lines[y];
             for (int x = 0; x < line.length(); x++) {
                 char c = line.charAt(x);
-                if (c == 'm') {
+                if (c == CellType.MAIN_WIDGET) {
                     board.mMain = new Point(x, y);
                 }
-                if (c != '-') {
-                    board.mBoard[x][y] = line.charAt(x);
+                if (c != CellType.EMPTY) {
+                    board.mWidget[x][y] = line.charAt(x);
                 }
             }
         }
-        board.mWidgetsRects = getRects(board.mBoard);
+        board.mWidgetsRects = getRects(board.mWidget);
         board.mWidgetsRects.forEach(
                 widgetRect -> board.mWidgetsMap.put(widgetRect.mType, widgetRect));
-        board.mIconPoints = getIconPoints(board.mBoard);
+        board.mIconPoints = getIconPoints(board.mWidget);
         return board;
     }
 }
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
index 5f5dfea..93fbf97 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
@@ -15,16 +15,13 @@
  */
 package com.android.launcher3.celllayout;
 
-import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
-
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Point;
-import android.graphics.Rect;
 import android.util.Log;
 import android.view.View;
 
-import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
@@ -34,13 +31,14 @@
 import com.android.launcher3.celllayout.testcases.PushReorderCase;
 import com.android.launcher3.celllayout.testcases.ReorderTestCase;
 import com.android.launcher3.celllayout.testcases.SimpleReorderCase;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
+import com.android.launcher3.tapl.Widget;
+import com.android.launcher3.tapl.WidgetResizeFrame;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.TaplTestsLauncher3;
-import com.android.launcher3.ui.TestViewHelpers;
 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
 import com.android.launcher3.util.rule.ShellCommandRule;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.views.DoubleShadowBubbleTextView;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
 import org.junit.Assume;
 import org.junit.Before;
@@ -60,6 +58,8 @@
 
     private static final String TAG = ReorderWidgets.class.getSimpleName();
 
+    TestWorkspaceBuilder mBoardBuilder;
+
     private View getViewAt(int cellX, int cellY) {
         return getFromLauncher(l -> l.getWorkspace().getScreenWithId(
                 l.getWorkspace().getScreenIdForPageIndex(0)).getChildAt(cellX, cellY));
@@ -76,6 +76,7 @@
 
     @Before
     public void setup() throws Throwable {
+        mBoardBuilder = new TestWorkspaceBuilder(this);
         TaplTestsLauncher3.initialize(this);
         clearHomescreen();
     }
@@ -86,78 +87,44 @@
     private boolean validateBoard(CellLayoutBoard board) {
         boolean match = true;
         Point cellDimensions = getCellDimensions();
-        for (TestBoardWidget widgetRect: board.getWidgets()) {
+        for (CellLayoutBoard.WidgetRect widgetRect: board.getWidgets()) {
             if (widgetRect.shouldIgnore()) {
                 continue;
             }
             View widget = getViewAt(widgetRect.getCellX(), widgetRect.getCellY());
+            assertTrue("The view selected at " + board + " is not a widget",
+                    widget instanceof LauncherAppWidgetHostView);
             match &= widgetRect.getSpanX()
                     == Math.round(widget.getWidth() / (float) cellDimensions.x);
             match &= widgetRect.getSpanY()
                     == Math.round(widget.getHeight() / (float) cellDimensions.y);
             if (!match) return match;
         }
+        for (CellLayoutBoard.IconPoint iconPoint : board.getIcons()) {
+            View icon = getViewAt(iconPoint.getCoord().x, iconPoint.getCoord().y);
+            assertTrue("The view selected at " + iconPoint.coord + " is not an Icon",
+                    icon instanceof DoubleShadowBubbleTextView);
+        }
         return match;
     }
 
-    /**
-     * Fills the given rect in WidgetRect with 1x1 widgets. This is useful to equalize cases.
-     */
-    private void fillWithWidgets(TestBoardWidget widgetRect) {
-        int initX = widgetRect.getCellX();
-        int initY = widgetRect.getCellY();
-        for (int x = 0; x < widgetRect.getSpanX(); x++) {
-            for (int y = 0; y < widgetRect.getSpanY(); y++) {
-                int auxX = initX + x;
-                int auxY = initY + y;
-                try {
-                    // this widgets are filling, we don't care if we can't place them
-                    addWidgetInCell(
-                            new TestBoardWidget('x',
-                                    new Rect(auxX, auxY, auxX, auxY))
-                    );
-                } catch (Exception e) {
-                    Log.d(TAG, "Unable to place filling widget at " + auxX + "," + auxY);
-                }
-            }
-        }
-    }
-
-    private void addWidgetInCell(TestBoardWidget widgetRect) {
-        LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
-        LauncherAppWidgetInfo item = createWidgetInfo(info,
-                ApplicationProvider.getApplicationContext(), true);
-        item.cellX = widgetRect.getCellX();
-        item.cellY = widgetRect.getCellY();
-
-        item.spanX = widgetRect.getSpanX();
-        item.spanY = widgetRect.getSpanY();
-        addItemToScreen(item);
-    }
-
-    private void addCorrespondingWidgetRect(TestBoardWidget widgetRect) {
-        if (widgetRect.mType == 'x') {
-            fillWithWidgets(widgetRect);
-        } else {
-            addWidgetInCell(widgetRect);
-        }
-    }
-
     private void runTestCase(ReorderTestCase testCase) {
         Point mainWidgetCellPos = testCase.mStart.getMain();
 
-        testCase.mStart.getWidgets().forEach(this::addCorrespondingWidgetRect);
+        mBoardBuilder.buildBoard(testCase.mStart);
 
-        mLauncher.getWorkspace()
-                .getWidgetAtCell(mainWidgetCellPos.x, mainWidgetCellPos.y)
-                .dragWidgetToWorkspace(testCase.moveMainTo.x, testCase.moveMainTo.y)
-                .dismiss(); // dismiss resize frame
+        Widget widget = mLauncher.getWorkspace().getWidgetAtCell(mainWidgetCellPos.x,
+                mainWidgetCellPos.y);
+        assertNotNull(widget);
+        WidgetResizeFrame resizeFrame = widget.dragWidgetToWorkspace(testCase.moveMainTo.x,
+                testCase.moveMainTo.y);
+        resizeFrame.dismiss();
 
         boolean isValid = false;
         for (CellLayoutBoard board : testCase.mEnd) {
             isValid |= validateBoard(board);
         }
-        assertTrue("None of the valid boards match with the current state", isValid);
+        assertTrue("Non of the valid boards match with the current state", isValid);
     }
 
     /**
diff --git a/tests/src/com/android/launcher3/celllayout/TestWorkspaceBuilder.java b/tests/src/com/android/launcher3/celllayout/TestWorkspaceBuilder.java
new file mode 100644
index 0000000..10e399d
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/TestWorkspaceBuilder.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 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.launcher3.celllayout;
+
+import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
+
+import android.content.ComponentName;
+import android.graphics.Rect;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.LauncherAppWidgetInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TestViewHelpers;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+
+public class TestWorkspaceBuilder {
+
+    private static final ComponentName APP_COMPONENT_NAME = new ComponentName(
+            "com.google.android.calculator", "com.android.calculator2.Calculator");
+
+    public AbstractLauncherUiTest mTest;
+
+    private UserHandle mMyUser;
+
+    public TestWorkspaceBuilder(AbstractLauncherUiTest test) {
+        mTest = test;
+        mMyUser = Process.myUserHandle();
+    }
+
+    private static final String TAG = "CellLayoutBoardBuilder";
+
+    /**
+     * Fills the given rect in WidgetRect with 1x1 widgets. This is useful to equalize cases.
+     */
+    private void fillWithWidgets(CellLayoutBoard.WidgetRect widgetRect) {
+        int initX = widgetRect.getCellX();
+        int initY = widgetRect.getCellY();
+        for (int x = initX; x < initX + widgetRect.getSpanX(); x++) {
+            for (int y = initY; y < initY + widgetRect.getSpanY(); y++) {
+                try {
+                    // this widgets are filling, we don't care if we can't place them
+                    addWidgetInCell(
+                            new CellLayoutBoard.WidgetRect(CellLayoutBoard.CellType.IGNORE,
+                                    new Rect(x, y, x, y))
+                    );
+                } catch (Exception e) {
+                    Log.d(TAG, "Unable to place filling widget at " + x + "," + y);
+                }
+            }
+        }
+    }
+
+    private void addWidgetInCell(CellLayoutBoard.WidgetRect widgetRect) {
+        LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(mTest, false);
+        LauncherAppWidgetInfo item = createWidgetInfo(info,
+                ApplicationProvider.getApplicationContext(), true);
+
+        item.cellX = widgetRect.getCellX();
+        item.cellY = widgetRect.getCellY();
+        item.spanX = widgetRect.getSpanX();
+        item.spanY = widgetRect.getSpanY();
+        mTest.addItemToScreen(item);
+    }
+
+    private void addIconInCell(CellLayoutBoard.IconPoint iconPoint) {
+        AppInfo appInfo = new AppInfo(APP_COMPONENT_NAME, "test icon", mMyUser,
+                AppInfo.makeLaunchIntent(APP_COMPONENT_NAME));
+
+        appInfo.cellX = iconPoint.getCoord().x;
+        appInfo.cellY = iconPoint.getCoord().y;
+        appInfo.minSpanY = appInfo.minSpanX = appInfo.spanX = appInfo.spanY = 1;
+        appInfo.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
+        appInfo.componentName = APP_COMPONENT_NAME;
+
+        mTest.addItemToScreen(new WorkspaceItemInfo(appInfo));
+    }
+
+    private void addCorrespondingWidgetRect(CellLayoutBoard.WidgetRect widgetRect) {
+        if (widgetRect.mType == 'x') {
+            fillWithWidgets(widgetRect);
+        } else {
+            addWidgetInCell(widgetRect);
+        }
+    }
+
+    public void buildBoard(CellLayoutBoard board) {
+        board.getWidgets().forEach(this::addCorrespondingWidgetRect);
+        board.getIcons().forEach(this::addIconInCell);
+    }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java
index 1326389..94e55cf 100644
--- a/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java
+++ b/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java
@@ -19,6 +19,10 @@
 
 import java.util.Map;
 
+/**
+ * The grids represent the workspace to be build by TestWorkspaceBuilder, to see what each character
+ * in the board mean refer to {@code CellType}
+ */
 public class FullReorderCase {
 
     /** 5x5 Test
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java
index 1701390..a222d3d 100644
--- a/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java
+++ b/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java
@@ -19,6 +19,10 @@
 
 import java.util.Map;
 
+/**
+ * The grids represent the workspace to be build by TestWorkspaceBuilder, to see what each character
+ * in the board mean refer to {@code CellType}
+ */
 public class MoveOutReorderCase {
 
     /** 5x5 Test
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java
index bb8d5e9..e16ff42 100644
--- a/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java
+++ b/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java
@@ -19,6 +19,10 @@
 
 import java.util.Map;
 
+/**
+ * The grids represent the workspace to be build by TestWorkspaceBuilder, to see what each character
+ * in the board mean refer to {@code CellType}
+ */
 public class PushReorderCase {
 
     /** 5x5 Test
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/SimpleReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/SimpleReorderCase.java
index 30269a0..546c48b 100644
--- a/tests/src/com/android/launcher3/celllayout/testcases/SimpleReorderCase.java
+++ b/tests/src/com/android/launcher3/celllayout/testcases/SimpleReorderCase.java
@@ -19,6 +19,10 @@
 
 import java.util.Map;
 
+/**
+ * The grids represent the workspace to be build by TestWorkspaceBuilder, to see what each character
+ * in the board mean refer to {@code CellType}
+ */
 public class SimpleReorderCase {
 
     /** 5x5 Test
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 304153f..a66b09a 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -319,7 +319,7 @@
     /**
      * Adds {@param item} on the homescreen on the 0th screen
      */
-    protected void addItemToScreen(ItemInfo item) {
+    public void addItemToScreen(ItemInfo item) {
         WidgetUtils.addItemToScreen(item, mTargetContext);
         resetLoaderState();