Commit c0d3d255 authored by MozLando's avatar MozLando
Browse files

Merge #7128



7128: Closes #7113: Implement the before unload prompt r=pocmo a=Amejia481
Co-authored-by: default avatarArturo Mejia <arturomejiamarmol@gmail.com>
parents 5f820348 c077fd36
......@@ -6,7 +6,7 @@ internal object GeckoVersions {
/**
* GeckoView Nightly Version.
*/
const val nightly_version = "78.0.20200526023857"
const val nightly_version = "78.0.20200527093527"
/**
* GeckoView Beta Version.
......
......@@ -23,6 +23,7 @@ import org.mozilla.geckoview.AllowOrDeny
import org.mozilla.geckoview.GeckoResult
import org.mozilla.geckoview.GeckoSession
import org.mozilla.geckoview.GeckoSession.PromptDelegate
import org.mozilla.geckoview.GeckoSession.PromptDelegate.BeforeUnloadPrompt
import org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.DATE
import org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.DATETIME_LOCAL
import org.mozilla.geckoview.GeckoSession.PromptDelegate.DateTimePrompt.Type.MONTH
......@@ -371,6 +372,22 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe
return geckoResult
}
override fun onBeforeUnloadPrompt(
session: GeckoSession,
geckoPrompt: BeforeUnloadPrompt
): GeckoResult<PromptResponse>? {
val geckoResult = GeckoResult<PromptResponse>()
val title = geckoPrompt.title ?: ""
val onAllow: () -> Unit = { geckoResult.complete(geckoPrompt.confirm(AllowOrDeny.ALLOW)) }
val onDeny: () -> Unit = { geckoResult.complete(geckoPrompt.confirm(AllowOrDeny.DENY)) }
geckoEngineSession.notifyObservers {
onPromptRequest(PromptRequest.BeforeUnload(title, onAllow, onDeny))
}
return geckoResult
}
override fun onSharePrompt(
session: GeckoSession,
prompt: PromptDelegate.SharePrompt
......
......@@ -805,6 +805,45 @@ class GeckoPromptDelegateTest {
assertTrue(onDenyWasCalled)
}
@Test
fun `onBeforeUnloadPrompt must provide a BeforeUnload PromptRequest`() {
val mockSession = GeckoEngineSession(runtime)
var request: PromptRequest.BeforeUnload? = null
var onAllowWasCalled = false
var onDenyWasCalled = false
val promptDelegate = GeckoPromptDelegate(mockSession)
mockSession.register(object : EngineSession.Observer {
override fun onPromptRequest(promptRequest: PromptRequest) {
request = promptRequest as PromptRequest.BeforeUnload
}
})
var geckoPrompt = GeckoBeforeUnloadPrompt()
var geckoResult = promptDelegate.onBeforeUnloadPrompt(mock(), geckoPrompt)
geckoResult!!.accept {
onAllowWasCalled = geckoPrompt.getGeckoResult()["allow"] == true
}
with(request!!) {
assertEquals(title, "")
onLeave()
assertTrue(onAllowWasCalled)
}
geckoPrompt = GeckoBeforeUnloadPrompt()
geckoResult = promptDelegate.onBeforeUnloadPrompt(mock(), geckoPrompt)
geckoResult!!.accept {
onDenyWasCalled = geckoPrompt.getGeckoResult()["allow"] == false
}
request!!.onStay()
assertTrue(onDenyWasCalled)
}
@Test
fun `onSharePrompt must provide a Share PromptRequest`() {
val mockSession = GeckoEngineSession(runtime)
......@@ -958,6 +997,8 @@ class GeckoPromptDelegateTest {
targetUri: String = "targetUri"
) : GeckoSession.PromptDelegate.PopupPrompt(targetUri)
class GeckoBeforeUnloadPrompt : GeckoSession.PromptDelegate.BeforeUnloadPrompt()
class GeckoSharePrompt(
title: String? = "title",
text: String? = "text",
......
......@@ -53,6 +53,20 @@ sealed class PromptRequest {
val onConfirm: (Boolean) -> Unit
) : PromptRequest(), Dismissible
/**
* BeforeUnloadPrompt represents the onbeforeunload prompt.
* This prompt is shown when a user is leaving a website and there is formation pending to be saved.
* For more information see https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload.
* @property title of the dialog.
* @property onLeave callback to notify that the user wants leave the site.
* @property onStay callback to notify that the user wants stay in the site.
*/
data class BeforeUnload(
val title: String,
val onLeave: () -> Unit,
val onStay: () -> Unit
) : PromptRequest()
/**
* Value type that represents a request for a save login prompt.
* @property hint a value that helps to determine the appropriate prompting behavior.
......
......@@ -24,6 +24,7 @@ import mozilla.components.browser.state.state.SessionState
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.prompt.Choice
import mozilla.components.concept.engine.prompt.PromptRequest
import mozilla.components.concept.engine.prompt.PromptRequest.BeforeUnload
import mozilla.components.concept.engine.prompt.PromptRequest.Alert
import mozilla.components.concept.engine.prompt.PromptRequest.Authentication
import mozilla.components.concept.engine.prompt.PromptRequest.Color
......@@ -300,6 +301,7 @@ class PromptFeature private constructor(
override fun onCancel(sessionId: String) {
store.consumePromptFrom(sessionId, activePrompt) {
when (it) {
is BeforeUnload -> it.onStay()
is Dismissible -> it.onDismiss()
is Popup -> it.onDeny()
}
......@@ -327,6 +329,7 @@ class PromptFeature private constructor(
}
is SingleChoice -> it.onConfirm(value as Choice)
is MenuChoice -> it.onConfirm(value as Choice)
is BeforeUnload -> it.onLeave()
is Popup -> it.onAllow()
is MultipleChoice -> it.onConfirm(value as Array<Choice>)
......@@ -529,6 +532,21 @@ class PromptFeature private constructor(
negativeButtonText = negativeLabel
)
}
is BeforeUnload -> {
val title = container.getString(R.string.mozac_feature_prompt_before_unload_dialog_title)
val body = container.getString(R.string.mozac_feature_prompt_before_unload_dialog_body)
val leaveLabel = container.getString(R.string.mozac_feature_prompts_before_unload_leave)
val stayLabel = container.getString(R.string.mozac_feature_prompts_before_unload_stay)
ConfirmDialogFragment.newInstance(
sessionId = session.id,
title = title,
message = body,
positiveButtonText = leaveLabel,
negativeButtonText = stayLabel
)
}
is Confirm -> {
with(promptRequest) {
......@@ -580,6 +598,7 @@ class PromptFeature private constructor(
is File,
is Color,
is Authentication,
is BeforeUnload,
is Popup,
is SaveLoginPrompt,
is SelectLoginPrompt,
......
......@@ -40,6 +40,14 @@
<string name="mozac_feature_prompts_allow">Allow</string>
<!-- Text of a negative button in dialog requesting to open a new window. -->
<string name="mozac_feature_prompts_deny">Deny</string>
<!-- Title of the dialog shown when a user is leaving a website and there is still data not saved yet. -->
<string name="mozac_feature_prompt_before_unload_dialog_title">Are you sure?</string>
<!-- Body text of the dialog shown when a user is leaving a website and there is still data not saved yet. -->
<string name="mozac_feature_prompt_before_unload_dialog_body">Do you want to leave this site? Data you have entered may not be saved</string>
<!-- Stay button of the dialog shown when a user is leaving a website and there is still data not saved yet, this indicates that the user wants to stay in the website. -->
<string name="mozac_feature_prompts_before_unload_stay">Stay</string>
<!-- Leave button of the dialog shown when a user is leaving a website and there is still data not saved yet, this indicates that the user wants to leave in the website. -->
<string name="mozac_feature_prompts_before_unload_leave">Leave</string>
<!-- Title of the month chooser dialog. -->
<string name="mozac_feature_prompts_set_month">Pick a month</string>
<!-- January (short description), used on the month chooser dialog. -->
......
......@@ -520,6 +520,34 @@ class PromptFeatureTest {
assertTrue(onDismissWasCalled)
}
@Test
fun `Calling onConfirm on a BeforeUnload request will consume promptRequest`() {
val fragment: Fragment = mock()
whenever(fragment.getString(R.string.mozac_feature_prompt_before_unload_dialog_title)).thenReturn("")
whenever(fragment.getString(R.string.mozac_feature_prompt_before_unload_dialog_body)).thenReturn("")
whenever(fragment.getString(R.string.mozac_feature_prompts_before_unload_stay)).thenReturn("")
whenever(fragment.getString(R.string.mozac_feature_prompts_before_unload_leave)).thenReturn("")
val feature = PromptFeature(fragment = fragment, store = store, fragmentManager = fragmentManager) { }
var onLeaveWasCalled = false
val promptRequest = PromptRequest.BeforeUnload(
title = "title",
onLeave = { onLeaveWasCalled = true },
onStay = { }
)
feature.start()
store.dispatch(ContentAction.UpdatePromptRequestAction(tabId, promptRequest)).joinBlocking()
feature.onConfirm(tabId, "" to "")
store.waitUntilIdle()
assertNull(tab()?.content?.promptRequest)
assertTrue(onLeaveWasCalled)
}
@Test
fun `Calling onCancel on a authentication request will consume promptRequest and call onDismiss`() {
val feature = PromptFeature(activity = mock(), store = store, fragmentManager = fragmentManager) { }
......@@ -630,6 +658,31 @@ class PromptFeatureTest {
assertTrue(onCancelWasCalled)
}
@Test
fun `Calling onCancel on a BeforeUnload request will consume promptRequest`() {
val fragment: Fragment = mock()
whenever(fragment.getString(R.string.mozac_feature_prompt_before_unload_dialog_title)).thenReturn("")
whenever(fragment.getString(R.string.mozac_feature_prompt_before_unload_dialog_body)).thenReturn("")
whenever(fragment.getString(R.string.mozac_feature_prompts_before_unload_stay)).thenReturn("")
whenever(fragment.getString(R.string.mozac_feature_prompts_before_unload_leave)).thenReturn("")
val feature = PromptFeature(fragment = fragment, store = store, fragmentManager = fragmentManager) { }
var onCancelWasCalled = false
val promptRequest = PromptRequest.BeforeUnload("http://www.test.com/", { }) {
onCancelWasCalled = true
}
feature.start()
store.dispatch(ContentAction.UpdatePromptRequestAction(tabId, promptRequest)).joinBlocking()
feature.onCancel(tabId)
store.waitUntilIdle()
assertNull(tab()?.content?.promptRequest)
assertTrue(onCancelWasCalled)
}
@Test
fun `Calling onConfirm on a confirm request will consume promptRequest`() {
val feature = PromptFeature(activity = mock(), store = store, fragmentManager = fragmentManager) { }
......
......@@ -12,6 +12,9 @@ permalink: /changelog/
* [Gecko](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Gecko.kt)
* [Configuration](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Config.kt)
* **browser-engine-gecko-nightly**
* Added support for [onbeforeunload prompt](https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload)
# 43.0.0
* [Commits](https://github.com/mozilla-mobile/android-components/compare/v42.0.0...v43.0.0)
......
Supports Markdown
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