Commit 5d5c9c1e authored by Evan Stade's avatar Evan Stade Committed by Commit Bot

Android: close tab modal dialogs on navigate.

This doesn't affect most tab modals, such as permissions and js dialogs,
because those have associated C++ objects which react to navigations and
close the dialogs.

This affects/fixes the form re-post confirmation dialog, which until
now would not dismiss on a navigation. It also removes code to
explicitly close that dialog when the tab is destroyed, as it duplicated
functionality from TabModalLifetimeHandler.

Bug: 1059853
Change-Id: I9d6c3c1843c1b39faf5836adf535f108bfa00eaf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2095137
Commit-Queue: Evan Stade <estade@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Cr-Commit-Position: refs/heads/master@{#749750}
parent b6bce509
...@@ -41,6 +41,13 @@ public class TabModalLifetimeHandler implements NativeInitObserver, Destroyable ...@@ -41,6 +41,13 @@ public class TabModalLifetimeHandler implements NativeInitObserver, Destroyable
mActiveTab = null; mActiveTab = null;
} }
} }
@Override
public void onPageLoadStarted(Tab tab, String url) {
if (mActiveTab == tab) {
mManager.dismissDialogsOfType(ModalDialogType.TAB, DialogDismissalCause.NAVIGATE);
}
}
}; };
private final ChromeActivity mActivity; private final ChromeActivity mActivity;
......
...@@ -96,7 +96,7 @@ public class ActivityTabWebContentsDelegateAndroid extends TabWebContentsDelegat ...@@ -96,7 +96,7 @@ public class ActivityTabWebContentsDelegateAndroid extends TabWebContentsDelegat
SwipeRefreshHandler handler = SwipeRefreshHandler.get(mTab); SwipeRefreshHandler handler = SwipeRefreshHandler.get(mTab);
if (handler != null) handler.reset(); if (handler != null) handler.reset();
new RepostFormWarningHelper().show(); showRepostFormWarningTabModalDialog();
} }
@Override @Override
...@@ -364,69 +364,61 @@ public class ActivityTabWebContentsDelegateAndroid extends TabWebContentsDelegat ...@@ -364,69 +364,61 @@ public class ActivityTabWebContentsDelegateAndroid extends TabWebContentsDelegat
return mActivity != null && mActivity.isCustomTab(); return mActivity != null && mActivity.isCustomTab();
} }
private class RepostFormWarningHelper extends EmptyTabObserver { private void showRepostFormWarningTabModalDialog() {
private ModalDialogManager mModalDialogManager; // As a rule, showRepostFormWarningDialog should only be called on active tabs, as it's
private PropertyModel mDialogModel; // called right after WebContents::Activate. But in various corner cases, that
// activation may fail.
void show() { if (mActivity == null || !mTab.isUserInteractable()) {
if (mActivity == null) return; mTab.getWebContents().getNavigationController().cancelPendingReload();
mTab.addObserver(this); return;
mModalDialogManager = mActivity.getModalDialogManager(); }
ModalDialogProperties
.Controller dialogController = new ModalDialogProperties.Controller() {
@Override
public void onClick(PropertyModel model, int buttonType) {
if (buttonType == ModalDialogProperties.ButtonType.POSITIVE) {
mModalDialogManager.dismissDialog(
model, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
} else if (buttonType == ModalDialogProperties.ButtonType.NEGATIVE) {
mModalDialogManager.dismissDialog(
model, DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
}
}
@Override ModalDialogManager modalDialogManager = mActivity.getModalDialogManager();
public void onDismiss(PropertyModel model, int dismissalCause) {
mTab.removeObserver(RepostFormWarningHelper.this); ModalDialogProperties.Controller dialogController = new ModalDialogProperties.Controller() {
if (!mTab.isInitialized()) return; @Override
switch (dismissalCause) { public void onClick(PropertyModel model, int buttonType) {
case DialogDismissalCause.POSITIVE_BUTTON_CLICKED: if (buttonType == ModalDialogProperties.ButtonType.POSITIVE) {
mTab.getWebContents().getNavigationController().continuePendingReload(); modalDialogManager.dismissDialog(
break; model, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
case DialogDismissalCause.ACTIVITY_DESTROYED: } else if (buttonType == ModalDialogProperties.ButtonType.NEGATIVE) {
case DialogDismissalCause.TAB_DESTROYED: modalDialogManager.dismissDialog(
// Intentionally ignored as the tab object is gone. model, DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
break;
default:
mTab.getWebContents().getNavigationController().cancelPendingReload();
break;
}
} }
}; }
Resources resources = mActivity.getResources();
mDialogModel = new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
.with(ModalDialogProperties.CONTROLLER, dialogController)
.with(ModalDialogProperties.TITLE, resources,
R.string.http_post_warning_title)
.with(ModalDialogProperties.MESSAGE, resources,
R.string.http_post_warning)
.with(ModalDialogProperties.POSITIVE_BUTTON_TEXT, resources,
R.string.http_post_warning_resend)
.with(ModalDialogProperties.NEGATIVE_BUTTON_TEXT, resources,
R.string.cancel)
.with(ModalDialogProperties.CANCEL_ON_TOUCH_OUTSIDE, true)
.build();
mModalDialogManager.showDialog(
mDialogModel, ModalDialogManager.ModalDialogType.TAB, true);
}
@Override @Override
public void onDestroyed(Tab tab) { public void onDismiss(PropertyModel model, int dismissalCause) {
super.onDestroyed(tab); if (!mTab.isInitialized()) return;
mModalDialogManager.dismissDialog(mDialogModel, DialogDismissalCause.TAB_DESTROYED); switch (dismissalCause) {
} case DialogDismissalCause.POSITIVE_BUTTON_CLICKED:
mTab.getWebContents().getNavigationController().continuePendingReload();
break;
case DialogDismissalCause.ACTIVITY_DESTROYED:
case DialogDismissalCause.TAB_DESTROYED:
// Intentionally ignored as the tab object is gone.
break;
default:
mTab.getWebContents().getNavigationController().cancelPendingReload();
break;
}
}
};
Resources resources = mActivity.getResources();
PropertyModel dialogModel =
new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
.with(ModalDialogProperties.CONTROLLER, dialogController)
.with(ModalDialogProperties.TITLE, resources,
R.string.http_post_warning_title)
.with(ModalDialogProperties.MESSAGE, resources, R.string.http_post_warning)
.with(ModalDialogProperties.POSITIVE_BUTTON_TEXT, resources,
R.string.http_post_warning_resend)
.with(ModalDialogProperties.NEGATIVE_BUTTON_TEXT, resources,
R.string.cancel)
.with(ModalDialogProperties.CANCEL_ON_TOUCH_OUTSIDE, true)
.build();
modalDialogManager.showDialog(dialogModel, ModalDialogManager.ModalDialogType.TAB, true);
} }
} }
...@@ -57,6 +57,7 @@ import org.chromium.content_public.browser.test.util.Criteria; ...@@ -57,6 +57,7 @@ import org.chromium.content_public.browser.test.util.Criteria;
import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.content_public.common.BrowserControlsState; import org.chromium.content_public.common.BrowserControlsState;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.DialogDismissalCause;
import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType; import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
...@@ -507,6 +508,26 @@ public class ChromeTabModalPresenterTest { ...@@ -507,6 +508,26 @@ public class ChromeTabModalPresenterTest {
mExpectedDismissalCause = null; mExpectedDismissalCause = null;
} }
@Test
@SmallTest
@Feature({"ModalDialog"})
public void testDismiss_DismissalCause_TabNavigated() throws Exception {
PropertyModel dialog1 =
createDialog(mActivity, mActivity.getModalDialogManager(), "1", mTestObserver);
mExpectedDismissalCause = DialogDismissalCause.NAVIGATE;
int callCount = mTestObserver.onDialogDismissedCallback.getCallCount();
// Show a tab modal dialog and then navigate to a different page.
showDialog(mManager, dialog1, ModalDialogType.TAB);
EmbeddedTestServer server =
EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
mActivityTestRule.loadUrl(server.getURL("/chrome/test/data/android/simple.html"));
mTestObserver.onDialogDismissedCallback.waitForCallback(callCount);
mExpectedDismissalCause = null;
server.stopAndDestroyServer();
}
@Test @Test
@SmallTest @SmallTest
@Feature({"ModalDialog"}) @Feature({"ModalDialog"})
......
...@@ -14,7 +14,7 @@ import java.lang.annotation.RetentionPolicy; ...@@ -14,7 +14,7 @@ import java.lang.annotation.RetentionPolicy;
DialogDismissalCause.DISMISSED_BY_NATIVE, DialogDismissalCause.DISMISSED_BY_NATIVE,
DialogDismissalCause.NAVIGATE_BACK_OR_TOUCH_OUTSIDE, DialogDismissalCause.TAB_SWITCHED, DialogDismissalCause.NAVIGATE_BACK_OR_TOUCH_OUTSIDE, DialogDismissalCause.TAB_SWITCHED,
DialogDismissalCause.TAB_DESTROYED, DialogDismissalCause.ACTIVITY_DESTROYED, DialogDismissalCause.TAB_DESTROYED, DialogDismissalCause.ACTIVITY_DESTROYED,
DialogDismissalCause.NOT_ATTACHED_TO_WINDOW}) DialogDismissalCause.NOT_ATTACHED_TO_WINDOW, DialogDismissalCause.NAVIGATE})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface DialogDismissalCause { public @interface DialogDismissalCause {
// Please do not remove or change the order of the existing values, and add new value at the end // Please do not remove or change the order of the existing values, and add new value at the end
...@@ -41,4 +41,6 @@ public @interface DialogDismissalCause { ...@@ -41,4 +41,6 @@ public @interface DialogDismissalCause {
int ACTIVITY_DESTROYED = 8; int ACTIVITY_DESTROYED = 8;
/** The content view of the activity associated with the dialog is not attached to window. */ /** The content view of the activity associated with the dialog is not attached to window. */
int NOT_ATTACHED_TO_WINDOW = 9; int NOT_ATTACHED_TO_WINDOW = 9;
/** User has navigated, e.g. by typing a URL in the location bar. */
int NAVIGATE = 10;
} }
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