Merge "Set drop target font weight to medium." into tm-qpr-dev
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index b297973..fefef2f 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -220,7 +220,6 @@
*/
public void enableInputConsumer() {
UI_HELPER_EXECUTOR.submit(() -> {
- mController.hideCurrentInputMethod();
mController.setInputConsumerEnabled(true);
});
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index f1189c9..e89c842 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -42,6 +42,8 @@
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import com.android.quickstep.SystemUiProxy;
@@ -171,6 +173,8 @@
public void launchTasks(int taskId1, @Nullable PendingIntent taskPendingIntent,
@Nullable Intent fillInIntent, int taskId2, @StagePosition int stagePosition,
Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
+ TestLogging.recordEvent(
+ TestProtocol.SEQUENCE_MAIN, "launchSplitTasks");
// Assume initial task is for top/left part of screen
final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT
? new int[]{taskId1, taskId2}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index c9d6394..c178175 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -204,7 +204,11 @@
if (mDp == null) {
return;
}
- if (mDp.areNavButtonsInline) {
+ boolean largeScreenLandscape = mDp.isTablet && !mDp.isTwoPanels && mDp.isLandscape;
+ // If in 3-button mode, shift action buttons to accommodate 3-button layout.
+ // (Special exception for landscape tablets, where there is enough room and we don't need to
+ // shift the action buttons.)
+ if (mDp.areNavButtonsInline && !largeScreenLandscape) {
// Add extra horizontal spacing
int additionalPadding = mDp.hotseatBarEndOffset;
if (isLayoutRtl()) {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 4bf247c..81df3c0 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -179,6 +179,20 @@
actionsView.clickAndDismissScreenshot();
}
+ @Test
+ @PortraitLandscape
+ public void testSplitFromOverviewForTablet() {
+ assumeTrue(mLauncher.isTablet());
+
+ startTestActivity(2);
+ startTestActivity(3);
+
+ mLauncher.goHome().switchToOverview().getOverviewActions()
+ .clickSplit()
+ .getTestActivityTask(2)
+ .open();
+ }
+
private int getCurrentOverviewPage(Launcher launcher) {
return launcher.<RecentsView>getOverviewPanel().getCurrentPage();
}
diff --git a/res/layout/all_apps_bottom_sheet_background.xml b/res/layout/all_apps_bottom_sheet_background.xml
index 12b6b7b..3e47690 100644
--- a/res/layout/all_apps_bottom_sheet_background.xml
+++ b/res/layout/all_apps_bottom_sheet_background.xml
@@ -22,7 +22,7 @@
<View
android:id="@+id/bottom_sheet_handle_area"
android:layout_width="match_parent"
- android:layout_height="36dp" />
+ android:layout_height="@dimen/bottom_sheet_handle_area_height" />
<View
android:id="@+id/bottom_sheet_handle"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index caa7da0..dc80bc3 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -413,6 +413,7 @@
<!-- Bottom sheet related parameters -->
<dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
+ <dimen name="bottom_sheet_handle_area_height">36dp</dimen>
<dimen name="bottom_sheet_handle_width">32dp</dimen>
<dimen name="bottom_sheet_handle_height">4dp</dimen>
<dimen name="bottom_sheet_handle_margin">16dp</dimen>
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index 6faedc0..f3c5dd6 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -602,6 +602,8 @@
if (mAH.get(currentActivePage).mRecyclerView != null) {
mAH.get(currentActivePage).mRecyclerView.bindFastScrollbar();
}
+ // Header keeps track of active recycler view to properly render header protection.
+ mHeader.setActiveRV(currentActivePage);
reset(true /* animate */);
mWorkManager.onActivePageChanged(currentActivePage);
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 489bc38..a9d272e 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -57,7 +57,9 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
* Handles updates due to changes in package manager (app installed/updated/removed)
@@ -343,7 +345,12 @@
.or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
.and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
deleteAndBindComponentsRemoved(removeMatch,
- "removed because the corresponding package or component is removed");
+ "removed because the corresponding package or component is removed. "
+ + "mOp=" + mOp + " removedPackages=" + removedPackages.stream().collect(
+ Collectors.joining(",", "[", "]"))
+ + " removedComponents=" + removedComponents.stream()
+ .filter(Objects::nonNull).map(ComponentName::toShortString)
+ .collect(Collectors.joining(",", "[", "]")));
// Remove any queued items from the install queue
ItemInstallQueue.INSTANCE.get(context)
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/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 6f8b9d2..1f6e1ec 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -563,10 +563,13 @@
break;
}
case OVERVIEW: {
- checkLauncherStateInOverview(launcher, expectedContainerType, isStarted,
- isResumed);
- assertTrue(TestProtocol.stateOrdinalToString(ordinal),
- ordinal == TestProtocol.OVERVIEW_STATE_ORDINAL);
+ verifyOverviewState(launcher, expectedContainerType, isStarted, isResumed,
+ ordinal, TestProtocol.OVERVIEW_STATE_ORDINAL);
+ break;
+ }
+ case SPLIT_SCREEN_SELECT: {
+ verifyOverviewState(launcher, expectedContainerType, isStarted, isResumed,
+ ordinal, TestProtocol.OVERVIEW_SPLIT_SELECT_ORDINAL);
break;
}
case TASKBAR_ALL_APPS:
@@ -632,5 +635,9 @@
return homeAppIcon;
}
-
+ private void verifyOverviewState(Launcher launcher, ContainerType expectedContainerType,
+ boolean isStarted, boolean isResumed, int ordinal, int expectedOrdinal) {
+ checkLauncherStateInOverview(launcher, expectedContainerType, isStarted, isResumed);
+ assertEquals(TestProtocol.stateOrdinalToString(ordinal), ordinal, expectedOrdinal);
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index b7bca02..6a11336 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -19,6 +19,7 @@
import android.graphics.Rect;
import androidx.annotation.NonNull;
+import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiObject2;
@@ -168,6 +169,27 @@
return new OverviewTask(mLauncher, widestTask, this);
}
+ /** Returns an overview task matching TestActivity {@param activityNumber}. */
+ @NonNull
+ public OverviewTask getTestActivityTask(int activityNumber) {
+ final List<UiObject2> taskViews = getTasks();
+ mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
+
+ final String activityName = "TestActivity" + activityNumber;
+ UiObject2 task = null;
+ for (UiObject2 taskView : taskViews) {
+ // TODO(b/239452415): Use equals instead of descEndsWith
+ if (taskView.getParent().hasObject(By.descEndsWith(activityName))) {
+ task = taskView;
+ break;
+ }
+ }
+ mLauncher.assertNotNull(
+ "Unable to find a task with " + activityName + " from the task list", task);
+
+ return new OverviewTask(mLauncher, task, this);
+ }
+
/**
* Returns a list of all tasks fully visible in the tablet grid overview.
*/
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index fa6141a..5f92097 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -121,8 +121,8 @@
// Types for launcher containers that the user is interacting with. "Background" is a
// pseudo-container corresponding to inactive launcher covered by another app.
public enum ContainerType {
- WORKSPACE, HOME_ALL_APPS, OVERVIEW, WIDGETS, FALLBACK_OVERVIEW, LAUNCHED_APP,
- TASKBAR_ALL_APPS
+ WORKSPACE, HOME_ALL_APPS, OVERVIEW, SPLIT_SCREEN_SELECT, WIDGETS, FALLBACK_OVERVIEW,
+ LAUNCHED_APP, TASKBAR_ALL_APPS
}
public enum NavigationModel {ZERO_BUTTON, THREE_BUTTON}
@@ -744,7 +744,8 @@
return waitForLauncherObject(APPS_RES_ID);
}
- case OVERVIEW: {
+ case OVERVIEW:
+ case SPLIT_SCREEN_SELECT: {
waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
@@ -1091,6 +1092,14 @@
}
@NonNull
+ UiObject2 waitForSystemUiObject(BySelector selector) {
+ final UiObject2 object = TestHelpers.wait(
+ Until.findObject(selector), WAIT_TIME_MS);
+ assertNotNull("Can't find a systemui object with selector: " + selector, object);
+ return object;
+ }
+
+ @NonNull
UiObject2 waitForNavigationUiObject(String resId) {
String resPackage = getNavigationButtonResPackage();
final UiObject2 object = mDevice.wait(
@@ -1221,6 +1230,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/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 66a51a5..50c2136 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -21,7 +21,7 @@
/**
* Overview pane.
*/
-public final class Overview extends BaseOverview {
+public class Overview extends BaseOverview {
Overview(LauncherInstrumentation launcher) {
super(launcher);
@@ -29,7 +29,7 @@
@Override
protected ContainerType getContainerType() {
- return LauncherInstrumentation.ContainerType.OVERVIEW;
+ return ContainerType.OVERVIEW;
}
@Override
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
index d1b1a84..5710713 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
@@ -86,7 +86,6 @@
"clicked select button")) {
return getSelectModeButtons();
}
-
}
}
@@ -103,4 +102,22 @@
return new SelectModeButtons(selectModeButtons, mLauncher);
}
}
+
+ /**
+ * Clicks split button and enters split select mode.
+ */
+ @NonNull
+ public SplitScreenSelect clickSplit() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to click split button to enter split select mode")) {
+ UiObject2 split = mLauncher.waitForObjectInContainer(mOverviewActions,
+ "action_split");
+ mLauncher.clickLauncherObject(split);
+ try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
+ "clicked split")) {
+ return new SplitScreenSelect(mLauncher);
+ }
+ }
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index c8caa42..ac7424e 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -20,6 +20,8 @@
import android.graphics.Rect;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.UiObject2;
import com.android.launcher3.testing.TestProtocol;
@@ -32,8 +34,12 @@
* A recent task in the overview panel carousel.
*/
public final class OverviewTask {
+ private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+
static final Pattern TASK_START_EVENT =
Pattern.compile("startActivityFromRecentsAsync");
+ static final Pattern SPLIT_START_EVENT =
+ Pattern.compile("launchSplitTasks");
private final LauncherInstrumentation mLauncher;
private final UiObject2 mTask;
private final BaseOverview mOverview;
@@ -125,7 +131,7 @@
}
/**
- * Clicks at the task.
+ * Clicks the task.
*/
public LaunchedAppState open() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
@@ -136,8 +142,21 @@
() -> "Launching task didn't open a new window: "
+ mTask.getParent().getContentDescription(),
"clicking an overview task");
- mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
- return new LaunchedAppState(mLauncher);
+ if (mOverview.getContainerType()
+ == LauncherInstrumentation.ContainerType.SPLIT_SCREEN_SELECT) {
+ mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SPLIT_START_EVENT);
+
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "launched splitscreen")) {
+
+ BySelector divider = By.res(SYSTEMUI_PACKAGE, "docked_divider_handle");
+ mLauncher.waitForSystemUiObject(divider);
+ return new LaunchedAppState(mLauncher);
+ }
+ } else {
+ mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
+ return new LaunchedAppState(mLauncher);
+ }
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/SplitScreenSelect.java b/tests/tapl/com/android/launcher3/tapl/SplitScreenSelect.java
new file mode 100644
index 0000000..3cf3ed6
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/SplitScreenSelect.java
@@ -0,0 +1,35 @@
+/*
+ * 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.tapl;
+
+import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
+
+/**
+ * Represents a special state in Overview where the initial split app is shoved to the side and a
+ * second split app can be selected.
+ */
+public class SplitScreenSelect extends Overview {
+
+ SplitScreenSelect(LauncherInstrumentation launcher) {
+ super(launcher);
+ }
+
+ @Override
+ protected ContainerType getContainerType() {
+ return ContainerType.SPLIT_SCREEN_SELECT;
+ }
+}
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.