Bug 1659073 - Implement confirmRepost on Mobile. r=owlish,snorp

Differential Revision: https://phabricator.services.mozilla.com/D89658
This commit is contained in:
Agi Sferro 2020-09-10 22:28:17 +00:00
Родитель c978775400
Коммит 68bde3475c
9 изменённых файлов: 182 добавлений и 1 удалений

Просмотреть файл

@ -20,6 +20,15 @@ XPCOMUtils.defineLazyModuleGetters(this, {
const { debug, warn } = GeckoViewUtils.initLogging("PromptCollection");
class PromptCollection {
confirmRepost(browsingContext) {
const msg = {
type: "repost",
};
const prompter = new GeckoViewPrompter(browsingContext);
const result = prompter.showPrompt(msg);
return !!result?.allow;
}
beforeUnloadCheck(browsingContext) {
const msg = {
type: "beforeUnload",

Просмотреть файл

@ -927,6 +927,7 @@ package org.mozilla.geckoview {
method @UiThread @Nullable default public GeckoResult<GeckoSession.PromptDelegate.PromptResponse> onLoginSave(@NonNull GeckoSession, @NonNull GeckoSession.PromptDelegate.AutocompleteRequest<Autocomplete.LoginSaveOption>);
method @UiThread @Nullable default public GeckoResult<GeckoSession.PromptDelegate.PromptResponse> onLoginSelect(@NonNull GeckoSession, @NonNull GeckoSession.PromptDelegate.AutocompleteRequest<Autocomplete.LoginSelectOption>);
method @UiThread @Nullable default public GeckoResult<GeckoSession.PromptDelegate.PromptResponse> onPopupPrompt(@NonNull GeckoSession, @NonNull GeckoSession.PromptDelegate.PopupPrompt);
method @UiThread @Nullable default public GeckoResult<GeckoSession.PromptDelegate.PromptResponse> onRepostConfirmPrompt(@NonNull GeckoSession, @NonNull GeckoSession.PromptDelegate.RepostConfirmPrompt);
method @UiThread @Nullable default public GeckoResult<GeckoSession.PromptDelegate.PromptResponse> onSharePrompt(@NonNull GeckoSession, @NonNull GeckoSession.PromptDelegate.SharePrompt);
method @UiThread @Nullable default public GeckoResult<GeckoSession.PromptDelegate.PromptResponse> onTextPrompt(@NonNull GeckoSession, @NonNull GeckoSession.PromptDelegate.TextPrompt);
}
@ -1084,6 +1085,11 @@ package org.mozilla.geckoview {
public static class GeckoSession.PromptDelegate.PromptResponse {
}
public static class GeckoSession.PromptDelegate.RepostConfirmPrompt extends GeckoSession.PromptDelegate.BasePrompt {
ctor protected RepostConfirmPrompt();
method @UiThread @NonNull public GeckoSession.PromptDelegate.PromptResponse confirm(@Nullable AllowOrDeny);
}
public static class GeckoSession.PromptDelegate.SharePrompt extends GeckoSession.PromptDelegate.BasePrompt {
ctor protected SharePrompt(@Nullable String, @Nullable String, @Nullable String);
method @UiThread @NonNull public GeckoSession.PromptDelegate.PromptResponse confirm(int);

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<form action="hello.html" method="post">
<input id=text>
<button id=submit>Submit</button>
</form>
</body>
</html>

Просмотреть файл

@ -26,6 +26,7 @@ import kotlin.reflect.KClass
*/
open class BaseSessionTest(noErrorCollector: Boolean = false) {
companion object {
const val RESUBMIT_CONFIRM = "/assets/www/resubmit.html"
const val BEFORE_UNLOAD = "/assets/www/beforeunload.html"
const val CLICK_TO_RELOAD_HTML_PATH = "/assets/www/clickToReload.html"
const val CONTENT_CRASH_URL = "about:crashcontent"

Просмотреть файл

@ -147,6 +147,66 @@ class PromptDelegateTest : BaseSessionTest() {
equalTo(false))
}
@Test
fun onFormResubmissionPrompt() {
sessionRule.session.loadTestPath(RESUBMIT_CONFIRM)
sessionRule.waitForPageStop()
sessionRule.session.evaluateJS(
"document.querySelector('#text').value = 'Some text';" +
"document.querySelector('#submit').click();"
)
// Submitting the form causes a navigation
sessionRule.waitForPageStop()
val result = GeckoResult<Void>()
sessionRule.delegateUntilTestEnd(object: Callbacks.ProgressDelegate {
override fun onPageStart(session: GeckoSession, url: String) {
assertThat("Only HELLO_HTML_PATH should load", url, endsWith(HELLO_HTML_PATH))
result.complete(null)
}
})
val promptResult = GeckoResult<PromptDelegate.PromptResponse>()
val promptResult2 = GeckoResult<PromptDelegate.PromptResponse>()
sessionRule.delegateUntilTestEnd(object : Callbacks.PromptDelegate {
@AssertCalled(count = 2)
override fun onRepostConfirmPrompt(session: GeckoSession, prompt: PromptDelegate.RepostConfirmPrompt): GeckoResult<PromptDelegate.PromptResponse>? {
// We have to return something here because otherwise the delegate will be invoked
// before we have a chance to override it in the waitUntilCalled call below
return forEachCall(promptResult, promptResult2)
}
})
// This should trigger a confirm resubmit prompt
sessionRule.session.reload();
sessionRule.waitUntilCalled(object : Callbacks.PromptDelegate {
@AssertCalled(count = 1)
override fun onRepostConfirmPrompt(session: GeckoSession, prompt: PromptDelegate.RepostConfirmPrompt): GeckoResult<PromptDelegate.PromptResponse>? {
promptResult.complete(prompt.confirm(AllowOrDeny.DENY))
return promptResult
}
})
sessionRule.waitForResult(promptResult)
// Trigger it again, this time the load should go through
sessionRule.session.reload();
sessionRule.waitUntilCalled(object : Callbacks.PromptDelegate {
@AssertCalled(count = 1)
override fun onRepostConfirmPrompt(session: GeckoSession, prompt: PromptDelegate.RepostConfirmPrompt): GeckoResult<PromptDelegate.PromptResponse>? {
promptResult2.complete(prompt.confirm(AllowOrDeny.ALLOW))
return promptResult2
}
})
sessionRule.waitForResult(promptResult2)
sessionRule.waitForResult(result)
}
@Test
fun onBeforeUnloadTest() {
sessionRule.setPrefsUntilTestEnd(mapOf(

Просмотреть файл

@ -2775,6 +2775,12 @@ public class GeckoSession implements Parcelable {
res = delegate.onBeforeUnloadPrompt(session, prompt);
break;
}
case "repost": {
final PromptDelegate.RepostConfirmPrompt prompt =
new PromptDelegate.RepostConfirmPrompt();
res = delegate.onRepostConfirmPrompt(session, prompt);
break;
}
case "button": {
final PromptDelegate.ButtonPrompt prompt =
new PromptDelegate.ButtonPrompt(title, msg);
@ -4087,6 +4093,31 @@ public class GeckoSession implements Parcelable {
}
}
/**
* RepostConfirmPrompt represents a prompt shown whenever the browser
* needs to resubmit POST data (e.g. due to page refresh).
*/
class RepostConfirmPrompt extends BasePrompt {
protected RepostConfirmPrompt() {
super(null);
}
/**
* Confirms the prompt.
*
* @param allowOrDeny whether the browser should allow resubmitting
* data.
*
* @return A {@link PromptResponse} which can be used to complete
* the {@link GeckoResult} associated with this prompt.
*/
@UiThread
public @NonNull PromptResponse confirm(final @Nullable AllowOrDeny allowOrDeny) {
ensureResult().putBoolean("allow", allowOrDeny != AllowOrDeny.DENY);
return super.confirm();
}
}
/**
* AlertPrompt contains the information necessary to represent a JavaScript
* alert() call from content; it can only be dismissed, not confirmed.
@ -5020,6 +5051,27 @@ public class GeckoSession implements Parcelable {
return null;
}
/**
* Display a POST resubmission confirmation prompt.
*
* This prompt will trigger whenever refreshing or navigating to a page needs resubmitting
* POST data that has been submitted already.
*
* @param session GeckoSession that triggered the prompt
* @param prompt the {@link RepostConfirmPrompt} that describes the
* prompt.
* @return A {@link GeckoResult} resolving to {@link AllowOrDeny#ALLOW}
* if the page is allowed to continue with the navigation and resubmit the POST
* data or {@link AllowOrDeny#DENY} otherwise.
*/
@UiThread
default @Nullable GeckoResult<PromptResponse> onRepostConfirmPrompt(
@NonNull final GeckoSession session,
@NonNull final RepostConfirmPrompt prompt
) {
return null;
}
/**
* Display a button prompt.
*

Просмотреть файл

@ -27,10 +27,14 @@ exclude: true
([bug 1658456]({{bugzilla}}1658456))
- ⚠️ Use [`Image`][82.3] for [`MediaSession`][81.6] artwork and [`WebExtension`][69.5] icon support.
([bug 1662508]({{bugzilla}}1662508))
- Added [`RepostConfirmPrompt`][82.4] to prompt the user for cofirmation before
resending POST requests.
([bug 1659073]({{bugzilla}}1659073))
[82.1]: {{javadoc_uri}}/GeckoSession.ContentDelegate.html#onExternalResponse-org.mozilla.geckoview.GeckoSession-org.mozilla.geckoview.GeckoSession.WebResponseInfo-
[82.2]: {{javadoc_uri}}/GeckoSession.ContentDelegate.html#onExternalResponse-org.mozilla.geckoview.GeckoSession-org.mozilla.geckoview.GeckoResult-
[82.3]: {{javadoc_uri}}/Image.html
[82.4]: {{javadoc_uri}}/GeckoSession.PromptDelegate.RepostConfirmPrompt.html
## v81
- Added `cookiePurging` to [`ContentBlocking.Settings.Builder`][81.1] and `getCookiePurging` and `setCookiePurging`
@ -789,4 +793,4 @@ to allow adding gecko profiler markers.
[65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
[65.25]: {{javadoc_uri}}/GeckoResult.html
[api-version]: 802b991116bf1a90050c412c32bc8ac3e7343fed
[api-version]: b2f304bfc18a9b3ce4bbe4cc12bc31be42f6fde8

Просмотреть файл

@ -122,6 +122,37 @@ final class BasicGeckoViewPrompt implements GeckoSession.PromptDelegate {
return GeckoResult.fromValue(prompt.dismiss());
}
@Nullable
@Override
public GeckoResult<PromptResponse> onRepostConfirmPrompt(final GeckoSession session,
final RepostConfirmPrompt prompt) {
final Activity activity = mActivity;
if (activity == null) {
return GeckoResult.fromValue(prompt.dismiss());
}
final AlertDialog.Builder builder = new AlertDialog.Builder(activity)
.setTitle(R.string.repost_confirm_title)
.setMessage(R.string.repost_confirm_message);
GeckoResult<PromptResponse> res = new GeckoResult<>();
final DialogInterface.OnClickListener listener = (dialog, which) -> {
if (which == DialogInterface.BUTTON_POSITIVE) {
res.complete(prompt.confirm(AllowOrDeny.ALLOW));
} else if (which == DialogInterface.BUTTON_NEGATIVE) {
res.complete(prompt.confirm(AllowOrDeny.DENY));
} else {
res.complete(prompt.dismiss());
}
};
builder.setPositiveButton(R.string.repost_confirm_resend, listener);
builder.setNegativeButton(R.string.repost_confirm_cancel, listener);
createStandardDialog(builder, prompt, res).show();
return res;
}
@Nullable
@Override
public GeckoResult<PromptResponse> onBeforeUnloadPrompt(final GeckoSession session,

Просмотреть файл

@ -58,11 +58,17 @@
<string name="key_allow_extensions_in_private_browsing">allow_extensions_in_private_browsing</string>
<string name="key_preferred_color_scheme">preferred_color_scheme</string>
<string name="key_user_agent_override">user_agent_override</string>
<string name="before_unload_message">This page is asking you to confirm that you want to leave - data you have entered may not be saved</string>
<string name="before_unload_title">Are you sure?</string>
<string name="before_unload_leave_page">Leave Page</string>
<string name="before_unload_stay">Stay on Page</string>
<string name="repost_confirm_message">To display this page, GeckoViewExample must send information that will repeat any action (such as a search or order confirmation) that was performed earlier.</string>
<string name="repost_confirm_title">Are you sure?</string>
<string name="repost_confirm_resend">Resend</string>
<string name="repost_confirm_cancel">Cancel</string>
<string-array name="pref_preferred_color_scheme_display_names">
<item>Follow System Preference</item>
<item>Light</item>