Merge "Adding test for the Widgets reordering." into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
df1c1c84b5
@@ -38,6 +38,7 @@ import com.android.launcher3.model.data.ItemInfo;
|
||||
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 @@ public class ItemLongClickListener {
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1221,6 +1221,13 @@ public final class LauncherInstrumentation {
|
||||
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);
|
||||
|
||||
@@ -69,7 +69,24 @@ public final class Widget extends Launchable implements WorkspaceDragSource {
|
||||
*/
|
||||
@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 @@ public final class Widget extends Launchable implements WorkspaceDragSource {
|
||||
*/
|
||||
@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 @@ public final class Widget extends Launchable implements WorkspaceDragSource {
|
||||
*
|
||||
* <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.
|
||||
|
||||
@@ -90,7 +90,7 @@ public final class Workspace extends Home {
|
||||
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 @@ public final class Workspace extends Home {
|
||||
|
||||
/**
|
||||
* @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 @@ public final class Workspace extends Home {
|
||||
/* 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 @@ public final class Workspace extends Home {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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(
|
||||
|
||||
@@ -32,23 +32,36 @@ interface WorkspaceDragSource {
|
||||
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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user