mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-01 16:26:47 +00:00
[revert ^2] Enable Floating Search and update tests accordingly.
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: 261873937 Test: Ran tests, manual Change-Id: I406fbcbe12acddb1dd4b862a380576a48cabbebc
This commit is contained in:
@@ -473,7 +473,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();
|
||||
@@ -519,7 +519,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);
|
||||
@@ -554,7 +554,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 */);
|
||||
@@ -593,6 +593,13 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
(int) (mSearchContainer.getAlpha() * 255));
|
||||
}
|
||||
|
||||
/** @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 +898,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);
|
||||
}
|
||||
@@ -1092,7 +1099,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(),
|
||||
@@ -1134,7 +1141,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();
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public final class FeatureFlags {
|
||||
"ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps");
|
||||
|
||||
public static final BooleanFlag ENABLE_FLOATING_SEARCH_BAR =
|
||||
getDebugFlag("ENABLE_FLOATING_SEARCH_BAR", false,
|
||||
new DeviceFlag("ENABLE_FLOATING_SEARCH_BAR", true,
|
||||
"Keep All Apps search bar at the bottom (but above keyboard if open)");
|
||||
|
||||
public static final BooleanFlag ENABLE_HIDE_HEADER = new DeviceFlag("ENABLE_HIDE_HEADER",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<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.
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
@@ -1490,19 +1488,21 @@ public final class LauncherInstrumentation {
|
||||
}
|
||||
|
||||
void scrollToLastVisibleRow(
|
||||
UiObject2 container, Collection<UiObject2> 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(
|
||||
@@ -1512,7 +1512,7 @@ public final class LauncherInstrumentation {
|
||||
0,
|
||||
containerRect.height() - distance - bottomGestureMarginInContainer,
|
||||
0,
|
||||
bottomGestureMarginInContainer),
|
||||
bottomGestureMarginInContainer + bottomPadding),
|
||||
/* steps= */ 10,
|
||||
/* slowDown= */ true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user