Merge "Adding support to add icons in the workspace for tests" into tm-qpr-dev am: 8236313204

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/19701339

Change-Id: I714b5340cb3f85b888a0be5f9fec7e8c43a430ff
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Sebastián Franco
2022-09-02 17:41:21 +00:00
committed by Automerger Merge Worker
8 changed files with 253 additions and 82 deletions
@@ -30,39 +30,117 @@ import java.util.Set;
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 @@ public class CellLayoutBoard {
}
}
}
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 @@ public class CellLayoutBoard {
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 @@ public class CellLayoutBoard {
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;
}
}
@@ -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.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.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 @@ public class ReorderWidgets extends AbstractLauncherUiTest {
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 @@ public class ReorderWidgets extends AbstractLauncherUiTest {
@Before
public void setup() throws Throwable {
mBoardBuilder = new TestWorkspaceBuilder(this);
TaplTestsLauncher3.initialize(this);
clearHomescreen();
}
@@ -86,78 +87,44 @@ public class ReorderWidgets extends AbstractLauncherUiTest {
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);
}
/**
@@ -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);
}
}
@@ -19,6 +19,10 @@ import android.graphics.Point;
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
@@ -19,6 +19,10 @@ import android.graphics.Point;
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
@@ -19,6 +19,10 @@ import android.graphics.Point;
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
@@ -19,6 +19,10 @@ import android.graphics.Point;
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
@@ -319,7 +319,7 @@ public abstract class AbstractLauncherUiTest {
/**
* 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();