Commit de245f04 authored by Stephane Zermatten's avatar Stephane Zermatten Committed by Chromium LUCI CQ

[Autofill Assistant] Add scroll-to-hide to JITT.

With this change when scroll-to-hide is enabled in the JITT UI,
scrolling down on the browser page hides the bottom sheet and scrolling
up reveals it again.

Change-Id: I92f9753b09d25443293e5a1b4cb23bc8c3cfb3d3
Bug: b/171792266
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2599864
Commit-Queue: Stephane Zermatten <szermatt@chromium.org>
Reviewed-by: default avatarClemens Arbesser <arbesser@google.com>
Cr-Commit-Position: refs/heads/master@{#842475}
parent e559586b
...@@ -115,6 +115,7 @@ android_library("java") { ...@@ -115,6 +115,7 @@ android_library("java") {
"java/src/org/chromium/chrome/browser/autofill_assistant/DialogOnboardingCoordinator.java", "java/src/org/chromium/chrome/browser/autofill_assistant/DialogOnboardingCoordinator.java",
"java/src/org/chromium/chrome/browser/autofill_assistant/FeedbackContext.java", "java/src/org/chromium/chrome/browser/autofill_assistant/FeedbackContext.java",
"java/src/org/chromium/chrome/browser/autofill_assistant/LayoutUtils.java", "java/src/org/chromium/chrome/browser/autofill_assistant/LayoutUtils.java",
"java/src/org/chromium/chrome/browser/autofill_assistant/ScrollToHideGestureListener.java",
"java/src/org/chromium/chrome/browser/autofill_assistant/SizeListenableLinearLayout.java", "java/src/org/chromium/chrome/browser/autofill_assistant/SizeListenableLinearLayout.java",
"java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsCarouselCoordinator.java", "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsCarouselCoordinator.java",
"java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsDecoration.java", "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsDecoration.java",
......
...@@ -11,9 +11,11 @@ import android.widget.ScrollView; ...@@ -11,9 +11,11 @@ import android.widget.ScrollView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.chromium.base.Callback;
import org.chromium.base.supplier.Supplier; import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.autofill_assistant.R; import org.chromium.chrome.autofill_assistant.R;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
/** /**
* The {@link BottomSheetContent} for the Autofill Assistant. It supports notifying the * The {@link BottomSheetContent} for the Autofill Assistant. It supports notifying the
...@@ -27,6 +29,9 @@ public class AssistantBottomSheetContent implements BottomSheetContent { ...@@ -27,6 +29,9 @@ public class AssistantBottomSheetContent implements BottomSheetContent {
private ScrollView mContentScrollableView; private ScrollView mContentScrollableView;
private Supplier<AssistantBottomBarDelegate> mBottomBarDelegateSupplier; private Supplier<AssistantBottomBarDelegate> mBottomBarDelegateSupplier;
private boolean mPeekModeDisabled; private boolean mPeekModeDisabled;
private BottomSheetController mController;
@Nullable
private Callback<Integer> mOffsetController;
public AssistantBottomSheetContent( public AssistantBottomSheetContent(
Context context, Supplier<AssistantBottomBarDelegate> supplier) { Context context, Supplier<AssistantBottomBarDelegate> supplier) {
...@@ -151,4 +156,18 @@ public class AssistantBottomSheetContent implements BottomSheetContent { ...@@ -151,4 +156,18 @@ public class AssistantBottomSheetContent implements BottomSheetContent {
return bottomBarDelegate.onBackButtonPressed(); return bottomBarDelegate.onBackButtonPressed();
} }
@Override
public boolean contentControlsOffset() {
return true;
}
@Override
public void setOffsetController(Callback<Integer> offsetController) {
mOffsetController = offsetController;
}
public Callback<Integer> getOffsetController() {
return mOffsetController;
}
} }
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.autofill_assistant;
import android.animation.ValueAnimator;
import android.view.animation.DecelerateInterpolator;
import androidx.annotation.Nullable;
import org.chromium.base.Callback;
import org.chromium.base.MathUtils;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
import org.chromium.content_public.browser.GestureStateListenerWithScroll;
/**
* A Gesture listener that implements scroll-to-hide for the assistant bottomsheet when in FULL
* state.
*/
public class ScrollToHideGestureListener implements GestureStateListenerWithScroll {
/** Base duration of the animation of the sheet. 218 ms is a spec for material design. */
private static final int BASE_ANIMATION_DURATION_MS = 218;
private final BottomSheetController mBottomSheetController;
private final AssistantBottomSheetContent mContent;
@Nullable
private final BottomSheetObserver mStateChangeTracker = new StateChangeTracker();
private boolean mScrolling;
/** Remembers the last value of scroll offset, to compute the delta for the next move. */
private int mLastScrollOffsetY;
/**
* A capture of {@code mBottomSheetController.getCurrentOffset()}. At the end of a scroll, it is
* compared with the current value to figure out whether the sheet was overall scrolled up or
* down.
*/
private float mOffsetMarkPx;
/** This animator moves the sheet to its final position after scrolling ended. */
private ValueAnimator mAnimator;
public ScrollToHideGestureListener(
BottomSheetController bottomSheetController, AssistantBottomSheetContent content) {
mBottomSheetController = bottomSheetController;
mContent = content;
}
@Override
public void onScrollStarted(int scrollOffsetY, int scrollExtentY) {
Callback<Integer> offsetController = mContent.getOffsetController();
if (offsetController == null) return;
// Scroll to hide only applies if the sheet is fully opened, and state is FULL or is being
// opened, and target state is FULL.
if (mBottomSheetController.getTargetSheetState() == SheetState.FULL) {
// This stops animation and freezes the sheet in place.
offsetController.onResult(mBottomSheetController.getCurrentOffset());
}
if (mBottomSheetController.getSheetState() != SheetState.FULL) return;
resetScrollingState(); // also cancels any running animations
mScrolling = true;
mLastScrollOffsetY = scrollOffsetY;
mOffsetMarkPx = mBottomSheetController.getCurrentOffset();
mBottomSheetController.addObserver(mStateChangeTracker);
}
@Override
public void onScrollEnded(int scrollOffsetY, int scrollExtentY) {
onScrollOffsetOrExtentChanged(scrollOffsetY, scrollExtentY);
if (!mScrolling) return;
resetScrollingState();
int maxOffsetPx = getMaxOffsetPx();
int currentOffsetPx = mBottomSheetController.getCurrentOffset();
if (currentOffsetPx == 0 || currentOffsetPx == maxOffsetPx) {
return;
}
if (currentOffsetPx >= mOffsetMarkPx || scrollOffsetY == 0) {
animateTowards(maxOffsetPx);
} else {
animateTowards(0);
}
}
@Override
public void onScrollOffsetOrExtentChanged(int scrollOffsetY, int scrollExtentY) {
if (!mScrolling) {
// It's possible for the scroll offset to reset to 0 outside of a scroll, if the page or
// viewport size change. Scrolling up is not possible so if the sheet is hidden or about
// to be hidden, show it.
if (scrollOffsetY == 0 && mBottomSheetController.getSheetState() == SheetState.FULL
&& (mBottomSheetController.getCurrentOffset() == 0 || mAnimator != null)) {
animateTowards(getMaxOffsetPx());
}
return;
}
Callback<Integer> offsetController = mContent.getOffsetController();
if (offsetController == null) {
resetScrollingState();
return;
}
// deltaPx is the value to add to the current sheet offset (height). It is negative when
// scrolling down, that is, when scrollOffsetY increases.
int deltaPx = mLastScrollOffsetY - scrollOffsetY;
mLastScrollOffsetY = scrollOffsetY;
int maxOffsetPx = getMaxOffsetPx();
int offsetPx = MathUtils.clamp(
mBottomSheetController.getCurrentOffset() + deltaPx, 0, maxOffsetPx);
offsetController.onResult(offsetPx);
// If either extremes were reached, update the mark. The decision to fully show or hide will
// be relative to that point.
if (offsetPx == 0) {
mOffsetMarkPx = 0;
} else if (offsetPx >= maxOffsetPx) {
mOffsetMarkPx = maxOffsetPx;
}
}
@Override
public void onFlingStartGesture(int scrollOffsetY, int scrollExtentY) {
// Flinging and scrolling are handled the same, the sheet follows the movement of the
// browser page.
onScrollStarted(scrollOffsetY, scrollExtentY);
}
@Override
public void onFlingEndGesture(int scrollOffsetY, int scrollExtentY) {
onScrollEnded(scrollOffsetY, scrollExtentY);
}
@Override
public void onDestroyed() {
resetScrollingState();
}
private int getMaxOffsetPx() {
return mContent.getContentView().getHeight() + mBottomSheetController.getTopShadowHeight();
}
private void resetScrollingState() {
mScrolling = false;
mLastScrollOffsetY = 0;
cancelAnimation();
mBottomSheetController.removeObserver(mStateChangeTracker);
}
private void cancelAnimation() {
if (mAnimator == null) return;
mAnimator.cancel();
mAnimator = null;
}
/** Animate the sheet towards {@code goalOffsetPx} without changing its state. */
private void animateTowards(int goalOffsetPx) {
Callback<Integer> offsetController = mContent.getOffsetController();
if (offsetController == null) return;
ValueAnimator animator =
ValueAnimator.ofInt(mBottomSheetController.getCurrentOffset(), goalOffsetPx);
animator.setDuration(BASE_ANIMATION_DURATION_MS);
animator.setInterpolator(new DecelerateInterpolator(1.0f));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
if (mAnimator != animator) return;
offsetController.onResult((Integer) animator.getAnimatedValue());
}
});
mAnimator = animator;
mAnimator.start();
}
/** Stop scrolling if the sheet leaves the FULL state during scrolling. */
private class StateChangeTracker extends EmptyBottomSheetObserver {
@Override
public void onSheetStateChanged(@SheetState int newState) {
if (newState != SheetState.FULL) {
resetScrollingState();
}
}
}
}
...@@ -20,6 +20,7 @@ import org.chromium.chrome.browser.autofill_assistant.AssistantBottomSheetConten ...@@ -20,6 +20,7 @@ import org.chromium.chrome.browser.autofill_assistant.AssistantBottomSheetConten
import org.chromium.chrome.browser.autofill_assistant.AssistantRootViewContainer; import org.chromium.chrome.browser.autofill_assistant.AssistantRootViewContainer;
import org.chromium.chrome.browser.autofill_assistant.BottomSheetUtils; import org.chromium.chrome.browser.autofill_assistant.BottomSheetUtils;
import org.chromium.chrome.browser.autofill_assistant.LayoutUtils; import org.chromium.chrome.browser.autofill_assistant.LayoutUtils;
import org.chromium.chrome.browser.autofill_assistant.ScrollToHideGestureListener;
import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChip; import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChip;
import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChipViewHolder; import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChipViewHolder;
import org.chromium.chrome.browser.autofill_assistant.generic_ui.AssistantDimension; import org.chromium.chrome.browser.autofill_assistant.generic_ui.AssistantDimension;
...@@ -30,6 +31,7 @@ import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; ...@@ -30,6 +31,7 @@ import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver; import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver; import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
import org.chromium.content_public.browser.GestureListenerManager;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.ApplicationViewportInsetSupplier; import org.chromium.ui.base.ApplicationViewportInsetSupplier;
...@@ -60,6 +62,7 @@ public class AssistantTriggerScript { ...@@ -60,6 +62,7 @@ public class AssistantTriggerScript {
private AssistantHeaderCoordinator mHeaderCoordinator; private AssistantHeaderCoordinator mHeaderCoordinator;
private AssistantHeaderModel mHeaderModel; private AssistantHeaderModel mHeaderModel;
private ScrollToHideGestureListener mGestureListener;
private LinearLayout mChipsContainer; private LinearLayout mChipsContainer;
private final int mInnerChipSpacing; private final int mInnerChipSpacing;
/** Height of the bottom sheet's shadow, used to compute the viewport resize offset. */ /** Height of the bottom sheet's shadow, used to compute the viewport resize offset. */
...@@ -152,6 +155,7 @@ public class AssistantTriggerScript { ...@@ -152,6 +155,7 @@ public class AssistantTriggerScript {
} }
public void destroy() { public void destroy() {
disableScrollToHide();
mBottomSheetController.removeObserver(mBottomSheetObserver); mBottomSheetController.removeObserver(mBottomSheetObserver);
if (mHeaderCoordinator != null) { if (mHeaderCoordinator != null) {
mHeaderCoordinator.destroy(); mHeaderCoordinator.destroy();
...@@ -250,7 +254,7 @@ public class AssistantTriggerScript { ...@@ -250,7 +254,7 @@ public class AssistantTriggerScript {
addChipsToContainer(mChipsContainer, mRightAlignedChips); addChipsToContainer(mChipsContainer, mRightAlignedChips);
} }
public boolean show(boolean resizeVisualViewport) { public boolean show(boolean resizeVisualViewport, boolean scrollToHide) {
if (mHeaderModel == null || mHeaderCoordinator == null) { if (mHeaderModel == null || mHeaderCoordinator == null) {
assert false : "createHeaderAndGetModel() must be called before show()"; assert false : "createHeaderAndGetModel() must be called before show()";
return false; return false;
...@@ -262,10 +266,14 @@ public class AssistantTriggerScript { ...@@ -262,10 +266,14 @@ public class AssistantTriggerScript {
mBottomSheetController.addObserver(mBottomSheetObserver); mBottomSheetController.addObserver(mBottomSheetObserver);
BottomSheetUtils.showContentAndMaybeExpand(mBottomSheetController, mContent, BottomSheetUtils.showContentAndMaybeExpand(mBottomSheetController, mContent,
/* shouldExpand = */ true, /* animate = */ mAnimateBottomSheet); /* shouldExpand = */ true, /* animate = */ mAnimateBottomSheet);
if (scrollToHide) enableScrollToHide();
return true; return true;
} }
public void hide() { public void hide() {
disableScrollToHide();
mBottomSheetController.removeObserver(mBottomSheetObserver); mBottomSheetController.removeObserver(mBottomSheetObserver);
mBottomSheetController.hideContent(mContent, /* animate = */ mAnimateBottomSheet); mBottomSheetController.hideContent(mContent, /* animate = */ mAnimateBottomSheet);
mResizeVisualViewport = false; mResizeVisualViewport = false;
...@@ -297,4 +305,18 @@ public class AssistantTriggerScript { ...@@ -297,4 +305,18 @@ public class AssistantTriggerScript {
mInsetSupplier.set(resizing); mInsetSupplier.set(resizing);
} }
private void disableScrollToHide() {
if (mGestureListener == null) return;
GestureListenerManager.fromWebContents(mWebContents).removeListener(mGestureListener);
mGestureListener = null;
}
private void enableScrollToHide() {
if (mGestureListener != null) return;
mGestureListener = new ScrollToHideGestureListener(mBottomSheetController, mContent);
GestureListenerManager.fromWebContents(mWebContents).addListener(mGestureListener);
}
} }
...@@ -143,7 +143,7 @@ public class AssistantTriggerScriptBridge { ...@@ -143,7 +143,7 @@ public class AssistantTriggerScriptBridge {
private boolean showTriggerScript(String[] cancelPopupMenuItems, int[] cancelPopupMenuActions, private boolean showTriggerScript(String[] cancelPopupMenuItems, int[] cancelPopupMenuActions,
List<AssistantChip> leftAlignedChips, int[] leftAlignedChipsActions, List<AssistantChip> leftAlignedChips, int[] leftAlignedChipsActions,
List<AssistantChip> rightAlignedChips, int[] rightAlignedChipsActions, List<AssistantChip> rightAlignedChips, int[] rightAlignedChipsActions,
boolean resizeVisualViewport) { boolean resizeVisualViewport, boolean scrollToHide) {
// Trigger scripts currently do not support switching activities (such as CCT->tab). // Trigger scripts currently do not support switching activities (such as CCT->tab).
// TODO(b/171776026): Re-inject dependencies on activity change to support CCT->tab. // TODO(b/171776026): Re-inject dependencies on activity change to support CCT->tab.
if (TabUtils.getActivity(TabUtils.fromWebContents(mWebContents)) != mContext) { if (TabUtils.getActivity(TabUtils.fromWebContents(mWebContents)) != mContext) {
...@@ -154,7 +154,7 @@ public class AssistantTriggerScriptBridge { ...@@ -154,7 +154,7 @@ public class AssistantTriggerScriptBridge {
mTriggerScript.setCancelPopupMenu(cancelPopupMenuItems, cancelPopupMenuActions); mTriggerScript.setCancelPopupMenu(cancelPopupMenuItems, cancelPopupMenuActions);
mTriggerScript.setLeftAlignedChips(leftAlignedChips, leftAlignedChipsActions); mTriggerScript.setLeftAlignedChips(leftAlignedChips, leftAlignedChipsActions);
mTriggerScript.setRightAlignedChips(rightAlignedChips, rightAlignedChipsActions); mTriggerScript.setRightAlignedChips(rightAlignedChips, rightAlignedChipsActions);
boolean shown = mTriggerScript.show(resizeVisualViewport); boolean shown = mTriggerScript.show(resizeVisualViewport, scrollToHide);
// A trigger script was displayed, users are no longer considered first-time users. // A trigger script was displayed, users are no longer considered first-time users.
if (shown) { if (shown) {
......
...@@ -15,6 +15,8 @@ import static androidx.test.espresso.matcher.ViewMatchers.withId; ...@@ -15,6 +15,8 @@ import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText; import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
import static org.chromium.base.test.util.CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL; import static org.chromium.base.test.util.CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL;
import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.tapElement; import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.tapElement;
...@@ -35,6 +37,7 @@ import org.junit.Rule; ...@@ -35,6 +37,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.DisableIf;
import org.chromium.chrome.autofill_assistant.R; import org.chromium.chrome.autofill_assistant.R;
...@@ -63,7 +66,12 @@ import org.chromium.chrome.browser.signin.services.UnifiedConsentServiceBridge; ...@@ -63,7 +66,12 @@ import org.chromium.chrome.browser.signin.services.UnifiedConsentServiceBridge;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.content_public.browser.GestureListenerManager;
import org.chromium.content_public.browser.GestureStateListener;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.content_public.browser.test.util.TouchCommon;
import org.chromium.net.test.EmbeddedTestServer; import org.chromium.net.test.EmbeddedTestServer;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -572,4 +580,80 @@ public class AutofillAssistantTriggerScriptIntegrationTest { ...@@ -572,4 +580,80 @@ public class AutofillAssistantTriggerScriptIntegrationTest {
Espresso.pressBack(); Espresso.pressBack();
waitUntilViewMatchesCondition(withText("Hello world"), isCompletelyDisplayed()); waitUntilViewMatchesCondition(withText("Hello world"), isCompletelyDisplayed());
} }
@Test
@MediumTest
@Features.EnableFeatures({ChromeFeatureList.AUTOFILL_ASSISTANT_DISABLE_ONBOARDING_FLOW,
ChromeFeatureList.AUTOFILL_ASSISTANT_PROACTIVE_HELP})
public void
testScrollToHide() throws Exception {
GetTriggerScriptsResponseProto triggerScripts =
GetTriggerScriptsResponseProto.newBuilder()
.addTriggerScripts(
TriggerScriptProto
.newBuilder()
/* no trigger condition */
.setUserInterface(createDefaultUI("Trigger script",
/* bubbleMessage = */ "",
/* withProgressBar = */ false)
.setScrollToHide(true)))
.build();
setupTriggerScripts(triggerScripts);
AutofillAssistantPreferencesUtil.setInitialPreferences(false);
startAutofillAssistantOnTab(TEST_PAGE_A);
waitUntilViewMatchesCondition(withText("Trigger script"), isCompletelyDisplayed());
BottomSheetController bottomSheetController =
AutofillAssistantUiTestUtil.getBottomSheetController(mTestRule.getActivity());
CallbackHelper waitForScroll = new CallbackHelper();
WebContents webContents = mTestRule.getWebContents();
TestThreadUtils.runOnUiThreadBlocking(() -> {
GestureListenerManager.fromWebContents(webContents)
.addListener(new GestureStateListener() {
@Override
public void onScrollEnded(int scrollOffsetY, int scrollExtentY) {
waitForScroll.notifyCalled();
}
});
});
int webContentX = TestThreadUtils.runOnUiThreadBlocking(
() -> webContents.getViewAndroidDelegate().getContainerView().getWidth() / 2);
int webContentY = TestThreadUtils.runOnUiThreadBlocking(
() -> webContents.getViewAndroidDelegate().getContainerView().getHeight() / 3);
int offsetBeforeScroll = TestThreadUtils.runOnUiThreadBlocking(
() -> bottomSheetController.getCurrentOffset());
assertThat(offsetBeforeScroll, greaterThan(0));
// Scroll more than the bottom sheet height, to be sure it's going to be completely hidden
// or shown due to the scroll.
int scrollDistance = (int) (bottomSheetController.getCurrentOffset() * 1.5f);
TouchCommon.performDrag(mTestRule.getActivity(), webContentX, webContentX, webContentY,
webContentY - scrollDistance,
/* stepCount*/ 10, /* duration in ms */ 250);
waitForScroll.waitForCallback("scroll down expected", /* currentCallCount= */ 0);
// After scroll down, the bottom sheet is completely hidden.
int offsetAfterScrollDown = TestThreadUtils.runOnUiThreadBlocking(
() -> bottomSheetController.getCurrentOffset());
Assert.assertEquals(0, offsetAfterScrollDown);
TouchCommon.performDrag(mTestRule.getActivity(), webContentX, webContentX, webContentY,
webContentY + scrollDistance, /* stepCount*/ 10, /* duration in ms */ 250);
waitForScroll.waitForCallback("scroll up expected", /* currentCallCount= */ 1);
// Wait until the bottom sheet is fully back on the screen again before capturing one last
// offset.
waitUntilViewMatchesCondition(withText("Trigger script"), isCompletelyDisplayed());
int offsetAfterScrollUp = TestThreadUtils.runOnUiThreadBlocking(
() -> bottomSheetController.getCurrentOffset());
// After scroll up, the bottom sheet is visible again.
Assert.assertEquals(offsetBeforeScroll, offsetAfterScrollUp);
}
} }
...@@ -223,7 +223,7 @@ void TriggerScriptBridgeAndroid::OnTriggerScriptShown( ...@@ -223,7 +223,7 @@ void TriggerScriptBridgeAndroid::OnTriggerScriptShown(
ToJavaIntArray(env, cancel_popup_actions), jleft_aligned_chips, ToJavaIntArray(env, cancel_popup_actions), jleft_aligned_chips,
ToJavaIntArray(env, left_aligned_chip_actions), jright_aligned_chips, ToJavaIntArray(env, left_aligned_chip_actions), jright_aligned_chips,
ToJavaIntArray(env, right_aligned_chip_actions), ToJavaIntArray(env, right_aligned_chip_actions),
proto.resize_visual_viewport()); proto.resize_visual_viewport(), proto.scroll_to_hide());
trigger_script_coordinator_->OnTriggerScriptShown(success); trigger_script_coordinator_->OnTriggerScriptShown(success);
} }
......
...@@ -596,6 +596,13 @@ message TriggerScriptUIProto { ...@@ -596,6 +596,13 @@ message TriggerScriptUIProto {
// Whether the visual viewport should be resized to allow scrolling to the // Whether the visual viewport should be resized to allow scrolling to the
// bottom of the page while the trigger script is being displayed. // bottom of the page while the trigger script is being displayed.
optional bool resize_visual_viewport = 8; optional bool resize_visual_viewport = 8;
// Whether the bottom sheet should temporarily disappear when scrolling down
// the website, to move out of the way.
//
// Avoid setting both resize_visual_viewport and scroll_to_hide to true, as
// the resulting behavior is confusing: the bottom sheet can pop back up after
// a scroll down instead of staying hidden in some situations.
optional bool scroll_to_hide = 9;
} }
// An action could be performed. // An action could be performed.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment