Loading src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +19 −6 Original line number Diff line number Diff line Loading @@ -477,7 +477,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> } 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(); Loading Loading @@ -536,7 +536,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> 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); Loading Loading @@ -571,7 +571,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> 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 */); Loading Loading @@ -610,6 +610,19 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> (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; Loading Loading @@ -908,7 +921,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> 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); } Loading Loading @@ -1109,7 +1122,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> 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(), Loading Loading @@ -1151,7 +1164,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> /** 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(); } Loading src/com/android/launcher3/testing/TestInformationHandler.java +7 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading src/com/android/launcher3/testing/shared/TestProtocol.java +1 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +3 −4 Original line number Diff line number Diff line Loading @@ -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", Loading Loading @@ -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(); Loading tests/tapl/com/android/launcher3/tapl/AllApps.java +38 −14 Original line number Diff line number Diff line Loading @@ -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; /** Loading Loading @@ -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(); } Loading Loading @@ -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( Loading Loading @@ -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<UiObject2> 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. Loading @@ -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; Loading Loading @@ -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"); } Loading Loading
src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +19 −6 Original line number Diff line number Diff line Loading @@ -477,7 +477,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> } 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(); Loading Loading @@ -536,7 +536,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> 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); Loading Loading @@ -571,7 +571,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> 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 */); Loading Loading @@ -610,6 +610,19 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> (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; Loading Loading @@ -908,7 +921,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> 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); } Loading Loading @@ -1109,7 +1122,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> 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(), Loading Loading @@ -1151,7 +1164,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> /** 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(); } Loading
src/com/android/launcher3/testing/TestInformationHandler.java +7 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading
src/com/android/launcher3/testing/shared/TestProtocol.java +1 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading
tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +3 −4 Original line number Diff line number Diff line Loading @@ -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", Loading Loading @@ -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(); Loading
tests/tapl/com/android/launcher3/tapl/AllApps.java +38 −14 Original line number Diff line number Diff line Loading @@ -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; /** Loading Loading @@ -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(); } Loading Loading @@ -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( Loading Loading @@ -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<UiObject2> 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. Loading @@ -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; Loading Loading @@ -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"); } Loading