From 8d004b0f49466028e2432d90f3dbc05c5a1defdd Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Tue, 31 Jan 2023 21:26:15 +0000 Subject: [PATCH] Update tests to support floating search. Tests need to be updated to account for the new placement of the searchbar because it overlapped with touch events for scrolling: - Scroll back to top: Instead of scrolling from the top of the container which could overlap status bar in landscape, scroll from the bottom of the top-most visible app icon. - Scroll down: swipe up from bottom padding to top of top-most visible icon. - Close all apps: swipe down more quickly from top icon insetad of the search bar (more quickly helps it be detected as a fling on more cramped devices). For Launcher3, the floating flag is not fully supported yet, so there were some layout issues which are now resolved by ignoring the flag if the searchbar is still at the top. Fix: 268052768 Test: Ran tests, manual Change-Id: If54717e2835c7cc4ed1368554bbc493193945c1d Merged-In: I406fbcbe12acddb1dd4b862a380576a48cabbebc --- .../allapps/ActivityAllAppsContainerView.java | 25 ++++++--- .../testing/TestInformationHandler.java | 7 +++ .../testing/shared/TestProtocol.java | 1 + .../launcher3/ui/TaplTestsLauncher3.java | 7 ++- .../com/android/launcher3/tapl/AllApps.java | 52 ++++++++++++++----- .../android/launcher3/tapl/HomeAllApps.java | 12 ++--- .../tapl/LauncherInstrumentation.java | 18 +++---- 7 files changed, 80 insertions(+), 42 deletions(-) diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java index da4739882a..3b6fd46251 100644 --- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java @@ -473,7 +473,7 @@ public class ActivityAllAppsContainerView } setupHeader(); - if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) { + if (isSearchBarOnBottom()) { // Keep the scroller above the search bar. RelativeLayout.LayoutParams scrollerLayoutParams = (LayoutParams) findViewById(R.id.fast_scroller).getLayoutParams(); @@ -519,7 +519,7 @@ public class ActivityAllAppsContainerView removeCustomRules(getSearchRecyclerView()); if (!isSearchSupported()) { layoutWithoutSearchContainer(rvContainer, showTabs); - } else if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) { + } else if (isSearchBarOnBottom()) { alignParentTop(rvContainer, showTabs); alignParentTop(getSearchRecyclerView(), /* tabs= */ false); layoutAboveSearchContainer(rvContainer); @@ -554,7 +554,7 @@ public class ActivityAllAppsContainerView removeCustomRules(mHeader); if (!isSearchSupported()) { layoutWithoutSearchContainer(mHeader, false /* includeTabsMargin */); - } else if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) { + } else if (isSearchBarOnBottom()) { alignParentTop(mHeader, false /* includeTabsMargin */); } else { layoutBelowSearchContainer(mHeader, false /* includeTabsMargin */); @@ -593,6 +593,19 @@ public class ActivityAllAppsContainerView (int) (mSearchContainer.getAlpha() * 255)); } + /** + * It is up to the search container view created by {@link #inflateSearchBox()} to use the + * floating search bar flag to move itself to the bottom of this container. This method checks + * if that had been done; otherwise the flag will be ignored. + * + * @return true if the search bar is at the bottom of the container (as opposed to the top). + **/ + private boolean isSearchBarOnBottom() { + return FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() + && ((RelativeLayout.LayoutParams) mSearchContainer.getLayoutParams()).getRule( + ALIGN_PARENT_BOTTOM) == RelativeLayout.TRUE; + } + private void layoutBelowSearchContainer(View v, boolean includeTabsMargin) { if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) { return; @@ -891,7 +904,7 @@ public class ActivityAllAppsContainerView setPadding(grid.workspacePadding.left, 0, grid.workspacePadding.right, 0); } else { int topPadding = grid.allAppsTopPadding; - if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() && !grid.isTablet) { + if (isSearchBarOnBottom() && !grid.isTablet) { topPadding += getResources().getDimensionPixelSize( R.dimen.all_apps_additional_top_padding_floating_search); } @@ -1092,7 +1105,7 @@ public class ActivityAllAppsContainerView FloatingHeaderView headerView = getFloatingHeaderView(); if (isTablet) { // Start adding header protection if search bar or tabs will attach to the top. - if (!FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() || mUsingTabs) { + if (!isSearchBarOnBottom() || mUsingTabs) { View panel = (View) mBottomSheetBackground; float translationY = ((View) panel.getParent()).getTranslationY(); mTmpRectF.set(panel.getLeft(), panel.getTop() + translationY, panel.getRight(), @@ -1134,7 +1147,7 @@ public class ActivityAllAppsContainerView /** Returns the position of the bottom edge of the header */ public int getHeaderBottom() { int bottom = (int) getTranslationY() + mHeader.getClipTop(); - if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) { + if (isSearchBarOnBottom()) { if (mActivityContext.getDeviceProfile().isTablet) { return bottom + mBottomSheetBackground.getTop(); } diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index 9a34478918..d3d644a083 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -232,6 +232,13 @@ public class TestInformationHandler implements ResourceBasedOverride { l -> l.getAppsView().getActiveRecyclerView().getClipBounds().top); } + case TestProtocol.REQUEST_ALL_APPS_BOTTOM_PADDING: { + return getLauncherUIProperty(Bundle::putInt, + l -> l.getAppsView().getBottom() + - l.getAppsView().getActiveRecyclerView().getBottom() + + l.getAppsView().getActiveRecyclerView().getPaddingBottom()); + } + default: return null; } diff --git a/src/com/android/launcher3/testing/shared/TestProtocol.java b/src/com/android/launcher3/testing/shared/TestProtocol.java index 9b2ce9a67f..11363a25fe 100644 --- a/src/com/android/launcher3/testing/shared/TestProtocol.java +++ b/src/com/android/launcher3/testing/shared/TestProtocol.java @@ -120,6 +120,7 @@ public final class TestProtocol { public static final String REQUEST_TASKBAR_ALL_APPS_TOP_PADDING = "taskbar-all-apps-top-padding"; public static final String REQUEST_ALL_APPS_TOP_PADDING = "all-apps-top-padding"; + public static final String REQUEST_ALL_APPS_BOTTOM_PADDING = "all-apps-bottom-padding"; public static final String REQUEST_WORKSPACE_CELL_LAYOUT_SIZE = "workspace-cell-layout-size"; public static final String REQUEST_WORKSPACE_CELL_CENTER = "workspace-cell-center"; diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java index 4b04c7e7e2..401c25a4cf 100644 --- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java @@ -169,9 +169,9 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { flingBackwardY < flingForwardY)); // Test scrolling down to YouTube. - assertNotNull("All apps: can't fine YouTube", allApps.getAppIcon("YouTube")); + assertNotNull("All apps: can't find YouTube", allApps.getAppIcon("YouTube")); // Test scrolling up to Camera. - assertNotNull("All apps: can't fine Camera", allApps.getAppIcon("Camera")); + assertNotNull("All apps: can't find Camera", allApps.getAppIcon("Camera")); // Test failing to find a non-existing app. final AllApps allAppsFinal = allApps; expectFail("All apps: could find a non-existing app", @@ -263,8 +263,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { assertNotNull("AppIcon.launch returned null", app.launch(getAppPackageName())); test.executeOnLauncher(launcher -> assertTrue( "Launcher activity is the top activity; expecting another activity to be the " - + "top " - + "one", + + "top one", test.isInLaunchedApp(launcher))); } finally { allApps.unfreeze(); diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index 6f6428ad78..2d4d2cd327 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -34,6 +34,9 @@ import androidx.test.uiautomator.UiObject2; import com.android.launcher3.testing.shared.TestProtocol; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; import java.util.stream.Collectors; /** @@ -102,10 +105,10 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { iconCenter.x, iconCenter.y); } - private boolean iconCenterInRecyclerTopPadding(UiObject2 appListRecycler, UiObject2 icon) { + private boolean iconCenterInRecyclerTopPadding(UiObject2 appsListRecycler, UiObject2 icon) { final Point iconCenter = icon.getVisibleCenter(); - return iconCenter.y <= mLauncher.getVisibleBounds(appListRecycler).top + return iconCenter.y <= mLauncher.getVisibleBounds(appsListRecycler).top + getAppsListRecyclerTopPadding(); } @@ -137,15 +140,11 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { bottomGestureStartOnScreen)) { mLauncher.scrollToLastVisibleRow( allAppsContainer, - mLauncher.getObjectsInContainer(allAppsContainer, "icon") - .stream() - .filter(icon -> - mLauncher.getVisibleBounds(icon).top - < bottomGestureStartOnScreen) - .collect(Collectors.toList()), + getBottomVisibleIconBounds(allAppsContainer), mLauncher.getVisibleBounds(appListRecycler).top + getAppsListRecyclerTopPadding() - - mLauncher.getVisibleBounds(allAppsContainer).top); + - mLauncher.getVisibleBounds(allAppsContainer).top, + getAppsListRecyclerBottomPadding()); verifyActiveContainer(); final int newScroll = getAllAppsScroll(); mLauncher.assertTrue( @@ -175,6 +174,28 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { } } + /** @return visible bounds of the top-most visible icon in the container. */ + protected Rect getTopVisibleIconBounds(UiObject2 allAppsContainer) { + return mLauncher.getVisibleBounds(Collections.min(getVisibleIcons(allAppsContainer), + Comparator.comparingInt(i -> mLauncher.getVisibleBounds(i).top))); + } + + /** @return visible bounds of the bottom-most visible icon in the container. */ + protected Rect getBottomVisibleIconBounds(UiObject2 allAppsContainer) { + return mLauncher.getVisibleBounds(Collections.max(getVisibleIcons(allAppsContainer), + Comparator.comparingInt(i -> mLauncher.getVisibleBounds(i).top))); + } + + @NonNull + private List getVisibleIcons(UiObject2 allAppsContainer) { + return mLauncher.getObjectsInContainer(allAppsContainer, "icon") + .stream() + .filter(icon -> + mLauncher.getVisibleBounds(icon).top + < mLauncher.getBottomGestureStartOnScreen()) + .collect(Collectors.toList()); + } + /** * Finds an icon. Fails if the icon doesn't exist. Scrolls the app list when needed to make * sure the icon is visible. @@ -196,20 +217,23 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { protected abstract int getAppsListRecyclerTopPadding(); + protected int getAppsListRecyclerBottomPadding() { + return mLauncher.getTestInfo(TestProtocol.REQUEST_ALL_APPS_BOTTOM_PADDING) + .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); + } + private void scrollBackToBeginning() { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "want to scroll back in all apps")) { LauncherInstrumentation.log("Scrolling to the beginning"); final UiObject2 allAppsContainer = verifyActiveContainer(); - final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer); int attempts = 0; final Rect margins = new Rect( /* left= */ 0, - mLauncher.getVisibleBounds(appListRecycler).top - + getAppsListRecyclerTopPadding() + 1, + getTopVisibleIconBounds(allAppsContainer).bottom, /* right= */ 0, - /* bottom= */ 5); + /* bottom= */ getAppsListRecyclerBottomPadding()); for (int scroll = getAllAppsScroll(); scroll != 0; @@ -240,7 +264,7 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); } - private UiObject2 getAppListRecycler(UiObject2 allAppsContainer) { + protected UiObject2 getAppListRecycler(UiObject2 allAppsContainer) { return mLauncher.waitForObjectInContainer(allAppsContainer, "apps_list_view"); } diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java index 50b03aa7df..e0c4c19679 100644 --- a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java @@ -17,15 +17,11 @@ package com.android.launcher3.tapl; import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL; -import android.graphics.Rect; - import androidx.annotation.NonNull; import androidx.test.uiautomator.UiObject2; import com.android.launcher3.testing.shared.TestProtocol; -import java.util.Objects; - public class HomeAllApps extends AllApps { private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background"; @@ -45,10 +41,8 @@ public class HomeAllApps extends AllApps { mLauncher.addContextLayer("want to switch from all apps to workspace")) { UiObject2 allAppsContainer = verifyActiveContainer(); - final Rect searchBoxBounds = Objects.requireNonNull( - mLauncher.getVisibleBounds(getSearchBox(allAppsContainer))); - final int startX = searchBoxBounds.centerX(); - final int startY = searchBoxBounds.bottom; + final int startX = allAppsContainer.getVisibleCenter().x; + final int startY = getTopVisibleIconBounds(allAppsContainer).centerY(); final int endY = mLauncher.getDevice().getDisplayHeight(); LauncherInstrumentation.log( "switchToWorkspace: startY = " + startY + ", endY = " + endY @@ -59,7 +53,7 @@ public class HomeAllApps extends AllApps { startY, startX, endY, - 12 /* steps */, + 5 /* steps */, NORMAL_STATE_ORDINAL, LauncherInstrumentation.GestureScope.INSIDE); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index ae9ba6787b..a3ec03ed1d 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -76,8 +76,6 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; import java.util.Deque; import java.util.LinkedList; import java.util.List; @@ -1485,19 +1483,21 @@ public final class LauncherInstrumentation { } void scrollToLastVisibleRow( - UiObject2 container, Collection items, int topPaddingInContainer) { - final UiObject2 lowestItem = Collections.max(items, (i1, i2) -> - Integer.compare(getVisibleBounds(i1).top, getVisibleBounds(i2).top)); - - final int itemRowCurrentTopOnScreen = getVisibleBounds(lowestItem).top; + UiObject2 container, Rect bottomVisibleIconBounds, int topPaddingInContainer, + int appsListBottomPadding) { + final int itemRowCurrentTopOnScreen = bottomVisibleIconBounds.top; final Rect containerRect = getVisibleBounds(container); final int itemRowNewTopOnScreen = containerRect.top + topPaddingInContainer; final int distance = itemRowCurrentTopOnScreen - itemRowNewTopOnScreen + getTouchSlop(); - scrollDownByDistance(container, distance); + scrollDownByDistance(container, distance, appsListBottomPadding); } void scrollDownByDistance(UiObject2 container, int distance) { + scrollDownByDistance(container, distance, 0); + } + + void scrollDownByDistance(UiObject2 container, int distance, int bottomPadding) { final Rect containerRect = getVisibleBounds(container); final int bottomGestureMarginInContainer = getBottomGestureMarginInContainer(container); scroll( @@ -1507,7 +1507,7 @@ public final class LauncherInstrumentation { 0, containerRect.height() - distance - bottomGestureMarginInContainer, 0, - bottomGestureMarginInContainer), + bottomGestureMarginInContainer + bottomPadding), /* steps= */ 10, /* slowDown= */ true); }