Merge "Adding test for the Widgets reordering." into tm-qpr-dev
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 6bae745..53cd416 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -38,6 +38,7 @@
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.views.BubbleTextHolder;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
/**
* Class to handle long-clicks on workspace items and start drag as a result.
@@ -51,7 +52,11 @@
ItemLongClickListener::onAllAppsItemLongClick;
private static boolean onWorkspaceItemLongClick(View v) {
- TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onWorkspaceItemLongClick");
+ if (v instanceof LauncherAppWidgetHostView) {
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick");
+ } else {
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onWorkspaceItemLongClick");
+ }
Launcher launcher = Launcher.getLauncher(v.getContext());
if (!canStartDrag(launcher)) return false;
if (!launcher.isInState(NORMAL) && !launcher.isInState(OVERVIEW)) return false;
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java b/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
new file mode 100644
index 0000000..3ca05bc
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
@@ -0,0 +1,152 @@
+/*
+ * 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 android.graphics.Point;
+import android.graphics.Rect;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+
+public class CellLayoutBoard {
+
+ static final int INFINITE = 99999;
+
+ char[][] mBoard = new char[30][30];
+
+ List<TestBoardWidget> mWidgetsRects = new ArrayList<>();
+ Map<Character, TestBoardWidget> mWidgetsMap = new HashMap<>();
+
+ List<TestBoardAppIcon> mIconPoints = new ArrayList<>();
+ Map<Character, TestBoardAppIcon> 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] = '-';
+ }
+ }
+ }
+
+ public List<TestBoardWidget> getWidgets() {
+ return mWidgetsRects;
+ }
+
+ public Point getMain() {
+ return mMain;
+ }
+
+ public TestBoardWidget getWidgetRect(char c) {
+ return mWidgetsMap.get(c);
+ }
+
+ public static TestBoardWidget 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);
+ search.add(current);
+ used.add(current);
+ List<Point> neighbors = new ArrayList<>(List.of(
+ new Point(-1, 0),
+ new Point(0, -1),
+ new Point(1, 0),
+ new Point(0, 1))
+ );
+ Rect widgetRect = new Rect(INFINITE, -INFINITE, -INFINITE, INFINITE);
+ while (!search.isEmpty()) {
+ current = search.poll();
+ widgetRect.top = Math.max(widgetRect.top, current.y);
+ widgetRect.right = Math.max(widgetRect.right, current.x);
+ widgetRect.bottom = Math.min(widgetRect.bottom, current.y);
+ widgetRect.left = Math.min(widgetRect.left, current.x);
+ for (Point p : neighbors) {
+ Point next = new Point(current.x + p.x, current.y + p.y);
+ if (next.x < 0 || next.x >= board.length) continue;
+ if (next.y < 0 || next.y >= board[0].length) continue;
+ if (board[next.x][next.y] == type && !used.contains(next)) {
+ used.add(next);
+ search.add(next);
+ }
+ }
+ }
+ return new TestBoardWidget(type, widgetRect);
+ }
+
+ public static boolean isWidget(char type) {
+ return type != 'i' && type != '-';
+ }
+
+ public static boolean isIcon(char type) {
+ return type == 'i';
+ }
+
+ private static List<TestBoardWidget> getRects(char[][] board) {
+ Set<Point> used = new HashSet<>();
+ List<TestBoardWidget> 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])) {
+ widgetsRects.add(getWidgetRect(x, y, used, board));
+ }
+ }
+ }
+ return widgetsRects;
+ }
+
+ private static List<TestBoardAppIcon> getIconPoints(char[][] board) {
+ List<TestBoardAppIcon> 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]));
+ }
+ }
+ }
+ return iconPoints;
+ }
+
+ public static CellLayoutBoard boardFromString(String boardStr) {
+ String[] lines = boardStr.split("\n");
+ CellLayoutBoard board = new CellLayoutBoard();
+
+ for (int y = 0; y < lines.length; y++) {
+ String line = lines[y];
+ for (int x = 0; x < line.length(); x++) {
+ char c = line.charAt(x);
+ if (c == 'm') {
+ board.mMain = new Point(x, y);
+ }
+ if (c != '-') {
+ board.mBoard[x][y] = line.charAt(x);
+ }
+ }
+ }
+ board.mWidgetsRects = getRects(board.mBoard);
+ board.mWidgetsRects.forEach(
+ widgetRect -> board.mWidgetsMap.put(widgetRect.mType, widgetRect));
+ board.mIconPoints = getIconPoints(board.mBoard);
+ return board;
+ }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
new file mode 100644
index 0000000..ed0b71d
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
@@ -0,0 +1,197 @@
+/*
+ * 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 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;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.celllayout.testcases.FullReorderCase;
+import com.android.launcher3.celllayout.testcases.MoveOutReorderCase;
+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.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TaplTestsLauncher3;
+import com.android.launcher3.ui.TestViewHelpers;
+import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Map;
+
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ReorderWidgets extends AbstractLauncherUiTest {
+
+ @Rule
+ public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
+
+ private static final String TAG = ReorderWidgets.class.getSimpleName();
+
+ private View getViewAt(int cellX, int cellY) {
+ return getFromLauncher(l -> l.getWorkspace().getScreenWithId(
+ l.getWorkspace().getScreenIdForPageIndex(0)).getChildAt(cellX, cellY));
+ }
+
+ private Point getCellDimensions() {
+ return getFromLauncher(l -> {
+ CellLayout cellLayout = l.getWorkspace().getScreenWithId(
+ l.getWorkspace().getScreenIdForPageIndex(0));
+ return new Point(cellLayout.getWidth() / cellLayout.getCountX(),
+ cellLayout.getHeight() / cellLayout.getCountY());
+ });
+ }
+
+ @Before
+ public void setup() throws Throwable {
+ TaplTestsLauncher3.initialize(this);
+ clearHomescreen();
+ }
+
+ /**
+ * Validate if the given board represent the current CellLayout
+ **/
+ private boolean validateBoard(CellLayoutBoard board) {
+ boolean match = true;
+ Point cellDimensions = getCellDimensions();
+ for (TestBoardWidget widgetRect: board.getWidgets()) {
+ if (widgetRect.shouldIgnore()) {
+ continue;
+ }
+ View widget = getViewAt(widgetRect.getCellX(), widgetRect.getCellY());
+ match &= widgetRect.getSpanX()
+ == Math.round(widget.getWidth() / (float) cellDimensions.x);
+ match &= widgetRect.getSpanY()
+ == Math.round(widget.getHeight() / (float) cellDimensions.y);
+ if (!match) return match;
+ }
+ 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);
+
+ mLauncher.getWorkspace()
+ .getWidgetAtCell(mainWidgetCellPos.x, mainWidgetCellPos.y)
+ .dragWidgetToWorkspace(testCase.moveMainTo.x, testCase.moveMainTo.y)
+ .dismiss(); // dismiss resize frame
+
+ boolean isValid = false;
+ for (CellLayoutBoard board : testCase.mEnd) {
+ isValid |= validateBoard(board);
+ }
+ assertTrue("None of the valid boards match with the current state", isValid);
+ }
+
+ /**
+ * Run only the test define for the current grid size if such test exist
+ *
+ * @param testCaseMap map containing all the tests per grid size (Point)
+ */
+ private void runTestCaseMap(Map<Point, ReorderTestCase> testCaseMap, String testName) {
+ Point iconGridDimensions = mLauncher.getWorkspace().getIconGridDimensions();
+ Log.d(TAG, "Running test " + testName + " for grid " + iconGridDimensions);
+ Assume.assumeTrue(
+ "The test " + testName + " doesn't support " + iconGridDimensions + " grid layout",
+ testCaseMap.containsKey(iconGridDimensions));
+ runTestCase(testCaseMap.get(iconGridDimensions));
+ }
+
+ @Test
+ public void simpleReorder() {
+ runTestCaseMap(SimpleReorderCase.TEST_BY_GRID_SIZE,
+ SimpleReorderCase.class.getSimpleName());
+ }
+
+ @Test
+ public void pushTest() {
+ runTestCaseMap(PushReorderCase.TEST_BY_GRID_SIZE, PushReorderCase.class.getSimpleName());
+ }
+
+ @Test
+ public void fullReorder() {
+ runTestCaseMap(FullReorderCase.TEST_BY_GRID_SIZE, FullReorderCase.class.getSimpleName());
+ }
+
+ @Test
+ public void moveOutReorder() {
+ runTestCaseMap(MoveOutReorderCase.TEST_BY_GRID_SIZE,
+ MoveOutReorderCase.class.getSimpleName());
+ }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/TestBoardAppIcon.java b/tests/src/com/android/launcher3/celllayout/TestBoardAppIcon.java
new file mode 100644
index 0000000..04604d7
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/TestBoardAppIcon.java
@@ -0,0 +1,44 @@
+/*
+ * 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 android.graphics.Point;
+
+public class TestBoardAppIcon {
+ public Point coord;
+ public char mType;
+
+ public TestBoardAppIcon(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;
+ }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/TestBoardWidget.java b/tests/src/com/android/launcher3/celllayout/TestBoardWidget.java
new file mode 100644
index 0000000..7f9aa95
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/TestBoardWidget.java
@@ -0,0 +1,48 @@
+/*
+ * 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 android.graphics.Rect;
+
+public class TestBoardWidget {
+ public char mType;
+ public Rect mBounds;
+
+ TestBoardWidget(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 == 'x';
+ }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java
new file mode 100644
index 0000000..ff03a50
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java
@@ -0,0 +1,65 @@
+/*
+ * 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.testcases;
+
+import android.graphics.Point;
+
+import java.util.Map;
+
+public class FullReorderCase {
+ private static final String START_BOARD_STR_5x5 = ""
+ + "xxxxx\n"
+ + "222mm\n"
+ + "222mm\n"
+ + "ad111\n"
+ + "bc111";
+
+ private static final Point MOVE_TO_5x5 = new Point(0, 4);
+
+ private static final String END_BOARD_STR_5x5 = ""
+ + "xxxxx\n"
+ + "222ad\n"
+ + "222bc\n"
+ + "mm111\n"
+ + "mm111";
+
+ private static final ReorderTestCase TEST_CASE_5x5 = new ReorderTestCase(START_BOARD_STR_5x5,
+ MOVE_TO_5x5,
+ END_BOARD_STR_5x5);
+
+ private static final String START_BOARD_STR_6x5 = ""
+ + "xxxxxx\n"
+ + "2222mm\n"
+ + "2222mm\n"
+ + "ad1111\n"
+ + "bc1111";
+
+ private static final Point MOVE_TO_6x5 = new Point(0, 4);
+
+ private static final String END_BOARD_STR_6x5 = ""
+ + "xxxxxx\n"
+ + "2222ad\n"
+ + "2222bc\n"
+ + "mm1111\n"
+ + "mm1111";
+
+ private static final ReorderTestCase TEST_CASE_6x5 = new ReorderTestCase(START_BOARD_STR_6x5,
+ MOVE_TO_6x5,
+ END_BOARD_STR_6x5);
+
+ public static final Map<Point, ReorderTestCase> TEST_BY_GRID_SIZE =
+ Map.of(new Point(5, 5), TEST_CASE_5x5, new Point(6, 5), TEST_CASE_6x5);
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java
new file mode 100644
index 0000000..32bf05a
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java
@@ -0,0 +1,66 @@
+/*
+ * 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.testcases;
+
+import android.graphics.Point;
+
+import java.util.Map;
+
+public class MoveOutReorderCase {
+ private static final String START_BOARD_STR_5x5 = ""
+ + "xxxxx\n"
+ + "34-m-\n"
+ + "35111\n"
+ + "32111\n"
+ + "32111";
+
+ private static final Point MOVE_TO_5x5 = new Point(1, 2);
+
+ private static final String END_BOARD_STR_5x5 = ""
+ + "xxxxx\n"
+ + "345--\n"
+ + "3m111\n"
+ + "32111\n"
+ + "32111";
+
+ private static final ReorderTestCase TEST_CASE_5x5 = new ReorderTestCase(START_BOARD_STR_5x5,
+ MOVE_TO_5x5,
+ END_BOARD_STR_5x5);
+
+
+ private static final String START_BOARD_STR_6x5 = ""
+ + "xxxxxx\n"
+ + "34-m--\n"
+ + "351111\n"
+ + "321111\n"
+ + "321111";
+
+ private static final Point MOVE_TO_6x5 = new Point(1, 2);
+
+ private static final String END_BOARD_STR_6x5 = ""
+ + "xxxxxx\n"
+ + "345---\n"
+ + "3m1111\n"
+ + "321111\n"
+ + "321111";
+
+ private static final ReorderTestCase TEST_CASE_6x5 = new ReorderTestCase(START_BOARD_STR_6x5,
+ MOVE_TO_6x5,
+ END_BOARD_STR_6x5);
+
+ public static final Map<Point, ReorderTestCase> TEST_BY_GRID_SIZE =
+ Map.of(new Point(5, 5), TEST_CASE_5x5, new Point(6, 5), TEST_CASE_6x5);
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java
new file mode 100644
index 0000000..b386946
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java
@@ -0,0 +1,76 @@
+/*
+ * 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.testcases;
+
+import android.graphics.Point;
+
+import com.android.launcher3.celllayout.CellLayoutBoard;
+
+import java.util.Map;
+
+public class PushReorderCase {
+ private static final String START_BOARD_STR_5x5 = ""
+ + "xxxxx\n"
+ + "222m-\n"
+ + "--111\n"
+ + "--333\n"
+ + "-----";
+ private static final CellLayoutBoard START_BOARD_5x5 = CellLayoutBoard.boardFromString(
+ START_BOARD_STR_5x5);
+
+ private static final Point MOVE_TO_5x5 = new Point(2, 1);
+
+ private static final String END_BOARD_STR_5x5 = ""
+ + "xxxxx\n"
+ + "--m--\n"
+ + "222--\n"
+ + "--111\n"
+ + "--333";
+ private static final CellLayoutBoard END_BOARD_5x5 = CellLayoutBoard.boardFromString(
+ END_BOARD_STR_5x5);
+
+ private static final ReorderTestCase TEST_CASE_5x5 = new ReorderTestCase(START_BOARD_5x5,
+ MOVE_TO_5x5,
+ END_BOARD_5x5);
+
+
+ private static final String START_BOARD_STR_6x5 = ""
+ + "xxxxxx\n"
+ + "2222m-\n"
+ + "--111-\n"
+ + "--333-\n"
+ + "------";
+ private static final CellLayoutBoard START_BOARD_6x5 = CellLayoutBoard.boardFromString(
+ START_BOARD_STR_6x5);
+
+ private static final Point MOVE_TO_6x5 = new Point(2, 1);
+
+ private static final String END_BOARD_STR_6x5 = ""
+ + "xxxxxx\n"
+ + "--m---\n"
+ + "2222--\n"
+ + "--111-\n"
+ + "--333-";
+ private static final CellLayoutBoard END_BOARD_6x5 = CellLayoutBoard.boardFromString(
+ END_BOARD_STR_6x5);
+
+ private static final ReorderTestCase TEST_CASE_6x5 = new ReorderTestCase(START_BOARD_6x5,
+ MOVE_TO_6x5,
+ END_BOARD_6x5);
+
+ public static final Map<Point, ReorderTestCase> TEST_BY_GRID_SIZE =
+ Map.of(new Point(5, 5), TEST_CASE_5x5, new Point(6, 5), TEST_CASE_6x5);
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/ReorderTestCase.java b/tests/src/com/android/launcher3/celllayout/testcases/ReorderTestCase.java
new file mode 100644
index 0000000..0a28668
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testcases/ReorderTestCase.java
@@ -0,0 +1,46 @@
+/*
+ * 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.testcases;
+
+import android.graphics.Point;
+
+import com.android.launcher3.celllayout.CellLayoutBoard;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ReorderTestCase {
+ public CellLayoutBoard mStart;
+ public Point moveMainTo;
+ public List<CellLayoutBoard> mEnd;
+
+ ReorderTestCase(CellLayoutBoard start, Point moveMainTo, CellLayoutBoard ... end) {
+ mStart = start;
+ this.moveMainTo = moveMainTo;
+ mEnd = Arrays.asList(end);
+ }
+
+ ReorderTestCase(String start, Point moveMainTo, String ... end) {
+ mStart = CellLayoutBoard.boardFromString(start);
+ this.moveMainTo = moveMainTo;
+ mEnd = Arrays
+ .asList(end)
+ .stream()
+ .map(CellLayoutBoard::boardFromString)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testcases/SimpleReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/SimpleReorderCase.java
new file mode 100644
index 0000000..57e1398
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testcases/SimpleReorderCase.java
@@ -0,0 +1,51 @@
+/*
+ * 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.testcases;
+
+import android.graphics.Point;
+
+import com.android.launcher3.celllayout.CellLayoutBoard;
+
+import java.util.Map;
+
+public class SimpleReorderCase {
+ private static final String START_BOARD_STR = ""
+ + "xxxxx\n"
+ + "--mm-\n"
+ + "--mm-\n"
+ + "-----\n"
+ + "-----";
+ private static final CellLayoutBoard START_BOARD_5x5 = CellLayoutBoard.boardFromString(
+ START_BOARD_STR);
+
+ private static final Point MOVE_TO_5x5 = new Point(4, 4);
+
+ private static final String END_BOARD_STR_5x5 = ""
+ + "xxxxx\n"
+ + "-----\n"
+ + "-----\n"
+ + "---mm\n"
+ + "---mm";
+ private static final CellLayoutBoard END_BOARD_5x5 = CellLayoutBoard.boardFromString(
+ END_BOARD_STR_5x5);
+
+ private static final ReorderTestCase TEST_CASE_5x5 = new ReorderTestCase(START_BOARD_5x5,
+ MOVE_TO_5x5,
+ END_BOARD_5x5);
+
+ public static final Map<Point, ReorderTestCase> TEST_BY_GRID_SIZE =
+ Map.of(new Point(5, 5), TEST_CASE_5x5);
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index fa6141a..f5b5a6a 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1221,6 +1221,13 @@
return object;
}
+ @NonNull
+ List<UiObject2> waitForObjectsBySelector(BySelector selector) {
+ final List<UiObject2> objects = mDevice.wait(Until.findObjects(selector), WAIT_TIME_MS);
+ assertNotNull("Can't find any view in Launcher, selector: " + selector, objects);
+ return objects;
+ }
+
private UiObject2 waitForObjectBySelector(BySelector selector) {
final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
assertNotNull("Can't find a view in Launcher, selector: " + selector, object);
diff --git a/tests/tapl/com/android/launcher3/tapl/Widget.java b/tests/tapl/com/android/launcher3/tapl/Widget.java
index 2346249..e1a09af 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widget.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widget.java
@@ -69,7 +69,24 @@
*/
@NonNull
public WidgetResizeFrame dragWidgetToWorkspace() {
- return dragWidgetToWorkspace(/* configurable= */ false, /* acceptsConfig= */ false);
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ return dragWidgetToWorkspace(/* configurable= */ false, /* acceptsConfig= */ false, -1,
+ -1);
+ }
+ }
+
+ /**
+ * Drags a non-configurable widget from the widgets container to the workspace at cellX and
+ * cellY and returns the resize frame that is shown after the widget is added.
+ */
+ @NonNull
+ public WidgetResizeFrame dragWidgetToWorkspace(int cellX, int cellY) {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "Dragging widget to workspace cell " + cellX + "," + cellY)) {
+ return dragWidgetToWorkspace(/* configurable= */ false, /* acceptsConfig= */ false,
+ cellX, cellY);
+ }
}
/**
@@ -79,7 +96,32 @@
*/
@Nullable
public WidgetResizeFrame dragConfigWidgetToWorkspace(boolean acceptsConfig) {
- return dragWidgetToWorkspace(/* configurable= */ true, acceptsConfig);
+ // TODO(b/239438337, fransebas) add correct event checking for this case
+ //try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ return dragWidgetToWorkspace(/* configurable= */ true, acceptsConfig, -1, -1);
+ //}
+ }
+
+ /**
+ * Drags an object to the center of homescreen.
+ *
+ * @param startsActivity whether it's expected to start an activity.
+ * @param isWidgetShortcut whether we drag a widget shortcut
+ * @param cellX X position in the CellLayout
+ * @param cellY Y position in the CellLayout
+ */
+ private void dragToWorkspace(boolean startsActivity, boolean isWidgetShortcut, int cellX,
+ int cellY) {
+ Launchable launchable = getLaunchable();
+ LauncherInstrumentation launcher = launchable.mLauncher;
+ Workspace.dragIconToWorkspace(
+ launcher,
+ launchable,
+ () -> Workspace.getCellCenter(launchable.mLauncher, cellX, cellY),
+ startsActivity,
+ isWidgetShortcut,
+ launchable::addExpectedEventsForLongClick);
+
}
/**
@@ -88,11 +130,28 @@
*
* <p> If {@code configurable} is true, then either accepts or cancels the configuration based
* on {@code acceptsConfig}.
+ * <p> If either {@code cellX} or {@code cellY} are negative, then a default location would be
+ * chosen
+ *
+ * @param configurable if the widget has a configuration activity.
+ * @param acceptsConfig if the widget has a configuration, then if we should accept it or
+ * cancel it
+ * @param cellX X position to drop the widget in the workspace
+ * @param cellY Y position to drop the widget in the workspace
+ * @return returns the given resize frame of the widget after being dropped, if
+ * configurable is true and acceptsConfig is false then the widget would not be places and will
+ * be cancel and it returns null.
*/
@Nullable
- private WidgetResizeFrame dragWidgetToWorkspace(
- boolean configurable, boolean acceptsConfig) {
- dragToWorkspace(/* startsActivity= */ configurable, /* isWidgetShortcut= */ false);
+ private WidgetResizeFrame dragWidgetToWorkspace(boolean configurable, boolean acceptsConfig,
+ int cellX, int cellY) {
+ if (cellX == -1 || cellY == -1) {
+ internalDragToWorkspace(/* startsActivity= */ configurable, /* isWidgetShortcut= */
+ false);
+ } else {
+ dragToWorkspace(/* startsActivity= */ configurable, /* isWidgetShortcut= */ false,
+ cellX, cellY);
+ }
if (configurable) {
// Configure the widget.
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 5e5fdec..6044b06 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -90,7 +90,7 @@
final int windowCornerRadius = (int) Math.ceil(mLauncher.getWindowCornerRadius());
final int startY = deviceHeight - Math.max(bottomGestureMargin, windowCornerRadius) - 1;
final int swipeHeight = mLauncher.getTestInfo(
- TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT)
+ TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT)
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
LauncherInstrumentation.log(
"switchToAllApps: deviceHeight = " + deviceHeight + ", startY = " + startY
@@ -271,7 +271,7 @@
/**
* @return map of text -> center of the view. In case of icons with the same name, the one with
- * lower x coordinate is selected.
+ * lower x coordinate is selected.
*/
public Map<String, Point> getWorkspaceIconsPositions() {
final UiObject2 workspace = verifyActiveContainer();
@@ -284,6 +284,7 @@
/* valueMapper= */ UiObject2::getVisibleCenter,
/* mergeFunction= */ (p1, p2) -> p1.x < p2.x ? p1 : p2));
}
+
/*
* Get the center point of the delete/uninstall icon in the drop target bar.
*/
@@ -581,6 +582,32 @@
}
}
+ /**
+ * @param cellX X position of the widget trying to get.
+ * @param cellY Y position of the widget trying to get.
+ * @return returns the Widget in the given position in the Launcher or an Exception if no such
+ * widget is in that position.
+ */
+ @NonNull
+ public Widget getWidgetAtCell(int cellX, int cellY) {
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "getting widget at cell position " + cellX + "," + cellY)) {
+ final List<UiObject2> widgets = mLauncher.waitForObjectsBySelector(
+ By.clazz("com.android.launcher3.widget.LauncherAppWidgetHostView"));
+ Point coordinateInScreen = Workspace.getCellCenter(mLauncher, cellX, cellY);
+ for (UiObject2 widget : widgets) {
+ if (widget.getVisibleBounds().contains(coordinateInScreen.x,
+ coordinateInScreen.y)) {
+ return new Widget(mLauncher, widget);
+ }
+ }
+ }
+ mLauncher.fail("Unable to find widget at cell " + cellX + "," + cellY);
+ // This statement is unreachable because mLauncher.fail throws an exception
+ // but is needed for compiling
+ return null;
+ }
+
@Nullable
public Widget tryGetPendingWidget(long timeout) {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
diff --git a/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
index 021cc98..141476c 100644
--- a/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
+++ b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
@@ -32,24 +32,37 @@
Launchable launchable = getLaunchable();
LauncherInstrumentation launcher = launchable.mLauncher;
try (LauncherInstrumentation.Closable e = launcher.eventsCheck()) {
- final Point launchableCenter = launchable.getObject().getVisibleCenter();
- final Point displaySize = launcher.getRealDisplaySize();
- final int width = displaySize.x / 2;
- Workspace.dragIconToWorkspace(
- launcher,
- launchable,
- () -> new Point(
- launchableCenter.x >= width
- ? launchableCenter.x - width / 2
- : launchableCenter.x + width / 2,
- displaySize.y / 2),
- startsActivity,
- isWidgetShortcut,
- launchable::addExpectedEventsForLongClick);
+ internalDragToWorkspace(startsActivity, isWidgetShortcut);
}
}
/**
+ * TODO(Redesign WorkspaceDragSource to have actual private methods)
+ * Temporary private method
+ *
+ * @param startsActivity whether it's expected to start an activity.
+ * @param isWidgetShortcut whether we drag a widget shortcut
+ */
+ default void internalDragToWorkspace(boolean startsActivity, boolean isWidgetShortcut) {
+ Launchable launchable = getLaunchable();
+ LauncherInstrumentation launcher = launchable.mLauncher;
+ final Point launchableCenter = launchable.getObject().getVisibleCenter();
+ final Point displaySize = launcher.getRealDisplaySize();
+ final int width = displaySize.x / 2;
+ Workspace.dragIconToWorkspace(
+ launcher,
+ launchable,
+ () -> new Point(
+ launchableCenter.x >= width
+ ? launchableCenter.x - width / 2
+ : launchableCenter.x + width / 2,
+ displaySize.y / 2),
+ startsActivity,
+ isWidgetShortcut,
+ launchable::addExpectedEventsForLongClick);
+ }
+
+ /**
* Drag an object to the given cell in workspace. The target cell must be empty.
*
* @param cellX zero based column number, starting from the left of the screen.