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:
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user