blob: c253860e287937a8a2e1725e70c505a6bea1825c [file] [log] [blame]
// Copyright 2017 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.modaldialog;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.not;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.Espresso;
import android.support.test.filters.SmallTest;
import android.view.View;
import android.view.ViewGroup;
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.ThreadUtils;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.ui.test.util.UiRestriction;
import java.util.List;
/**
* Tests for displaying and functioning of modal dialogs on tabs.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class ModalDialogManagerTest {
private static class TestObserver implements UrlFocusChangeListener {
public final CallbackHelper onUrlFocusChangedCallback = new CallbackHelper();
@Override
public void onUrlFocusChange(boolean hasFocus) {
onUrlFocusChangedCallback.notifyCalled();
}
}
@Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
private static final int MAX_DIALOGS = 4;
private ChromeTabbedActivity mActivity;
private ModalDialogManager mManager;
private ModalDialogView[] mModalDialogViews;
private TestObserver mTestObserver;
@Before
public void setUp() throws Exception {
mActivityTestRule.startMainActivityOnBlankPage();
mActivity = mActivityTestRule.getActivity();
mManager = mActivity.getModalDialogManager();
mModalDialogViews = new ModalDialogView[MAX_DIALOGS];
for (int i = 0; i < MAX_DIALOGS; i++) mModalDialogViews[i] = createDialog(i);
mTestObserver = new TestObserver();
mActivity.getToolbarManager().getToolbarLayout().getLocationBar().addUrlFocusChangeListener(
mTestObserver);
TabModalPresenter presenter =
(TabModalPresenter) mManager.getPresenterForTest(ModalDialogManager.TAB_MODAL);
presenter.disableAnimationForTest();
}
@Test
@SmallTest
public void testOneDialog() throws Exception {
// Initially there are no dialogs in the pending list. Browser controls are not restricted.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Show a dialog. The pending list should be empty, and the dialog should be showing.
// Browser controls should be restricted.
showDialog(0, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(hasDescendant(withText("0"))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Dismiss the dialog by clicking positive button.
onView(withText(R.string.ok)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(not(hasDescendant(withText("0")))));
checkBrowserControls(false);
checkCurrentPresenter(null);
}
@Test
@SmallTest
public void testTwoDialogs() throws Exception {
// Initially there are no dialogs in the pending list. Browser controls are not restricted.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Show the first dialog.
// The pending list should be empty, and the dialog should be showing.
// The tab modal container shouldn't be in the window hierarchy when an app modal dialog is
// showing.
showDialog(0, ModalDialogManager.APP_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withText("0")).check(matches(isDisplayed()));
onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
// Show the second dialog. It should be added to the pending list, and the first dialog
// should still be shown.
showDialog(1, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withText("0")).check(matches(isDisplayed()));
onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
// Dismiss the first dialog by clicking cancel. The second dialog should be removed from
// pending list and shown immediately after.
onView(withText(R.string.cancel)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withText("0")).check(doesNotExist());
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(
allOf(not(hasDescendant(withText("0"))), hasDescendant(withText("1")))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Dismiss the second dialog by clicking ok. Browser controls should no longer be
// restricted.
onView(withText(R.string.ok)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withText("0")).check(doesNotExist());
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(allOf(
not(hasDescendant(withText("0"))), not(hasDescendant(withText("1"))))));
checkBrowserControls(false);
checkCurrentPresenter(null);
}
@Test
@SmallTest
public void testThreeDialogs() throws Exception {
// Initially there are no dialogs in the pending list. Browser controls are not restricted.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Show the first dialog.
// The pending list should be empty, and the dialog should be showing.
// Browser controls should be restricted.
showDialog(0, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(hasDescendant(withText("0"))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Show the second dialog. It should be added to the pending list, and the first dialog
// should still be shown.
showDialog(1, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(
allOf(hasDescendant(withText("0")), not(hasDescendant(withText("1"))))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Show the third dialog (app modal). The first tab modal dialog should be back to the
// pending list and this app modal dialog should be shown right after.
showDialog(2, ModalDialogManager.APP_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 2);
onView(withText("2")).check(matches(isDisplayed()));
onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
// Simulate dismissing the dialog by non-user action. The second dialog should be removed
// from pending list without showing.
dismissDialog(1);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withText("2")).check(matches(isDisplayed()));
onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
// Dismiss the second dialog twice and verify nothing breaks.
dismissDialog(1);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withText("2")).check(matches(isDisplayed()));
onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
// Dismiss the third dialog. The first dialog should be removed from pending list and
// shown immediately after. The tab modal container shouldn't be in the window hierarchy
// when an app modal dialog is showing.
dismissDialog(2);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withText("2")).check(doesNotExist());
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(allOf(hasDescendant(withText("0")),
not(hasDescendant(withText("1"))), not(hasDescendant(withText("2"))))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Dismiss the first dialog by clicking OK. Browser controls should no longer be restricted.
onView(withText(R.string.ok)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withText("2")).check(doesNotExist());
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(allOf(not(hasDescendant(withText("0"))),
not(hasDescendant(withText("1"))), not(hasDescendant(withText("2"))))));
checkBrowserControls(false);
checkCurrentPresenter(null);
}
@Test
@SmallTest
public void testShow_ShowNext() throws Exception {
// Initially there are no dialogs in the pending list. Browser controls are not restricted.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Insert two tab modal dialogs and two app modal dialogs for showing.
showDialog(0, ModalDialogManager.TAB_MODAL);
showDialog(1, ModalDialogManager.TAB_MODAL);
showDialog(2, ModalDialogManager.APP_MODAL);
showDialog(3, ModalDialogManager.APP_MODAL);
// The first inserted app modal dialog is shown.
checkPendingSize(ModalDialogManager.APP_MODAL, 1);
checkPendingSize(ModalDialogManager.TAB_MODAL, 2);
onView(withText("2")).check(matches(isDisplayed()));
onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
// Dismiss the dialog by clicking OK. The second inserted app modal dialog should be shown.
onView(withText(R.string.ok)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 2);
onView(withText("3")).check(matches(isDisplayed()));
onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
// Dismiss the dialog by clicking OK. The first tab modal dialog should be shown.
onView(withText(R.string.ok)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(allOf(hasDescendant(withText("0")),
not(hasDescendant(withText("1"))), not(hasDescendant(withText("2"))),
not(hasDescendant(withText("3"))))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Dismiss the dialog by clicking OK. The second tab modal dialog should be shown.
onView(withText(R.string.ok)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(allOf(hasDescendant(withText("1")),
not(hasDescendant(withText("0"))), not(hasDescendant(withText("2"))),
not(hasDescendant(withText("3"))))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
}
@Test
@SmallTest
public void testShow_ShowDialogAsNext() throws Exception {
// Initially there are no dialogs in the pending list. Browser controls are not restricted.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Insert a tab modal dialog and a app modal dialog for showing.
showDialog(0, ModalDialogManager.TAB_MODAL);
showDialog(1, ModalDialogManager.TAB_MODAL);
showDialog(2, ModalDialogManager.APP_MODAL);
// The first inserted app modal dialog is shown.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 2);
onView(withText("2")).check(matches(isDisplayed()));
onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
// Show a tab modal dialog as the next dialog to be shown. Verify that the app modal dialog
// is still showing.
showDialogAsNext(3, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 3);
onView(withText("2")).check(matches(isDisplayed()));
onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
// Dismiss the dialog by clicking OK. The third tab modal dialog should be shown.
onView(withText(R.string.ok)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 2);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(allOf(hasDescendant(withText("3")),
not(hasDescendant(withText("0"))), not(hasDescendant(withText("1"))),
not(hasDescendant(withText("2"))))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Dismiss the dialog by clicking OK. The first tab modal dialog should be shown.
onView(withText(R.string.ok)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(allOf(hasDescendant(withText("0")),
not(hasDescendant(withText("1"))), not(hasDescendant(withText("2"))),
not(hasDescendant(withText("3"))))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
}
@Test
@SmallTest
@DisabledTest(message = "crbug.com/812066")
public void testShow_UrlBarFocused() throws Exception {
// Show a dialog. The dialog should be shown on top of the toolbar.
showDialog(0, ModalDialogManager.TAB_MODAL);
TabModalPresenter presenter =
(TabModalPresenter) mManager.getPresenterForTest(ModalDialogManager.TAB_MODAL);
final View dialogContainer = presenter.getDialogContainerForTest();
final View controlContainer = mActivity.findViewById(R.id.control_container);
final ViewGroup containerParent = presenter.getContainerParentForTest();
ThreadUtils.runOnUiThreadBlocking(() -> {
Assert.assertTrue(containerParent.indexOfChild(dialogContainer)
> containerParent.indexOfChild(controlContainer));
});
// When editing URL, it should be shown on top of the dialog.
int callCount = mTestObserver.onUrlFocusChangedCallback.getCallCount();
onView(withId(R.id.url_bar)).perform(click());
mTestObserver.onUrlFocusChangedCallback.waitForCallback(callCount);
ThreadUtils.runOnUiThreadBlocking(() -> {
Assert.assertTrue(containerParent.indexOfChild(dialogContainer)
< containerParent.indexOfChild(controlContainer));
});
// When URL bar is not focused, the dialog should be shown on top of the toolbar again.
callCount = mTestObserver.onUrlFocusChangedCallback.getCallCount();
Espresso.pressBack();
mTestObserver.onUrlFocusChangedCallback.waitForCallback(callCount);
ThreadUtils.runOnUiThreadBlocking(() -> {
Assert.assertTrue(containerParent.indexOfChild(dialogContainer)
> containerParent.indexOfChild(controlContainer));
});
// Dismiss the dialog by clicking OK.
onView(withText(R.string.ok)).perform(click());
}
@Test
@SmallTest
@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
@DisabledTest(message = "crbug.com/804858")
public void testSuspend_ToggleOverview() throws Exception {
// Initially there are no dialogs in the pending list. Browser controls are not restricted.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Add two dialogs available for showing.
showDialog(0, ModalDialogManager.TAB_MODAL);
showDialog(1, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(
allOf(hasDescendant(withText("0")), not(hasDescendant(withText("1"))))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Tab modal dialogs should be suspended on entering tab switcher.
onView(withId(R.id.tab_switcher_button)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 2);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(allOf(
not(hasDescendant(withText("0"))), not(hasDescendant(withText("1"))))));
checkBrowserControls(false);
checkCurrentPresenter(null);
// Exit overview mode. The first dialog should be showing again.
onView(withId(R.id.tab_switcher_button)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(
allOf(hasDescendant(withText("0")), not(hasDescendant(withText("1"))))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Dismiss the first dialog. The second dialog should be shown.
onView(withText(R.string.ok)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(
allOf(not(hasDescendant(withText("0"))), hasDescendant(withText("1")))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
}
@Test
@SmallTest
@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
@DisabledTest(message = "crbug.com/804858")
public void testSuspend_ShowNext() throws Exception {
// Initially there are no dialogs in the pending list. Browser controls are not restricted.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Add a tab modal dialog available for showing.
showDialog(0, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(hasDescendant(withText("0"))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Tab modal dialogs should be suspended on entering tab switcher. App modal dialog should
// be showing.
onView(withId(R.id.tab_switcher_button)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
// An app modal dialog can be shown in tab switcher.
showDialog(1, ModalDialogManager.APP_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
onView(withText("1")).check(matches(isDisplayed()));
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
// Close the app modal dialog and exit overview mode. The first dialog should be showing
// again.
onView(withText(R.string.ok)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withId(R.id.tab_switcher_button)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(hasDescendant(withText("0"))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
}
@Test
@SmallTest
@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
public void testSuspend_LastTabClosed() throws Exception {
// Make sure there is only one opened tab.
while (mActivity.getCurrentTabModel().getCount() > 1) {
ChromeTabUtils.closeCurrentTab(InstrumentationRegistry.getInstrumentation(), mActivity);
}
// Initially there are no dialogs in the pending list. Browser controls are not restricted.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Add a tab modal dialog available for showing.
showDialog(0, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(hasDescendant(withText("0"))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Tab modal dialogs should be suspended on entering tab switcher.
onView(withId(R.id.tab_switcher_button)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Close the only tab in the tab switcher.
ChromeTabUtils.closeCurrentTab(InstrumentationRegistry.getInstrumentation(), mActivity);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
}
@Test
@SmallTest
@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
public void testSuspend_TabClosed() throws Exception {
mActivityTestRule.loadUrlInNewTab("about:blank");
// Initially there are no dialogs in the pending list. Browser controls are not restricted.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Add a tab modal dialog available for showing.
showDialog(0, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(hasDescendant(withText("0"))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Tab modal dialogs should be suspended on entering tab switcher.
onView(withId(R.id.tab_switcher_button)).perform(click());
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Close current tab in the tab switcher.
ChromeTabUtils.closeCurrentTab(InstrumentationRegistry.getInstrumentation(), mActivity);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Show a new tab modal dialog, and it should be suspended in tab switcher.
showDialog(1, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Show an app modal dialog. The app modal dialog should be shown.
showDialog(2, ModalDialogManager.APP_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withText("2")).check(matches(isDisplayed()));
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
}
@Test
@SmallTest
public void testDismiss_SwitchTab() throws Exception {
// Open a new tab and make sure that the current tab is at index 0.
mActivityTestRule.loadUrlInNewTab("about:blank");
ChromeTabUtils.switchTabInCurrentTabModel(mActivity, 0);
// Initially there are no dialogs in the pending list. Browser controls are not restricted.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Add a tab modal dialog available for showing.
showDialog(0, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(hasDescendant(withText("0"))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Dialog should be dismissed after switching to a different tab.
ChromeTabUtils.switchTabInCurrentTabModel(mActivity, 1);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Open a tab modal dialog in the current tab. The dialog should be shown.
showDialog(1, ModalDialogManager.TAB_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(hasDescendant(withText("1"))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
}
@Test
@SmallTest
public void testDismiss_BackPressed() throws Exception {
// Initially there are no dialogs in the pending list. Browser controls are not restricted.
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
checkBrowserControls(false);
checkCurrentPresenter(null);
// Add three dialogs available for showing. The app modal dialog should be shown first.
showDialog(0, ModalDialogManager.TAB_MODAL);
showDialog(1, ModalDialogManager.TAB_MODAL);
showDialog(2, ModalDialogManager.APP_MODAL);
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 2);
onView(withText("2")).check(matches(isDisplayed()));
onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist());
checkCurrentPresenter(ModalDialogManager.APP_MODAL);
// Perform back press. The app modal dialog should be dismissed.
// The first tab modal dialog should be shown. The tab modal container shouldn't be in the
// window hierarchy when an app modal dialog is showing.
Espresso.pressBack();
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 1);
onView(withText("2")).check(doesNotExist());
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(allOf(hasDescendant(withText("0")),
not(hasDescendant(withText("1"))), not(hasDescendant(withText("2"))))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Perform a second back press. The first tab modal dialog should be dismissed.
Espresso.pressBack();
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withText("2")).check(doesNotExist());
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(allOf(not(hasDescendant(withText("0"))),
hasDescendant(withText("1")), not(hasDescendant(withText("2"))))));
checkBrowserControls(true);
checkCurrentPresenter(ModalDialogManager.TAB_MODAL);
// Perform a third back press. The second tab modal dialog should be dismissed.
Espresso.pressBack();
checkPendingSize(ModalDialogManager.APP_MODAL, 0);
checkPendingSize(ModalDialogManager.TAB_MODAL, 0);
onView(withText("2")).check(doesNotExist());
onView(withId(R.id.tab_modal_dialog_container))
.check(matches(allOf(not(hasDescendant(withText("0"))),
not(hasDescendant(withText("1"))), not(hasDescendant(withText("2"))))));
checkBrowserControls(false);
checkCurrentPresenter(null);
}
private ModalDialogView createDialog(final int index) throws Exception {
return ThreadUtils.runOnUiThreadBlocking(() -> {
ModalDialogView.Controller controller = new ModalDialogView.Controller() {
@Override
public void onCancel() {}
@Override
public void onDismiss() {}
@Override
public void onClick(int buttonType) {
switch (buttonType) {
case ModalDialogView.BUTTON_POSITIVE:
case ModalDialogView.BUTTON_NEGATIVE:
dismissDialog(index);
break;
default:
Assert.fail("Unknown button type: " + buttonType);
}
}
};
final ModalDialogView.Params p = new ModalDialogView.Params();
p.title = Integer.toString(index);
p.positiveButtonTextId = R.string.ok;
p.negativeButtonTextId = R.string.cancel;
return new ModalDialogView(controller, p);
});
}
private void showDialog(
final int index, final @ModalDialogManager.ModalDialogType int dialogType) {
ThreadUtils.runOnUiThreadBlocking(
() -> mManager.showDialog(mModalDialogViews[index], dialogType));
}
private void showDialogAsNext(
final int index, final @ModalDialogManager.ModalDialogType int dialogType) {
ThreadUtils.runOnUiThreadBlocking(
() -> mManager.showDialog(mModalDialogViews[index], dialogType, true));
}
private void dismissDialog(final int index) {
ThreadUtils.runOnUiThreadBlocking(() -> mManager.dismissDialog(mModalDialogViews[index]));
}
private void checkPendingSize(
final @ModalDialogManager.ModalDialogType int dialogType, final int expected) {
ThreadUtils.runOnUiThreadBlocking(() -> {
List list = mManager.getPendingDialogsForTest(dialogType);
Assert.assertEquals(expected, list != null ? list.size() : 0);
});
}
private void checkCurrentPresenter(final Integer dialogType) {
ThreadUtils.runOnUiThreadBlocking(() -> {
if (dialogType == null) {
Assert.assertFalse(mManager.isShowing());
Assert.assertNull(mManager.getCurrentPresenterForTest());
} else {
Assert.assertTrue(mManager.isShowing());
Assert.assertEquals(mManager.getPresenterForTest(dialogType),
mManager.getCurrentPresenterForTest());
}
});
}
private void checkBrowserControls(boolean restricted) {
if (restricted) {
Assert.assertTrue("All tabs should be obscured", mActivity.isViewObscuringAllTabs());
onView(withId(R.id.menu_button)).check(matches(not(isEnabled())));
} else {
Assert.assertFalse("Tabs shouldn't be obscured", mActivity.isViewObscuringAllTabs());
onView(withId(R.id.menu_button)).check(matches(isEnabled()));
}
}
}