mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-18 18:28:20 +00:00
Merge "Add new quickstep test for many tasks open at once." into sc-v2-dev
This commit is contained in:
@@ -63,6 +63,17 @@ public class QuickstepTestInformationHandler extends TestInformationHandler {
|
||||
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, focusedTaskRect.height());
|
||||
return response;
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET: {
|
||||
if (!mDeviceProfile.isTablet) {
|
||||
return null;
|
||||
}
|
||||
Rect gridTaskRect = new Rect();
|
||||
LauncherActivityInterface.INSTANCE.calculateGridTaskSize(mContext, mDeviceProfile,
|
||||
gridTaskRect, PagedOrientationHandler.PORTRAIT);
|
||||
response.putParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD, gridTaskRect);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
return super.call(method, arg);
|
||||
|
||||
@@ -1484,6 +1484,20 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
return groupViewCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tasks in the top row of the overview grid.
|
||||
*/
|
||||
public int getTopRowTaskCountForTablet() {
|
||||
return mTopRowIdSet.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tasks in the bottom row of the overview grid.
|
||||
*/
|
||||
public int getBottomRowTaskCountForTablet() {
|
||||
return getTaskViewCount() - mTopRowIdSet.size() - 1;
|
||||
}
|
||||
|
||||
protected void onTaskStackUpdated() {
|
||||
// Lazily update the empty message only when the task stack is reapplied
|
||||
updateEmptyMessage();
|
||||
@@ -3170,7 +3184,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
* Returns all the tasks in the bottom row, without the focused task
|
||||
*/
|
||||
private IntArray getBottomRowIdArray() {
|
||||
int bottomRowIdArraySize = getTaskViewCount() - mTopRowIdSet.size() - 1;
|
||||
int bottomRowIdArraySize = getBottomRowTaskCountForTablet();
|
||||
if (bottomRowIdArraySize <= 0) {
|
||||
return new IntArray(0);
|
||||
}
|
||||
|
||||
@@ -146,7 +146,8 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
|
||||
// Test dismissing all tasks.
|
||||
mLauncher.pressHome().switchToOverview().dismissAllTasks();
|
||||
waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
|
||||
assertTrue("Launcher internal state is not Home",
|
||||
isInState(() -> LauncherState.NORMAL));
|
||||
executeOnLauncher(
|
||||
launcher -> assertEquals("Still have tasks after dismissing all",
|
||||
0, getTaskCount(launcher)));
|
||||
@@ -180,6 +181,14 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
return launcher.<RecentsView>getOverviewPanel().getTaskViewCount();
|
||||
}
|
||||
|
||||
private int getTopRowTaskCountForTablet(Launcher launcher) {
|
||||
return launcher.<RecentsView>getOverviewPanel().getTopRowTaskCountForTablet();
|
||||
}
|
||||
|
||||
private int getBottomRowTaskCountForTablet(Launcher launcher) {
|
||||
return launcher.<RecentsView>getOverviewPanel().getBottomRowTaskCountForTablet();
|
||||
}
|
||||
|
||||
@Test
|
||||
@NavigationModeSwitch
|
||||
@PortraitLandscape
|
||||
@@ -276,4 +285,70 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
isTestActivityRunning(2));
|
||||
getAndAssertBackground();
|
||||
}
|
||||
|
||||
@Test
|
||||
@PortraitLandscape
|
||||
public void testOverviewForTablet() throws Exception {
|
||||
if (!mLauncher.isTablet()) {
|
||||
return;
|
||||
}
|
||||
for (int i = 2; i <= 12; i++) {
|
||||
startTestActivity(i);
|
||||
}
|
||||
|
||||
Overview overview = mLauncher.pressHome().switchToOverview();
|
||||
executeOnLauncher(
|
||||
launcher -> assertTrue("Don't have at least 11 tasks",
|
||||
getTaskCount(launcher) >= 11));
|
||||
|
||||
// Test scroll the first task off screen
|
||||
overview.scrollCurrentTaskOffScreen();
|
||||
assertTrue("Launcher internal state is not Overview",
|
||||
isInState(() -> LauncherState.OVERVIEW));
|
||||
executeOnLauncher(launcher -> assertTrue("Current task in Overview is still 0",
|
||||
getCurrentOverviewPage(launcher) > 0));
|
||||
|
||||
// Test opening the task.
|
||||
overview.getCurrentTask().open();
|
||||
assertTrue("Test activity didn't open from Overview",
|
||||
mDevice.wait(Until.hasObject(By.pkg(getAppPackageName()).text("TestActivity8")),
|
||||
DEFAULT_UI_TIMEOUT));
|
||||
|
||||
// Scroll the task offscreen as it is now first
|
||||
overview = mLauncher.pressHome().switchToOverview();
|
||||
overview.scrollCurrentTaskOffScreen();
|
||||
assertTrue("Launcher internal state is not Overview",
|
||||
isInState(() -> LauncherState.OVERVIEW));
|
||||
executeOnLauncher(launcher -> assertTrue("Current task in Overview is still 0",
|
||||
getCurrentOverviewPage(launcher) > 0));
|
||||
|
||||
// Test dismissing the later task.
|
||||
final Integer numTasks = getFromLauncher(this::getTaskCount);
|
||||
overview.getCurrentTask().dismiss();
|
||||
executeOnLauncher(
|
||||
launcher -> assertEquals("Dismissing a task didn't remove 1 task from Overview",
|
||||
numTasks - 1, getTaskCount(launcher)));
|
||||
executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after dismissal",
|
||||
(Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet(
|
||||
launcher)) <= 1)));
|
||||
|
||||
// Test dismissing more tasks.
|
||||
assertTrue("Launcher internal state didn't remain in Overview",
|
||||
isInState(() -> LauncherState.OVERVIEW));
|
||||
overview.getCurrentTask().dismiss();
|
||||
assertTrue("Launcher internal state didn't remain in Overview",
|
||||
isInState(() -> LauncherState.OVERVIEW));
|
||||
overview.getCurrentTask().dismiss();
|
||||
executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals",
|
||||
(Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet(
|
||||
launcher)) <= 1)));
|
||||
|
||||
// Test dismissing all tasks.
|
||||
mLauncher.pressHome().switchToOverview().dismissAllTasks();
|
||||
assertTrue("Launcher internal state is not Home",
|
||||
isInState(() -> LauncherState.NORMAL));
|
||||
executeOnLauncher(
|
||||
launcher -> assertEquals("Still have tasks after dismissing all",
|
||||
0, getTaskCount(launcher)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,8 @@ public final class TestProtocol {
|
||||
public static final String REQUEST_GET_ACTIVITIES = "get-activities";
|
||||
public static final String REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET =
|
||||
"get-focused-task-height-for-tablet";
|
||||
public static final String REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET =
|
||||
"get-grid-task-size-rect-for-tablet";
|
||||
|
||||
public static Long sForcePauseTimeout;
|
||||
public static final String REQUEST_SET_FORCE_PAUSE_TIMEOUT = "set-force-pause-timeout";
|
||||
|
||||
@@ -145,6 +145,16 @@
|
||||
<meta-data android:name="android.app.shortcuts"
|
||||
android:resource="@xml/shortcuts"/>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.android.launcher3.testcomponent.OtherBaseTestingActivity"
|
||||
android:label="OtherLauncherTestApp"
|
||||
android:exported="true"
|
||||
android:taskAffinity="com.android.launcher3.testcomponent.Affinity2">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity-alias android:name="Activity2"
|
||||
android:label="TestActivity2"
|
||||
android:exported="true"
|
||||
@@ -208,31 +218,36 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity9"
|
||||
android:label="TestActivity9"
|
||||
android:exported="true"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<activity-alias android:name="Activity9" android:exported="true"
|
||||
android:label="TestActivity9"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity10"
|
||||
android:label="TestActivity10"
|
||||
android:exported="true"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<activity-alias android:name="Activity10" android:exported="true"
|
||||
android:label="TestActivity10"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity11"
|
||||
android:label="TestActivity11"
|
||||
android:exported="true"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
|
||||
<activity-alias android:name="Activity11" android:exported="true"
|
||||
android:label="TestActivity11"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity-alias android:name="Activity12" android:exported="true"
|
||||
android:label="TestActivity12"
|
||||
android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
</application>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.testcomponent;
|
||||
|
||||
/**
|
||||
* Extension of BaseTestingActivity to help test many activities open at once.
|
||||
*/
|
||||
public class OtherBaseTestingActivity extends BaseTestingActivity {}
|
||||
@@ -25,6 +25,7 @@ import androidx.test.uiautomator.UiObject2;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Common overview panel for both Launcher and fallback recents
|
||||
@@ -53,14 +54,18 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
|
||||
}
|
||||
|
||||
private void flingForwardImpl() {
|
||||
flingForwardImpl(0);
|
||||
}
|
||||
|
||||
private void flingForwardImpl(int rightMargin) {
|
||||
try (LauncherInstrumentation.Closable c =
|
||||
mLauncher.addContextLayer("want to fling forward in overview")) {
|
||||
LauncherInstrumentation.log("Overview.flingForward before fling");
|
||||
final UiObject2 overview = verifyActiveContainer();
|
||||
final int leftMargin =
|
||||
mLauncher.getTargetInsets().left + mLauncher.getEdgeSensitivityWidth();
|
||||
mLauncher.scroll(
|
||||
overview, Direction.LEFT, new Rect(leftMargin + 1, 0, 0, 0), 20, false);
|
||||
mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin + 1, 0, rightMargin, 0),
|
||||
20, false);
|
||||
try (LauncherInstrumentation.Closable c2 =
|
||||
mLauncher.addContextLayer("flung forwards")) {
|
||||
verifyActiveContainer();
|
||||
@@ -86,6 +91,8 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
|
||||
|
||||
mLauncher.clickLauncherObject(
|
||||
mLauncher.waitForObjectInContainer(verifyActiveContainer(), clearAllSelector));
|
||||
|
||||
mLauncher.waitUntilLauncherObjectGone(clearAllSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +117,40 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the current task via flinging forward until it is off screen.
|
||||
*
|
||||
* If only one task is present, it is only partially scrolled off screen and will still be
|
||||
* the current task.
|
||||
*/
|
||||
public void scrollCurrentTaskOffScreen() {
|
||||
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
|
||||
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"want to scroll current task off screen in overview")) {
|
||||
verifyActiveContainer();
|
||||
|
||||
OverviewTask task = getCurrentTask();
|
||||
mLauncher.assertNotNull("current task is null", task);
|
||||
flingForwardImpl(task.getTaskCenterX());
|
||||
|
||||
try (LauncherInstrumentation.Closable c2 =
|
||||
mLauncher.addContextLayer("scrolled task off screen")) {
|
||||
verifyActiveContainer();
|
||||
verifyActionsViewVisibility();
|
||||
|
||||
if (getTaskCount() > 1) {
|
||||
if (mLauncher.isTablet()) {
|
||||
mLauncher.assertTrue("current task is not grid height",
|
||||
getCurrentTask().getVisibleHeight() == mLauncher
|
||||
.getGridTaskRectForTablet().height());
|
||||
}
|
||||
mLauncher.assertTrue("Current task not scrolled off screen",
|
||||
!getCurrentTask().equals(task));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current task in the carousel, or fails if the carousel is empty.
|
||||
*
|
||||
@@ -130,6 +171,20 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
|
||||
return new OverviewTask(mLauncher, widestTask, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all tasks fully visible in the tablet grid overview.
|
||||
*/
|
||||
@NonNull
|
||||
public List<OverviewTask> getCurrentTasksForTablet() {
|
||||
final List<UiObject2> taskViews = getTasks();
|
||||
mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
|
||||
|
||||
final int gridTaskWidth = mLauncher.getGridTaskRectForTablet().width();
|
||||
|
||||
return taskViews.stream().filter(t -> t.getVisibleBounds().width() == gridTaskWidth).map(
|
||||
t -> new OverviewTask(mLauncher, t, this)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<UiObject2> getTasks() {
|
||||
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
@@ -166,11 +221,18 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if clear all button is visible.
|
||||
*/
|
||||
public boolean isClearAllVisible() {
|
||||
return mLauncher.hasLauncherObject(mLauncher.getOverviewObjectSelector("clear_all"));
|
||||
}
|
||||
|
||||
/* TODO(b/197630182): Once b/188790554 is fixed, remove instanceof check. Currently, when
|
||||
swiping from app to overview in Fallback Recents, taskbar remains and no action buttons
|
||||
are visible, so we are only testing Overview for now, not BaseOverview. */
|
||||
private void verifyActionsViewVisibility() {
|
||||
if (!(this instanceof Overview)) {
|
||||
if (!(this instanceof Overview) || !hasTasks()) {
|
||||
return;
|
||||
}
|
||||
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
@@ -198,8 +260,13 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
|
||||
|
||||
/**
|
||||
* Returns Overview focused task if it exists.
|
||||
*
|
||||
* @throws IllegalStateException if not run on a tablet device.
|
||||
*/
|
||||
UiObject2 getFocusedTaskForTablet() {
|
||||
if (!mLauncher.isTablet()) {
|
||||
throw new IllegalStateException("Must be run on tablet device.");
|
||||
}
|
||||
final List<UiObject2> taskViews = getTasks();
|
||||
if (taskViews.size() == 0) {
|
||||
return null;
|
||||
|
||||
@@ -326,6 +326,11 @@ public final class LauncherInstrumentation {
|
||||
TestProtocol.TEST_INFO_RESPONSE_FIELD);
|
||||
}
|
||||
|
||||
Rect getGridTaskRectForTablet() {
|
||||
return ((Rect) getTestInfo(TestProtocol.REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET)
|
||||
.getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD));
|
||||
}
|
||||
|
||||
float getExactScreenCenterX() {
|
||||
return getRealDisplaySize().x / 2f;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ import androidx.test.uiautomator.UiObject2;
|
||||
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A recent task in the overview panel carousel.
|
||||
@@ -47,10 +49,14 @@ public final class OverviewTask {
|
||||
mOverview.verifyActiveContainer();
|
||||
}
|
||||
|
||||
private int getVisibleHeight() {
|
||||
int getVisibleHeight() {
|
||||
return mTask.getVisibleBounds().height();
|
||||
}
|
||||
|
||||
int getTaskCenterX() {
|
||||
return mTask.getVisibleCenter().x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismisses the task by swiping up.
|
||||
*/
|
||||
@@ -68,6 +74,8 @@ public final class OverviewTask {
|
||||
|
||||
boolean taskWasFocused = mLauncher.isTablet() && getVisibleHeight() == mLauncher
|
||||
.getFocusedTaskHeightForTablet();
|
||||
List<Integer> originalTasksCenterX = getCurrentTasksCenterXList();
|
||||
boolean isClearAllVisibleBeforeDismiss = mOverview.isClearAllVisible();
|
||||
|
||||
dismissBySwipingUp();
|
||||
|
||||
@@ -76,6 +84,16 @@ public final class OverviewTask {
|
||||
mLauncher.assertNotNull("No task became focused",
|
||||
mOverview.getFocusedTaskForTablet());
|
||||
}
|
||||
if (!isClearAllVisibleBeforeDismiss) {
|
||||
List<Integer> currentTasksCenterX = getCurrentTasksCenterXList();
|
||||
if (originalTasksCenterX.size() == currentTasksCenterX.size()) {
|
||||
// Check for the same number of visible tasks before and after to
|
||||
// avoid asserting on cases of shifting all tasks to close the distance
|
||||
// between clear all and tasks at the end of the grid.
|
||||
mLauncher.assertTrue("Task centers not aligned",
|
||||
originalTasksCenterX.equals(currentTasksCenterX));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,6 +112,14 @@ public final class OverviewTask {
|
||||
+ centerY, "swiping to dismiss");
|
||||
}
|
||||
|
||||
private List<Integer> getCurrentTasksCenterXList() {
|
||||
return mLauncher.isTablet()
|
||||
? mOverview.getCurrentTasksForTablet().stream()
|
||||
.map(OverviewTask::getTaskCenterX)
|
||||
.collect(Collectors.toList())
|
||||
: List.of(mOverview.getCurrentTask().getTaskCenterX());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks at the task.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user