diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java index ea0d1b9785..9fb0e71463 100644 --- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java @@ -477,7 +477,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(); @@ -536,7 +536,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); @@ -571,7 +571,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 */); @@ -610,6 +610,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; @@ -908,7 +921,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); } @@ -1109,7 +1122,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(), @@ -1151,7 +1164,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 2d1c963f9a..52994a50b4 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; @@ -1486,19 +1484,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( @@ -1508,7 +1508,7 @@ public final class LauncherInstrumentation { 0, containerRect.height() - distance - bottomGestureMarginInContainer, 0, - bottomGestureMarginInContainer), + bottomGestureMarginInContainer + bottomPadding), /* steps= */ 10, /* slowDown= */ true); }