From 1ceac5ddfe8cfb6e427b4d8c0a1fdb32557e61a0 Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Tue, 30 Jul 2024 16:04:32 +0100 Subject: [PATCH] Implement e2e test for desktop windowing Code changes: - TaskView, GroupedTaskView and DesktopTaskView now uses different resId, so it can be differentiated by TAPL - Extracted result handling of icon loading, so we can override in DesktopTaskView - DesktopTaskView now load icons, so titleDescription can be loaded. When icons are loaded, contentDescription are applied to respective snapshotViews; icon unloading is ignored - Track launchDesktopFromRecents and composeRecentsLaunchAnimator in TAPL events so we can test if the TaskView launch path is correct Test changes: - Added TaplTestsOverviewDesktop that move 2 TestActivities into Desktop, and launch the DesktopTaskView as static and live tile - TaplTestsOverviewDesktop is limited to Tangor/cf_tablet only, and added LimitDeviceRule to AbstractLauncherUiTest to enable @AllowedDevices and @IgnoreLimit TAPL changes (2 APIs added/modified): - Changed TaskView matcher to use id/task_view_* to match all TaskView types - When Overview is launcehd from Background, mark the currentTask after the launch as liveTile. When an OverviewTask has the same accessibility node as the liveTile, it'll expect different event when launching. - [API change] BaseOverview.getTestActivityTask can now matches mutiple test activiites, useful for matching GroupedTaskView and DesktopTaskView; Fix a bug that getTestActivityTask wrongly use `getParent()` which is RecentsView to match activityName. - In OverviewTask.open, we'll expect different events based on TaskView types and whether it's a live tile. Launching DesktopTaskView will in additional verify Desktop header is present on screen. - [API change] In OverviewTaskMenu, support tapping Desktop menu and verify Desktop header is present on screen. - Removed unused OverviewTaskMenuItem Fix: 320313527 Test: TaplTestsOverviewDesktop Flag: com.android.window.flags.enable_desktop_windowing_mode Change-Id: I89261c787364901320f3acb18f01ddad5f62d17c --- quickstep/res/layout/task.xml | 2 +- quickstep/res/layout/task_desktop.xml | 2 +- quickstep/res/layout/task_grouped.xml | 2 +- .../quickstep/views/DesktopTaskView.kt | 17 ++- .../com/android/quickstep/views/TaskView.kt | 31 ++++-- .../quickstep/TaplTestsOverviewDesktop.kt | 105 ++++++++++++++++++ .../launcher3/ui/AbstractLauncherUiTest.java | 4 + .../android/launcher3/tapl/Background.java | 6 +- .../android/launcher3/tapl/BaseOverview.java | 86 ++++++++++---- .../launcher3/tapl/LaunchedAppState.java | 15 +++ .../tapl/LauncherInstrumentation.java | 2 +- .../com/android/launcher3/tapl/Overview.java | 7 +- .../android/launcher3/tapl/OverviewTask.java | 43 ++++++- .../launcher3/tapl/OverviewTaskMenu.java | 31 ++++-- .../launcher3/tapl/OverviewTaskMenuItem.java | 39 ------- 15 files changed, 302 insertions(+), 90 deletions(-) create mode 100644 quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt delete mode 100644 tests/tapl/com/android/launcher3/tapl/OverviewTaskMenuItem.java diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml index ac1a50a5d8..34193d34c6 100644 --- a/quickstep/res/layout/task.xml +++ b/quickstep/res/layout/task.xml @@ -19,7 +19,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:launcher="http://schemas.android.com/apk/res-auto" - android:id="@+id/task" + android:id="@+id/task_view_single" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml index 64aa7e14ed..8c7090e41a 100644 --- a/quickstep/res/layout/task_desktop.xml +++ b/quickstep/res/layout/task_desktop.xml @@ -19,7 +19,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:launcher="http://schemas.android.com/apk/res-auto" - android:id="@+id/task" + android:id="@+id/task_view_desktop" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="true" diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml index da2b29f9c6..cb4b98fd4c 100644 --- a/quickstep/res/layout/task_grouped.xml +++ b/quickstep/res/layout/task_grouped.xml @@ -24,7 +24,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:launcher="http://schemas.android.com/apk/res-auto" - android:id="@+id/task" + android:id="@+id/task_view_grouped" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt index 9ce2277b14..384945b34c 100644 --- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt +++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt @@ -30,6 +30,8 @@ import android.view.ViewGroup import androidx.core.view.updateLayoutParams import com.android.launcher3.Flags.enableRefactorTaskThumbnail import com.android.launcher3.R +import com.android.launcher3.testing.TestLogging +import com.android.launcher3.testing.shared.TestProtocol import com.android.launcher3.util.RunnableList import com.android.launcher3.util.SplitConfigurationOptions import com.android.launcher3.util.TransformingTouchDelegate @@ -213,7 +215,15 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu } override fun needsUpdate(dataChange: Int, flag: Int) = - if (flag == FLAG_UPDATE_THUMBNAIL) super.needsUpdate(dataChange, flag) else false + if (flag == FLAG_UPDATE_CORNER_RADIUS) false else super.needsUpdate(dataChange, flag) + + override fun onIconLoaded(taskContainer: TaskContainer) { + // Update contentDescription of snapshotView only, individual task icon is unused. + taskContainer.snapshotView.contentDescription = taskContainer.task.titleDescription + } + + // Ignoring [onIconUnloaded] as all tasks shares the same Desktop icon + override fun onIconUnloaded(taskContainer: TaskContainer) {} // thumbnailView is laid out differently and is handled in onMeasure override fun updateThumbnailSize() {} @@ -228,6 +238,11 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu override fun launchTaskAnimated(): RunnableList? { val recentsView = recentsView ?: return null + TestLogging.recordEvent( + TestProtocol.SEQUENCE_MAIN, + "launchDesktopFromRecents", + taskIds.contentToString() + ) val endCallback = RunnableList() val desktopController = recentsView.desktopRecentsController checkNotNull(desktopController) { "recentsController is null" } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index e189d14527..99574a6645 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -868,18 +868,11 @@ constructor( it.task.icon = icon it.task.titleDescription = contentDescription it.task.title = title - setIcon(it.iconView, icon) - if (enableOverviewIconMenu()) { - setText(it.iconView, title) - } - it.digitalWellBeingToast?.initialize(it.task) + onIconLoaded(it) } ?.also { request -> pendingIconLoadRequests.add(request) } } else { - setIcon(it.iconView, null) - if (enableOverviewIconMenu()) { - setText(it.iconView, null) - } + onIconUnloaded(it) } } } @@ -898,6 +891,21 @@ constructor( pendingIconLoadRequests.clear() } + protected open fun onIconLoaded(taskContainer: TaskContainer) { + setIcon(taskContainer.iconView, taskContainer.task.icon) + if (enableOverviewIconMenu()) { + setText(taskContainer.iconView, taskContainer.task.title) + } + taskContainer.digitalWellBeingToast?.initialize(taskContainer.task) + } + + protected open fun onIconUnloaded(taskContainer: TaskContainer) { + setIcon(taskContainer.iconView, null) + if (enableOverviewIconMenu()) { + setText(taskContainer.iconView, null) + } + } + protected fun setIcon(iconView: TaskViewIcon, icon: Drawable?) { with(iconView) { if (icon != null) { @@ -1119,6 +1127,11 @@ constructor( isClickableAsLiveTile = true return runnableList } + TestLogging.recordEvent( + TestProtocol.SEQUENCE_MAIN, + "composeRecentsLaunchAnimator", + taskIds.contentToString() + ) val runnableList = RunnableList() with(AnimatorSet()) { TaskViewUtils.composeRecentsLaunchAnimator( diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt new file mode 100644 index 0000000000..694a3822fe --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2024 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.quickstep + +import android.platform.test.rule.AllowedDevices +import android.platform.test.rule.DeviceProduct +import android.platform.test.rule.IgnoreLimit +import androidx.test.uiautomator.By +import androidx.test.uiautomator.Until +import com.android.launcher3.BuildConfig +import com.android.launcher3.ui.AbstractLauncherUiTest +import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape +import com.android.launcher3.uioverrides.QuickstepLauncher +import com.google.common.truth.Truth.assertWithMessage +import org.junit.Before +import org.junit.Test + +/** Test Desktop windowing in Overview. */ +@AllowedDevices(allowed = [DeviceProduct.CF_TABLET, DeviceProduct.TANGORPRO]) +@IgnoreLimit(ignoreLimit = BuildConfig.IS_STUDIO_BUILD) +class TaplTestsOverviewDesktop : AbstractLauncherUiTest() { + @Before + fun setup() { + val overview = mLauncher.goHome().switchToOverview() + if (overview.hasTasks()) { + overview.dismissAllTasks() + } + startTestAppsWithCheck() + mLauncher.goHome() + } + + @Test + @PortraitLandscape + fun enterDesktopViaOverviewMenu() { + // Move last launched TEST_ACTIVITY_2 into Desktop + mLauncher.workspace + .switchToOverview() + .getTestActivityTask(TEST_ACTIVITY_2) + .tapMenu() + .tapDesktopMenuItem() + assertTestAppLaunched(TEST_ACTIVITY_2) + + // Scroll back to TEST_ACTIVITY_1, then move it into Desktop + mLauncher + .goHome() + .switchToOverview() + .apply { flingForward() } + .getTestActivityTask(TEST_ACTIVITY_1) + .tapMenu() + .tapDesktopMenuItem() + TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) } + + // Launch static DesktopTaskView + val desktop = + mLauncher.goHome().switchToOverview().getTestActivityTask(TEST_ACTIVITIES).open() + TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) } + + // Launch live-tile DesktopTaskView + desktop.switchToOverview().getTestActivityTask(TEST_ACTIVITIES).open() + TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) } + } + + private fun startTestAppsWithCheck() { + TEST_ACTIVITIES.forEach { + startTestActivity(it) + executeOnLauncher { launcher -> + assertWithMessage( + "Launcher activity is the top activity; expecting TestActivity$it" + ) + .that(isInLaunchedApp(launcher)) + .isTrue() + } + } + } + + private fun assertTestAppLaunched(index: Int) { + assertWithMessage("TestActivity$index not opened in Desktop") + .that( + mDevice.wait( + Until.hasObject(By.pkg(getAppPackageName()).text("TestActivity$index")), + DEFAULT_UI_TIMEOUT + ) + ) + .isTrue() + } + + companion object { + const val TEST_ACTIVITY_1 = 2 + const val TEST_ACTIVITY_2 = 3 + val TEST_ACTIVITIES = listOf(TEST_ACTIVITY_1, TEST_ACTIVITY_2) + } +} diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 1e2744c3aa..749a75aaa1 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -43,6 +43,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.flag.junit.SetFlagsRule; +import android.platform.test.rule.LimitDevicesRule; import android.system.OsConstants; import android.util.Log; @@ -222,6 +223,9 @@ public abstract class AbstractLauncherUiTest { @Rule public ExtendedLongPressTimeoutRule mLongPressTimeoutRule = new ExtendedLongPressTimeoutRule(); + @Rule + public LimitDevicesRule mlimitDevicesRule = new LimitDevicesRule(); + public static void initialize(AbstractLauncherUiTest test) throws Exception { test.reinitializeLauncherData(); test.mDevice.pressHome(); diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java index 988aa94c28..b7ebfcd0d6 100644 --- a/tests/tapl/com/android/launcher3/tapl/Background.java +++ b/tests/tapl/com/android/launcher3/tapl/Background.java @@ -16,7 +16,7 @@ package com.android.launcher3.tapl; -import static com.android.launcher3.tapl.BaseOverview.TASK_RES_ID; +import static com.android.launcher3.tapl.BaseOverview.TASK_SELECTOR; import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT; import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL; @@ -117,10 +117,10 @@ public abstract class Background extends LauncherInstrumentation.VisibleContaine // non-tablet overview, snapshots can be on either side of the swiped // task, but we still check that they become visible after swiping and // pausing. - mLauncher.waitForOverviewObject(TASK_RES_ID); + mLauncher.waitForObjectBySelector(TASK_SELECTOR); if (mLauncher.isTablet()) { List tasks = mLauncher.getDevice().findObjects( - mLauncher.getOverviewObjectSelector(TASK_RES_ID)); + TASK_SELECTOR); final int centerX = mLauncher.getDevice().getDisplayWidth() / 2; mLauncher.assertTrue( "All tasks not to the left of the swiped task", diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java index 567a8bd1c0..e71b49fcad 100644 --- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java +++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java @@ -19,7 +19,9 @@ package com.android.launcher3.tapl; import static android.view.KeyEvent.KEYCODE_ESCAPE; import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID; +import static com.android.launcher3.tapl.LauncherInstrumentation.log; import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT; +import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName; import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL; import android.graphics.Rect; @@ -35,9 +37,11 @@ import androidx.test.uiautomator.UiObject2; import com.android.launcher3.testing.shared.TestProtocol; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Optional; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -46,7 +50,9 @@ import java.util.stream.Collectors; */ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { private static final String TAG = "BaseOverview"; - protected static final String TASK_RES_ID = "task"; + protected static final BySelector TASK_SELECTOR = By.res(Pattern.compile( + getOverviewPackageName() + + ":id/(task_view_single|task_view_grouped|task_view_desktop)")); private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile( "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0"); private static final Pattern EVENT_ENTER_DOWN = Pattern.compile( @@ -56,10 +62,22 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { private static final int FLINGS_FOR_DISMISS_LIMIT = 40; + private final @Nullable UiObject2 mLiveTileTask; + + BaseOverview(LauncherInstrumentation launcher) { + this(launcher, /*launchedFromApp=*/false); + } + + BaseOverview(LauncherInstrumentation launcher, boolean launchedFromApp) { super(launcher); verifyActiveContainer(); verifyActionsViewVisibility(); + if (launchedFromApp) { + mLiveTileTask = getCurrentTaskUnchecked(); + } else { + mLiveTileTask = null; + } } @Override @@ -79,7 +97,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { private void flingForwardImpl() { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer("want to fling forward in overview")) { - LauncherInstrumentation.log("Overview.flingForward before fling"); + log("Overview.flingForward before fling"); final UiObject2 overview = verifyActiveContainer(); final int leftMargin = mLauncher.getTargetInsets().left + mLauncher.getEdgeSensitivityWidth(); @@ -105,7 +123,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { private void flingBackwardImpl() { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer("want to fling backward in overview")) { - LauncherInstrumentation.log("Overview.flingBackward before fling"); + log("Overview.flingBackward before fling"); final UiObject2 overview = verifyActiveContainer(); final int rightMargin = mLauncher.getTargetInsets().right + mLauncher.getEdgeSensitivityWidth(); @@ -276,37 +294,56 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { */ @NonNull public OverviewTask getCurrentTask() { + UiObject2 currentTask = getCurrentTaskUnchecked(); + mLauncher.assertNotNull("Unable to find a task", currentTask); + return new OverviewTask(mLauncher, currentTask, this); + } + + @Nullable + private UiObject2 getCurrentTaskUnchecked() { final List taskViews = getTasks(); - mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size()); + if (taskViews.isEmpty()) { + return null; + } // The widest, and most top-right task should be the current task - UiObject2 currentTask = Collections.max(taskViews, + return Collections.max(taskViews, Comparator.comparingInt((UiObject2 t) -> t.getVisibleBounds().width()) .thenComparingInt((UiObject2 t) -> t.getVisibleCenter().x) .thenComparing(Comparator.comparing( (UiObject2 t) -> t.getVisibleCenter().y).reversed())); - return new OverviewTask(mLauncher, currentTask, this); } - /** Returns an overview task matching TestActivity {@param activityNumber}. */ + /** + * Returns an overview task that contains the specified test activity in its thumbnails. + * + * @param activityIndex index of TestActivity to match against + */ @NonNull - public OverviewTask getTestActivityTask(int activityNumber) { + public OverviewTask getTestActivityTask(int activityIndex) { + return getTestActivityTask(Collections.singleton(activityIndex)); + } + + /** + * Returns an overview task that contains all the specified test activities in its thumbnails. + * + * @param activityNumbers collection of indices of TestActivity to match against + */ + @NonNull + public OverviewTask getTestActivityTask(Collection activityNumbers) { final List 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); + Optional task = taskViews.stream().filter( + taskView -> activityNumbers.stream().allMatch(activityNumber -> + // TODO(b/239452415): Use equals instead of descEndsWith + taskView.hasObject(By.descEndsWith("TestActivity" + activityNumber)) + )).findFirst(); - return new OverviewTask(mLauncher, task, this); + mLauncher.assertTrue("Unable to find a task with test activities " + activityNumbers + + " from the task list", task.isPresent()); + + return new OverviewTask(mLauncher, task.get(), this); } /** @@ -328,8 +365,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "want to get overview tasks")) { verifyActiveContainer(); - return mLauncher.getDevice().findObjects( - mLauncher.getOverviewObjectSelector(TASK_RES_ID)); + return mLauncher.getDevice().findObjects(TASK_SELECTOR); } } @@ -506,4 +542,10 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { } return null; } + + protected boolean isLiveTile(UiObject2 task) { + // UiObject2.equals returns false even when mLiveTileTask and task have the same node, hence + // compare only hashCode as a workaround. + return mLiveTileTask != null && mLiveTileTask.hashCode() == task.hashCode(); + } } diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java index 200f2fff17..b3ad930659 100644 --- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java +++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java @@ -33,6 +33,7 @@ import android.view.InputDevice; import android.view.MotionEvent; import android.view.ViewConfiguration; +import androidx.annotation.NonNull; import androidx.test.uiautomator.Condition; import androidx.test.uiautomator.UiDevice; @@ -75,6 +76,20 @@ public final class LaunchedAppState extends Background { return false; } + @NonNull + @Override + public BaseOverview switchToOverview() { + try (LauncherInstrumentation.Closable ignored = mLauncher.eventsCheck(); + LauncherInstrumentation.Closable ignored1 = mLauncher.addContextLayer( + "want to switch from background to overview")) { + verifyActiveContainer(); + goToOverviewUnchecked(); + return mLauncher.is3PLauncher() + ? new BaseOverview(mLauncher, /*launchedFromApp=*/true) + : new Overview(mLauncher, /*launchedFromApp=*/true); + } + } + /** * Returns the taskbar. * diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 75c1b24e23..a87406286b 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -1585,7 +1585,7 @@ public final class LauncherInstrumentation { return objects; } - private UiObject2 waitForObjectBySelector(BySelector selector) { + UiObject2 waitForObjectBySelector(BySelector selector) { Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE, "LauncherInstrumentation.waitForObjectBySelector"); final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS); diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java index 50c21368e0..deb27e4f87 100644 --- a/tests/tapl/com/android/launcher3/tapl/Overview.java +++ b/tests/tapl/com/android/launcher3/tapl/Overview.java @@ -22,9 +22,12 @@ import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType; * Overview pane. */ public class Overview extends BaseOverview { - Overview(LauncherInstrumentation launcher) { - super(launcher); + this(launcher, /*launchedFromApp=*/false); + } + + Overview(LauncherInstrumentation launcher, boolean launchedFromApp) { + super(launcher, launchedFromApp); } @Override diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java index 6f420afe78..7a8ab492b5 100644 --- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java +++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java @@ -40,16 +40,23 @@ import java.util.stream.Collectors; 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 TASK_START_EVENT_DESKTOP = Pattern.compile("launchDesktopFromRecents"); + static final Pattern TASK_START_EVENT_LIVE_TILE = Pattern.compile( + "composeRecentsLaunchAnimator"); static final Pattern SPLIT_SELECT_EVENT = Pattern.compile("enterSplitSelect"); static final Pattern SPLIT_START_EVENT = Pattern.compile("launchSplitTasks"); private final LauncherInstrumentation mLauncher; + @NonNull private final UiObject2 mTask; + private final TaskViewType mType; private final BaseOverview mOverview; - OverviewTask(LauncherInstrumentation launcher, UiObject2 task, BaseOverview overview) { + OverviewTask(LauncherInstrumentation launcher, @NonNull UiObject2 task, BaseOverview overview) { mLauncher = launcher; + mLauncher.assertNotNull("task must not be null", task); mTask = task; mOverview = overview; + mType = getType(); verifyActiveContainer(); } @@ -220,7 +227,22 @@ public final class OverviewTask { return new LaunchedAppState(mLauncher); } } else { - mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT); + final Pattern event; + if (mOverview.isLiveTile(mTask)) { + event = TASK_START_EVENT_LIVE_TILE; + } else if (mType == TaskViewType.DESKTOP) { + event = TASK_START_EVENT_DESKTOP; + } else { + event = TASK_START_EVENT; + } + mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, event); + + if (mType == TaskViewType.DESKTOP) { + try (LauncherInstrumentation.Closable ignored = mLauncher.addContextLayer( + "launched desktop")) { + mLauncher.waitForSystemUiObject("desktop_mode_caption"); + } + } return new LaunchedAppState(mLauncher); } } @@ -273,6 +295,17 @@ public final class OverviewTask { return actual.contains(expected); } + private TaskViewType getType() { + String resourceName = mTask.getResourceName(); + if (resourceName.endsWith("task_view_grouped")) { + return TaskViewType.GROUPED; + } else if (resourceName.endsWith("task_view_desktop")) { + return TaskViewType.DESKTOP; + } else { + return TaskViewType.SINGLE; + } + } + /** * Enum used to specify which task is retrieved when it is a split task. */ @@ -292,4 +325,10 @@ public final class OverviewTask { this.iconAppRes = iconAppRes; } } + + private enum TaskViewType { + SINGLE, + GROUPED, + DESKTOP + } } diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java index 902ad5b568..90d32f3249 100644 --- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java +++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java @@ -97,20 +97,35 @@ public class OverviewTaskMenu { } } + /** + * Taps the Desktop item from the overview task menu and returns the LaunchedAppState + * representing the Desktop. + */ + @NonNull + public LaunchedAppState tapDesktopMenuItem() { + try (LauncherInstrumentation.Closable ignored = mLauncher.eventsCheck(); + LauncherInstrumentation.Closable ignored1 = mLauncher.addContextLayer( + "before tapping the desktop menu item")) { + mLauncher.executeAndWaitForLauncherStop( + () -> mLauncher.clickLauncherObject( + mLauncher.findObjectInContainer(mMenu, By.text("Desktop"))), + "tapped desktop menu item"); + + try (LauncherInstrumentation.Closable ignored2 = mLauncher.addContextLayer( + "tapped desktop menu item")) { + mLauncher.waitUntilSystemLauncherObjectGone("overview_panel"); + mLauncher.waitForSystemUiObject("desktop_mode_caption"); + return new LaunchedAppState(mLauncher); + } + } + } + /** Returns true if an item matching the given string is present in the menu. */ public boolean hasMenuItem(String expectedMenuItemText) { UiObject2 menuItem = mLauncher.findObjectInContainer(mMenu, By.text(expectedMenuItemText)); return menuItem != null; } - /** - * Returns the menu item specified by name if present. - */ - public OverviewTaskMenuItem getMenuItemByName(String menuItemName) { - return new OverviewTaskMenuItem(mLauncher, - mLauncher.waitForObjectInContainer(mMenu, By.text(menuItemName))); - } - /** * Taps outside task menu to dismiss it. */ diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenuItem.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenuItem.java deleted file mode 100644 index e3035bf71b..0000000000 --- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenuItem.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2023 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 android.graphics.Rect; - -import androidx.test.uiautomator.UiObject2; - -/** Represents an item in the overview task menu. */ -public class OverviewTaskMenuItem { - - private final LauncherInstrumentation mLauncher; - private final UiObject2 mMenuItem; - - OverviewTaskMenuItem(LauncherInstrumentation launcher, UiObject2 menuItem) { - mLauncher = launcher; - mMenuItem = menuItem; - } - - /** - * Returns this menu item's visible bounds. - */ - public Rect getVisibleBounds() { - return mMenuItem.getVisibleBounds(); - } -}