// Copyright 2019 The Chromium Authors
// 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.gesturenav;
import static org.chromium.ui.base.LocalizationUtils.setRtlForTesting;
import android.os.Build;
import android.os.SystemClock;
import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.FeatureList;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.DisableIf;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Features.DisableFeatures;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.base.test.util.HistogramWatcher;
import org.chromium.base.test.util.Restriction;
import org.chromium.base.test.util.TestAnimations;
import org.chromium.chrome.browser.bookmarks.BookmarkPage;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.init.AsyncInitializationActivity;
import org.chromium.chrome.browser.layouts.LayoutManager;
import org.chromium.chrome.browser.layouts.LayoutTestUtils;
import org.chromium.chrome.browser.layouts.LayoutType;
import org.chromium.chrome.browser.layouts.animation.CompositorAnimationHandler;
import org.chromium.chrome.browser.ntp.NewTabPage;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabCreator;
import org.chromium.chrome.browser.ui.native_page.BasicSmoothTransitionDelegate;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.chrome.test.util.NewTabPageTestUtils;
import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.back_forward_transition.AnimationStage;
import org.chromium.content_public.browser.test.util.UiUtils;
import org.chromium.content_public.common.ContentUrlConstants;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.ui.base.BackGestureEventSwipeEdge;
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.base.UiAndroidFeatures;
import org.chromium.ui.test.util.UiDisableIf;
import org.chromium.ui.test.util.UiRestriction;
import java.util.Map;
import java.util.concurrent.TimeoutException;
/** Tests {@link NavigationHandler} navigating back/forward using overscroll history navigation. */
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@DisableIf.Build(
sdk_is_greater_than = Build.VERSION_CODES.Q,
message = "crbug.com/1276402 crbug.com/345352689")
@Batch(Batch.PER_CLASS)
public class NavigationHandlerTest {
private static final String RENDERED_PAGE = "/chrome/test/data/android/navigate/simple.html";
private static final String TEST_PAGE = "/chrome/test/data/android/test.html";
private static final boolean LEFT_EDGE = true;
private static final boolean RIGHT_EDGE = false;
private EmbeddedTestServer mTestServer;
private HistoryNavigationLayout mNavigationLayout;
private NavigationHandler mNavigationHandler;
@Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
private GestureNavigationTestUtils mNavUtils;
@Before
public void setUp() throws InterruptedException {
TestAnimations.setEnabled(true);
mTestServer =
EmbeddedTestServer.createAndStartServer(
InstrumentationRegistry.getInstrumentation().getContext());
mActivityTestRule.startMainActivityWithURL(mTestServer.getURL(TEST_PAGE));
CompositorAnimationHandler.setTestingMode(true);
mNavUtils = new GestureNavigationTestUtils(mActivityTestRule);
mNavigationHandler = mNavUtils.getNavigationHandler();
mNavigationLayout = mNavUtils.getLayout();
}
@After
public void tearDown() {
CompositorAnimationHandler.setTestingMode(false);
setRtlForTesting(false);
}
private Tab currentTab() {
return ThreadUtils.runOnUiThreadBlocking(
() -> mActivityTestRule.getActivity().getActivityTabProvider().get());
}
private void loadNewTabPage() {
ChromeTabUtils.newTabFromMenu(
InstrumentationRegistry.getInstrumentation(),
mActivityTestRule.getActivity(),
false,
true);
}
private void assertNavigateOnSwipeFrom(boolean edge, String toUrl) {
ChromeTabUtils.waitForTabPageLoaded(
currentTab(), toUrl, () -> mNavUtils.swipeFromEdge(edge), 10);
CriteriaHelper.pollUiThread(
() ->
Criteria.checkThat(
ChromeTabUtils.getUrlStringOnUiThread(currentTab()),
Matchers.is(toUrl)));
Assert.assertEquals(
"Didn't navigate back", toUrl, ChromeTabUtils.getUrlStringOnUiThread(currentTab()));
Assert.assertEquals(
"Detected a wrong direction.",
mNavigationHandler.getInitiatingEdge() == BackGestureEventSwipeEdge.LEFT,
edge);
}
/**
* Enter or exit the tab switcher with animations and wait for the scene to change.
*
* @param inSwitcher Whether to enter or exit the tab switcher.
*/
private void setTabSwitcherModeAndWait(boolean inSwitcher) {
LayoutManager layoutManager = mActivityTestRule.getActivity().getLayoutManager();
@LayoutType int layout = inSwitcher ? LayoutType.TAB_SWITCHER : LayoutType.BROWSING;
LayoutTestUtils.startShowingAndWaitForLayout(layoutManager, layout, false);
}
@Test
@SmallTest
@CommandLineFlags.Add({
"enable-features=BackForwardTransitions<Study",
"force-fieldtrials=Study/Group",
"force-fieldtrial-params=Study.Group:transition_from_native_pages/true/"
+ "transition_to_native_pages/true"
})
public void testSwipeBackToNTPWithTransition() throws InterruptedException {
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
final Tab tab = mActivityTestRule.getActivity().getActivityTab();
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
NewTabPageTestUtils.waitForNtpLoaded(mActivityTestRule.getActivity().getActivityTab());
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
mNavUtils.swipeFromEdgeAndHold(true);
Assert.assertEquals(
"Back forward transition not invoked yet",
AnimationStage.OTHER,
tab.getWebContents().getCurrentBackForwardTransitionStage());
ThreadUtils.runOnUiThreadBlocking(() -> mNavigationHandler.release(true));
CriteriaHelper.pollInstrumentationThread(
() ->
AnimationStage.INVOKE_ANIMATION
== tab.getWebContents().getCurrentBackForwardTransitionStage(),
"invoking animation should be started");
CriteriaHelper.pollInstrumentationThread(
() ->
AnimationStage.NONE
== tab.getWebContents().getCurrentBackForwardTransitionStage(),
"should wait for animation to be finished");
CriteriaHelper.pollInstrumentationThread(
() ->
((NewTabPage) tab.getNativePage()).getSmoothTransitionDelegateForTesting()
!= null,
"Smooth transition should be enabled");
CriteriaHelper.pollInstrumentationThread(
() ->
!((BasicSmoothTransitionDelegate)
((NewTabPage) tab.getNativePage())
.getSmoothTransitionDelegateForTesting())
.getAnimatorForTesting()
.isRunning(),
"Smooth transition should be finished");
}
@Test
@SmallTest
@CommandLineFlags.Add({
"enable-features=BackForwardTransitions<Study",
"force-fieldtrials=Study/Group",
"force-fieldtrial-params=Study.Group:transition_from_native_pages/true/"
+ "transition_to_native_pages/false"
})
public void testSwipeBackToNTPWithoutTransition() throws InterruptedException {
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
final Tab tab = mActivityTestRule.getActivity().getActivityTab();
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
NewTabPageTestUtils.waitForNtpLoaded(mActivityTestRule.getActivity().getActivityTab());
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
mNavUtils.swipeFromEdgeAndHold(true);
Assert.assertEquals(
"Back forward transition is not enabled for native pages",
AnimationStage.NONE,
tab.getWebContents().getCurrentBackForwardTransitionStage());
ThreadUtils.runOnUiThreadBlocking(() -> mNavigationHandler.release(true));
CriteriaHelper.pollInstrumentationThread(
() ->
AnimationStage.NONE
== tab.getWebContents().getCurrentBackForwardTransitionStage(),
"Back forward transition is not enabled for native pages");
}
@Test
@SmallTest
@CommandLineFlags.Add({
"enable-features=BackForwardTransitions<Study",
"force-fieldtrials=Study/Group",
"force-fieldtrial-params=Study.Group:transition_from_native_pages/false/"
+ "transition_to_native_pages/false"
})
public void testSwipeBackFromNTPWithoutTransition() throws InterruptedException {
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
final Tab tab = mActivityTestRule.getActivity().getActivityTab();
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
NewTabPageTestUtils.waitForNtpLoaded(mActivityTestRule.getActivity().getActivityTab());
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
mNavUtils.swipeFromEdgeAndHold(true);
Assert.assertEquals(
"Back forward transition is not enabled for native pages",
AnimationStage.NONE,
tab.getWebContents().getCurrentBackForwardTransitionStage());
ThreadUtils.runOnUiThreadBlocking(() -> mNavigationHandler.release(true));
CriteriaHelper.pollInstrumentationThread(
() ->
AnimationStage.NONE
== tab.getWebContents().getCurrentBackForwardTransitionStage(),
"Back forward transition is not enabled for native pages");
}
@Test
@SmallTest
@CommandLineFlags.Add({
"enable-features=BackForwardTransitions<Study",
"force-fieldtrials=Study/Group",
"force-fieldtrial-params=Study.Group:transition_from_native_pages/true/"
+ "transition_to_native_pages/true"
})
public void testSwipeBackToNativeBookmarksPageWithTransition() throws InterruptedException {
final Tab tab = mActivityTestRule.getActivity().getActivityTab();
mActivityTestRule.loadUrl("chrome-native://bookmarks/folder/0");
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
mNavUtils.swipeFromEdgeAndHold(true);
Assert.assertEquals(
"Back forward transition not invoked yet",
AnimationStage.OTHER,
tab.getWebContents().getCurrentBackForwardTransitionStage());
ThreadUtils.runOnUiThreadBlocking(() -> mNavigationHandler.release(true));
CriteriaHelper.pollInstrumentationThread(
() ->
AnimationStage.INVOKE_ANIMATION
== tab.getWebContents().getCurrentBackForwardTransitionStage(),
"invoking animation should be started");
CriteriaHelper.pollInstrumentationThread(
() ->
AnimationStage.NONE
== tab.getWebContents().getCurrentBackForwardTransitionStage(),
"should wait for animation to be finished");
CriteriaHelper.pollInstrumentationThread(
() ->
((BookmarkPage) tab.getNativePage()).getSmoothTransitionDelegateForTesting()
!= null,
"Smooth transition should be enabled");
CriteriaHelper.pollInstrumentationThread(
() ->
!((BasicSmoothTransitionDelegate)
((BookmarkPage) tab.getNativePage())
.getSmoothTransitionDelegateForTesting())
.getAnimatorForTesting()
.isRunning(),
"Smooth transition should be finished");
}
@Test
@SmallTest
@CommandLineFlags.Add({
"enable-features=BackForwardTransitions<Study",
"force-fieldtrials=Study/Group",
"force-fieldtrial-params=Study.Group:transition_from_native_pages/true/"
+ "transition_to_native_pages/true"
})
public void testSwipeBackWithoutTransition_AnimationsDisabled() throws InterruptedException {
TestAnimations.setEnabled(false);
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
final Tab tab = mActivityTestRule.getActivity().getActivityTab();
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
NewTabPageTestUtils.waitForNtpLoaded(mActivityTestRule.getActivity().getActivityTab());
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
mNavUtils.swipeFromEdgeAndHold(true);
Assert.assertEquals(
"Back forward transition is disabled due to no animation",
AnimationStage.NONE,
tab.getWebContents().getCurrentBackForwardTransitionStage());
ThreadUtils.runOnUiThreadBlocking(() -> mNavigationHandler.release(true));
CriteriaHelper.pollInstrumentationThread(
() ->
AnimationStage.NONE
== tab.getWebContents().getCurrentBackForwardTransitionStage(),
"Back forward transition is disabled due to no animation");
}
@Test
@SmallTest
public void testShortSwipeDoesNotTriggerNavigation() {
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
mNavUtils.shortSwipeFromEdge(LEFT_EDGE);
CriteriaHelper.pollUiThread(
mNavigationLayout::isLayoutDetached,
"Navigation Layout should be detached after use");
Assert.assertEquals(
"Current page should not change",
UrlConstants.NTP_URL,
ChromeTabUtils.getUrlStringOnUiThread(currentTab()));
Assert.assertTrue(
"The gesture should start from the left side.",
mNavigationHandler.getInitiatingEdge() == BackGestureEventSwipeEdge.LEFT);
}
@Test
@SmallTest
@DisableIf.Device(type = {UiDisableIf.TABLET}) // https://crbug.com/338972492
public void testCloseChromeAtHistoryStackHead() {
loadNewTabPage();
AsyncInitializationActivity.interceptMoveTaskToBackForTesting();
mNavUtils.swipeFromLeftEdge();
CriteriaHelper.pollUiThread(
AsyncInitializationActivity::wasMoveTaskToBackInterceptedForTesting);
}
@Test
@SmallTest
public void testLayoutGetsDetachedAfterUse() {
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
mActivityTestRule.loadUrl(UrlConstants.RECENT_TABS_URL);
mNavUtils.swipeFromLeftEdge();
CriteriaHelper.pollUiThread(
mNavigationLayout::isLayoutDetached,
"Navigation Layout should be detached after use");
Assert.assertNull(mNavigationLayout.getDetachLayoutRunnable());
}
@Test
@SmallTest
public void testReleaseGlowWithoutPrecedingPullIgnored() {
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
ThreadUtils.runOnUiThreadBlocking(
() -> {
// Right swipe on a rendered page to initiate overscroll glow.
mNavigationHandler.onDown();
mNavigationHandler.triggerUi(BackGestureEventSwipeEdge.RIGHT);
// Test that a release without preceding pull requests works
// without crashes.
mNavigationHandler.release(true);
});
// Just check we're still on the same URL.
Assert.assertEquals(
mTestServer.getURL(RENDERED_PAGE),
ChromeTabUtils.getUrlStringOnUiThread(currentTab()));
}
@Test
@SmallTest
@DisableIf.Device(type = {UiDisableIf.TABLET}) // https://crbug.com/338972492
public void testSwipeNavigateOnNativePage() {
HistogramWatcher histogramWatcher =
HistogramWatcher.newBuilder()
.expectBooleanRecordTimes("Navigation.DuringGesture.NavStarted", false, 2)
.expectBooleanRecordTimes(
"Navigation.DuringGesture.NavStarted.3ButtonMode", false, 2)
.expectBooleanRecordTimes(
"Navigation.OnGestureStart.NavigationInProgress", false, 2)
.expectBooleanRecordTimes(
"Navigation.OnGestureStart.NavigationInProgress.3ButtonMode",
false,
2)
.build();
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
mActivityTestRule.loadUrl(UrlConstants.RECENT_TABS_URL);
assertNavigateOnSwipeFrom(LEFT_EDGE, UrlConstants.NTP_URL);
assertNavigateOnSwipeFrom(RIGHT_EDGE, UrlConstants.RECENT_TABS_URL);
histogramWatcher.assertExpected("Wrong histogram recording");
histogramWatcher =
HistogramWatcher.newBuilder()
.expectNoRecords("Navigation.DuringGesture.NavStarted")
.expectNoRecords("Navigation.DuringGesture.NavStarted.3ButtonMode")
.expectNoRecords("Navigation.OnGestureStart.NavigationInProgress")
.expectNoRecords(
"Navigation.OnGestureStart.NavigationInProgress.3ButtonMode")
.build();
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
mActivityTestRule.loadUrl(UrlConstants.RECENT_TABS_URL);
ThreadUtils.runOnUiThreadBlocking(
mActivityTestRule.getActivity().getOnBackPressedDispatcher()::onBackPressed);
ThreadUtils.runOnUiThreadBlocking(
mActivityTestRule.getActivity().getOnBackPressedDispatcher()::onBackPressed);
histogramWatcher.assertExpected("Should not record when back is not triggered by swipe");
}
@Test
@SmallTest
public void testSwipeNavigateOnRenderedPage() {
// TODO(crbug.com/40899221): Write a test variation running with
// ChromeFeatureList.BACK_FORWARD_TRANSITIONS enabled when the feature is completed.
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
mActivityTestRule.loadUrl(ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
assertNavigateOnSwipeFrom(LEFT_EDGE, mTestServer.getURL(RENDERED_PAGE));
assertNavigateOnSwipeFrom(RIGHT_EDGE, ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
}
@Test
@SmallTest
public void testLeftEdgeSwipeClosesTabLaunchedFromLink() {
FeatureList.setTestFeatures(Map.of(ChromeFeatureList.BACK_FORWARD_TRANSITIONS, false));
testLeftEdgeSwipeClosesTabLaunchedFromLinkInternal();
}
@Test
@SmallTest
@DisabledTest(message = "crbug.com/1426201")
public void testLeftEdgeSwipeClosesTabLaunchedFromLink_withBackForwardTransition() {
FeatureList.setTestFeatures(Map.of(ChromeFeatureList.BACK_FORWARD_TRANSITIONS, true));
testLeftEdgeSwipeClosesTabLaunchedFromLinkInternal();
}
private void testLeftEdgeSwipeClosesTabLaunchedFromLinkInternal() {
Tab oldTab = currentTab();
TabCreator tabCreator =
ThreadUtils.runOnUiThreadBlocking(
() -> mActivityTestRule.getActivity().getTabCreator(false));
Tab newTab =
ThreadUtils.runOnUiThreadBlocking(
() -> {
return tabCreator.createNewTab(
new LoadUrlParams(
UrlConstants.RECENT_TABS_URL, PageTransition.LINK),
TabLaunchType.FROM_LINK,
oldTab);
});
Assert.assertEquals(newTab, currentTab());
mNavUtils.swipeFromLeftEdge();
// Assert that the new tab was closed and the old tab is the current tab again.
CriteriaHelper.pollUiThread(() -> !newTab.isInitialized());
Assert.assertNull(
"Not supposed to trigger an animation when closing tab",
mNavigationHandler.getTabOnBackGestureHandlerForTesting());
Assert.assertEquals(oldTab, currentTab());
Assert.assertEquals(
"Chrome should remain in foreground",
ActivityState.RESUMED,
ApplicationStatus.getStateForActivity(mActivityTestRule.getActivity()));
}
@Test
@SmallTest
public void testSwipeAfterDestroy() {
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
ThreadUtils.runOnUiThreadBlocking(mNavigationHandler::destroy);
// |triggerUi| can be invoked by SwipeRefreshHandler on the rendered
// page. Make sure this won't crash after the handler(and also
// handler action delegate) is destroyed.
Assert.assertTrue(
ThreadUtils.runOnUiThreadBlocking(
() -> mNavigationHandler.triggerUi(BackGestureEventSwipeEdge.LEFT)));
// Just check we're still on the same URL.
Assert.assertEquals(
mTestServer.getURL(RENDERED_PAGE),
ChromeTabUtils.getUrlStringOnUiThread(currentTab()));
}
@Test
@SmallTest
public void testSwipeAfterTabDestroy() {
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
ThreadUtils.runOnUiThreadBlocking(currentTab()::destroy);
// |triggerUi| can be invoked by SwipeRefreshHandler on the rendered
// page. Make sure this won't crash after the current tab is destroyed.
Assert.assertFalse(
ThreadUtils.runOnUiThreadBlocking(
() -> mNavigationHandler.triggerUi(BackGestureEventSwipeEdge.LEFT)));
}
@Test
@SmallTest
public void testSwipeAfterDestroyActivity_NativePage() {
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
ThreadUtils.runOnUiThreadBlocking(mActivityTestRule.getActivity()::finish);
// CompositorViewHolder dispatches motion events and invoke the handler's
// |handleTouchEvent| on native pages. Make sure this won't crash the app after
// the handler is destroyed.
long eventTime = SystemClock.uptimeMillis();
MotionEvent e =
MotionEvent.obtain(
eventTime,
eventTime,
MotionEvent.ACTION_DOWN,
/* x= */ 10,
/* y= */ 100,
0);
ThreadUtils.runOnUiThreadBlocking(
() ->
mActivityTestRule
.getActivity()
.getCompositorViewHolderForTesting()
.dispatchTouchEvent(e));
}
@Test
@SmallTest
@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
public void testEdgeSwipeIsNoopInTabSwitcher() throws TimeoutException {
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
mActivityTestRule.loadUrl(UrlConstants.RECENT_TABS_URL);
setTabSwitcherModeAndWait(true);
mNavUtils.swipeFromLeftEdge();
Assert.assertTrue(
"Chrome should stay in tab switcher",
mActivityTestRule.getActivity().isInOverviewMode());
setTabSwitcherModeAndWait(false);
Assert.assertEquals(
"Current page should not change. ",
UrlConstants.RECENT_TABS_URL,
ChromeTabUtils.getUrlStringOnUiThread(currentTab()));
}
@Test
@SmallTest
@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
public void testSwipeAndHoldOnNtp_EnterTabSwitcher() throws TimeoutException {
// Clicking tab switcher button while swiping and holding the gesture navigation
// bubble should reset the state and dismiss the UI.
mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
mNavUtils.swipeFromEdgeAndHold(/* leftEdge= */ true);
setTabSwitcherModeAndWait(true);
Assert.assertFalse(
"Navigation UI should be reset.",
ThreadUtils.runOnUiThreadBlocking(mNavigationHandler::isActive));
}
@Test
@SmallTest
@EnableFeatures({UiAndroidFeatures.MIRROR_BACK_FORWARD_GESTURES_IN_RTL})
public void testRtlUiMirrorsDirectionsWithFlagEnabled() {
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
mActivityTestRule.loadUrl(ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
setRtlForTesting(true);
assertNavigateOnSwipeFrom(RIGHT_EDGE, mTestServer.getURL(RENDERED_PAGE));
assertNavigateOnSwipeFrom(LEFT_EDGE, ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
}
@Test
@SmallTest
@DisableFeatures({UiAndroidFeatures.MIRROR_BACK_FORWARD_GESTURES_IN_RTL})
public void testRtlUiMirrorsDirectionsWithFlagDisabled() {
mActivityTestRule.loadUrl(mTestServer.getURL(RENDERED_PAGE));
mActivityTestRule.loadUrl(ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
setRtlForTesting(true);
assertNavigateOnSwipeFrom(LEFT_EDGE, mTestServer.getURL(RENDERED_PAGE));
assertNavigateOnSwipeFrom(RIGHT_EDGE, ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL);
}
}