Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 314bbf1c authored by Sebastian Franco's avatar Sebastian Franco
Browse files

Adding support to add icons in the workspace for tests

Test: atest ReorderWidgets
Bug: 243440737
Change-Id: Ic656cef079be965d17ab1b58d5f73ce955c9374c
parent 2886ff08
Loading
Loading
Loading
Loading
+102 −24
Original line number Diff line number Diff line
@@ -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;
    }
}
+24 −57
Original line number Diff line number Diff line
@@ -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;
        }
        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);
        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;
    }

    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);
    }

    /**
+110 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -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
+4 −0
Original line number Diff line number Diff line
@@ -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
Loading