Bug 1810047 - Implement UI for webextensions optional permissions.

fenix/120.0
William Durand 9 months ago committed by mergify[bot]
parent 814400a287
commit 5264d19c7c

@ -81,6 +81,10 @@ class WebExtensionPromptFeature(
addon,
promptRequest,
)
is WebExtensionPromptRequest.AfterInstallation.OptionalPermissions -> handleOptionalPermissionsRequest(
addon,
promptRequest,
)
is WebExtensionPromptRequest.AfterInstallation.PostInstallation -> handlePostInstallationRequest(
addon.copy(installedState = promptRequest.extension.toInstalledState()),
)
@ -108,10 +112,32 @@ class WebExtensionPromptFeature(
addon: Addon,
promptRequest: WebExtensionPromptRequest.AfterInstallation.Permissions,
) {
if (hasExistingPermissionDialogFragment()) return
showPermissionDialog(
addon,
promptRequest,
addon = addon,
onConfirm = promptRequest.onConfirm,
)
}
@VisibleForTesting
internal fun handleOptionalPermissionsRequest(
addon: Addon,
promptRequest: WebExtensionPromptRequest.AfterInstallation.OptionalPermissions,
) {
val shouldGrantWithoutPrompt = Addon.localizePermissions(promptRequest.permissions, context).isEmpty()
// If we don't have any promptable permissions, just proceed.
if (shouldGrantWithoutPrompt) {
promptRequest.onConfirm(true)
consumePromptRequest()
return
}
showPermissionDialog(
// This is a bit of a hack so that the permission prompt only lists
// the optional permissions that are requested.
addon = addon.copy(permissions = promptRequest.permissions),
onConfirm = promptRequest.onConfirm,
forOptionalPermissions = true,
)
}
@ -185,37 +211,43 @@ class WebExtensionPromptFeature(
@VisibleForTesting
internal fun showPermissionDialog(
addon: Addon,
promptRequest: WebExtensionPromptRequest.AfterInstallation.Permissions,
onConfirm: (Boolean) -> Unit,
forOptionalPermissions: Boolean = false,
) {
if (!isInstallationInProgress && !hasExistingPermissionDialogFragment()) {
val dialog = PermissionsDialogFragment.newInstance(
addon = addon,
promptsStyling = PermissionsDialogFragment.PromptsStyling(
gravity = Gravity.BOTTOM,
shouldWidthMatchParent = true,
positiveButtonBackgroundColor = ThemeManager.resolveAttribute(
R.attr.accent,
context,
),
positiveButtonTextColor = ThemeManager.resolveAttribute(
R.attr.textOnColorPrimary,
context,
),
positiveButtonRadius =
(context.resources.getDimensionPixelSize(R.dimen.tab_corner_radius)).toFloat(),
),
onPositiveButtonClicked = {
handleApprovedPermissions(promptRequest)
},
onNegativeButtonClicked = {
handleDeniedPermissions(promptRequest)
},
)
dialog.show(
fragmentManager,
PERMISSIONS_DIALOG_FRAGMENT_TAG,
)
if (isInstallationInProgress || hasExistingPermissionDialogFragment()) {
return
}
val dialog = PermissionsDialogFragment.newInstance(
addon = addon,
forOptionalPermissions = forOptionalPermissions,
promptsStyling = PermissionsDialogFragment.PromptsStyling(
gravity = Gravity.BOTTOM,
shouldWidthMatchParent = true,
positiveButtonBackgroundColor = ThemeManager.resolveAttribute(
R.attr.accent,
context,
),
positiveButtonTextColor = ThemeManager.resolveAttribute(
R.attr.textOnColorPrimary,
context,
),
positiveButtonRadius =
(context.resources.getDimensionPixelSize(R.dimen.tab_corner_radius)).toFloat(),
),
onPositiveButtonClicked = {
onConfirm(true)
consumePromptRequest()
},
onNegativeButtonClicked = {
onConfirm(false)
consumePromptRequest()
},
)
dialog.show(
fragmentManager,
PERMISSIONS_DIALOG_FRAGMENT_TAG,
)
}
private fun tryToReAttachButtonHandlersToPreviousDialog() {

@ -14,7 +14,9 @@ import mozilla.components.browser.state.action.WebExtensionAction.UpdatePromptRe
import mozilla.components.browser.state.state.extension.WebExtensionPromptRequest
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.webextension.WebExtensionInstallException
import mozilla.components.feature.addons.Addon
import mozilla.components.support.ktx.android.content.appVersionName
import mozilla.components.support.test.any
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.robolectric.testContext
import mozilla.components.support.test.rule.MainCoroutineRule
@ -216,4 +218,77 @@ class WebExtensionPromptFeatureTest {
verify { webExtensionPromptFeature.showDialog(expectedTitle, expectedMessage) }
}
@Test
fun `WHEN OptionalPermissions is dispatched THEN handleOptionalPermissionsRequest is called`() {
webExtensionPromptFeature.start()
every { webExtensionPromptFeature.handleOptionalPermissionsRequest(any(), any()) } just runs
store.dispatch(
UpdatePromptRequestWebExtensionAction(
WebExtensionPromptRequest.AfterInstallation.OptionalPermissions(
mockk(relaxed = true),
mockk(),
mockk(),
),
),
).joinBlocking()
verify { webExtensionPromptFeature.handleOptionalPermissionsRequest(any(), any()) }
}
@Test
fun `WHEN calling handleOptionalPermissionsRequest with permissions THEN call showPermissionDialog`() {
val addon: Addon = mockk(relaxed = true)
val onConfirm: ((Boolean) -> Unit) = mockk()
val promptRequest = WebExtensionPromptRequest.AfterInstallation.OptionalPermissions(
extension = mockk(),
permissions = listOf("tabs"),
onConfirm = onConfirm,
)
webExtensionPromptFeature.handleOptionalPermissionsRequest(
addon = addon,
promptRequest = promptRequest,
)
verify { webExtensionPromptFeature.showPermissionDialog(any(), eq(onConfirm), eq(true)) }
// We should verify that only the requested optional permissions are assigned to the add-on because
// those are the permissions that are going to be listed in the dialog.
verify { addon.copy(permissions = promptRequest.permissions) }
}
@Test
fun `WHEN calling handleOptionalPermissionsRequest with a permission that doesn't have a description THEN do not call showPermissionDialog`() {
val onConfirm: ((Boolean) -> Unit) = mockk()
every { onConfirm(any()) } just runs
val promptRequest = WebExtensionPromptRequest.AfterInstallation.OptionalPermissions(
extension = mockk(),
// The "scripting" API permission doesn't have a description so we should not show a dialog for it.
permissions = listOf("scripting"),
onConfirm = onConfirm,
)
webExtensionPromptFeature.handleOptionalPermissionsRequest(addon = mockk(relaxed = true), promptRequest = promptRequest)
verify(exactly = 0) { webExtensionPromptFeature.showPermissionDialog(any(), any(), any()) }
verify(exactly = 1) { onConfirm(true) }
}
@Test
fun `WHEN calling handleOptionalPermissionsRequest with no permissions THEN do not call showPermissionDialog`() {
val onConfirm: ((Boolean) -> Unit) = mockk()
every { onConfirm(any()) } just runs
val promptRequest = WebExtensionPromptRequest.AfterInstallation.OptionalPermissions(
extension = mockk(),
permissions = emptyList(),
onConfirm = onConfirm,
)
webExtensionPromptFeature.handleOptionalPermissionsRequest(addon = mockk(relaxed = true), promptRequest = promptRequest)
verify(exactly = 0) { webExtensionPromptFeature.showPermissionDialog(any(), any(), any()) }
verify(exactly = 1) { onConfirm(true) }
}
}

Loading…
Cancel
Save