Simplify `PhoneFeature` code (#10810)
parent
74948cb3f1
commit
1a19b06227
|
@ -4,26 +4,33 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.settings
|
package org.mozilla.fenix.settings
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.RadioButton
|
import android.widget.RadioButton
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.core.text.HtmlCompat
|
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||||
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelative
|
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelative
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.theme.ThemeManager
|
import org.mozilla.fenix.theme.ThemeManager
|
||||||
|
|
||||||
fun SitePermissions.toggle(featurePhone: PhoneFeature): SitePermissions {
|
fun SitePermissions.toggle(featurePhone: PhoneFeature): SitePermissions {
|
||||||
return when (featurePhone) {
|
return update(featurePhone, get(featurePhone).toggle())
|
||||||
PhoneFeature.CAMERA -> copy(camera = camera.toggle())
|
}
|
||||||
PhoneFeature.LOCATION -> copy(location = location.toggle())
|
|
||||||
PhoneFeature.MICROPHONE -> copy(microphone = microphone.toggle())
|
fun SitePermissions.get(field: PhoneFeature) = when (field) {
|
||||||
PhoneFeature.NOTIFICATION -> copy(notification = notification.toggle())
|
PhoneFeature.CAMERA -> camera
|
||||||
PhoneFeature.AUTOPLAY_AUDIBLE -> copy(autoplayAudible = autoplayAudible.toggle())
|
PhoneFeature.LOCATION -> location
|
||||||
PhoneFeature.AUTOPLAY_INAUDIBLE -> copy(autoplayInaudible = autoplayInaudible.toggle())
|
PhoneFeature.MICROPHONE -> microphone
|
||||||
}
|
PhoneFeature.NOTIFICATION -> notification
|
||||||
|
PhoneFeature.AUTOPLAY_AUDIBLE -> autoplayAudible
|
||||||
|
PhoneFeature.AUTOPLAY_INAUDIBLE -> autoplayInaudible
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SitePermissions.update(field: PhoneFeature, value: SitePermissions.Status) = when (field) {
|
||||||
|
PhoneFeature.CAMERA -> copy(camera = value)
|
||||||
|
PhoneFeature.LOCATION -> copy(location = value)
|
||||||
|
PhoneFeature.MICROPHONE -> copy(microphone = value)
|
||||||
|
PhoneFeature.NOTIFICATION -> copy(notification = value)
|
||||||
|
PhoneFeature.AUTOPLAY_AUDIBLE -> copy(autoplayAudible = value)
|
||||||
|
PhoneFeature.AUTOPLAY_INAUDIBLE -> copy(autoplayInaudible = value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,26 +46,6 @@ fun RadioButton.setStartCheckedIndicator() {
|
||||||
putCompoundDrawablesRelative(start = buttonDrawable)
|
putCompoundDrawablesRelative(start = buttonDrawable)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initBlockedByAndroidView(phoneFeature: PhoneFeature, blockedByAndroidView: View) {
|
|
||||||
val context = blockedByAndroidView.context
|
|
||||||
if (!phoneFeature.isAndroidPermissionGranted(context)) {
|
|
||||||
blockedByAndroidView.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
val descriptionLabel = blockedByAndroidView.findViewById<TextView>(R.id.blocked_by_android_feature_label)
|
|
||||||
val descriptionText = context.getString(
|
|
||||||
R.string.phone_feature_blocked_step_feature,
|
|
||||||
phoneFeature.getLabel(context)
|
|
||||||
)
|
|
||||||
descriptionLabel.text = HtmlCompat.fromHtml(descriptionText, HtmlCompat.FROM_HTML_MODE_COMPACT)
|
|
||||||
|
|
||||||
val permissionsLabel = blockedByAndroidView.findViewById<TextView>(R.id.blocked_by_android_permissions_label)
|
|
||||||
val permissionsText = context.getString(R.string.phone_feature_blocked_step_permissions)
|
|
||||||
permissionsLabel.text = HtmlCompat.fromHtml(permissionsText, HtmlCompat.FROM_HTML_MODE_COMPACT)
|
|
||||||
} else {
|
|
||||||
blockedByAndroidView.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the callback to be invoked when this preference is changed by the user (but before
|
* Sets the callback to be invoked when this preference is changed by the user (but before
|
||||||
* the internal state has been updated). Allows the type of the preference to be specified.
|
* the internal state has been updated). Allows the type of the preference to be specified.
|
||||||
|
|
|
@ -8,7 +8,9 @@ import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||||
import android.Manifest.permission.ACCESS_FINE_LOCATION
|
import android.Manifest.permission.ACCESS_FINE_LOCATION
|
||||||
import android.Manifest.permission.RECORD_AUDIO
|
import android.Manifest.permission.RECORD_AUDIO
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Parcelable
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import kotlinx.android.parcel.Parcelize
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
||||||
import mozilla.components.support.ktx.android.content.isPermissionGranted
|
import mozilla.components.support.ktx.android.content.isPermissionGranted
|
||||||
|
@ -21,26 +23,17 @@ import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_BLOCK_AUDIBLE
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
import android.Manifest.permission.CAMERA as CAMERA_PERMISSION
|
import android.Manifest.permission.CAMERA as CAMERA_PERMISSION
|
||||||
|
|
||||||
const val ID_CAMERA_PERMISSION = 0
|
@Parcelize
|
||||||
const val ID_LOCATION_PERMISSION = 1
|
enum class PhoneFeature(val androidPermissionsList: Array<String>) : Parcelable {
|
||||||
const val ID_MICROPHONE_PERMISSION = 2
|
CAMERA(arrayOf(CAMERA_PERMISSION)),
|
||||||
const val ID_NOTIFICATION_PERMISSION = 3
|
LOCATION(arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION)),
|
||||||
const val ID_AUTOPLAY_AUDIBLE_PERMISSION = 4
|
MICROPHONE(arrayOf(RECORD_AUDIO)),
|
||||||
const val ID_AUTOPLAY_INAUDIBLE_PERMISSION = 5
|
NOTIFICATION(emptyArray()),
|
||||||
|
AUTOPLAY_AUDIBLE(emptyArray()),
|
||||||
enum class PhoneFeature(val id: Int, val androidPermissionsList: Array<String>) {
|
AUTOPLAY_INAUDIBLE(emptyArray());
|
||||||
CAMERA(ID_CAMERA_PERMISSION, arrayOf(CAMERA_PERMISSION)),
|
|
||||||
LOCATION(ID_LOCATION_PERMISSION, arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION)),
|
|
||||||
MICROPHONE(ID_MICROPHONE_PERMISSION, arrayOf(RECORD_AUDIO)),
|
|
||||||
NOTIFICATION(ID_NOTIFICATION_PERMISSION, emptyArray()),
|
|
||||||
AUTOPLAY_AUDIBLE(ID_AUTOPLAY_AUDIBLE_PERMISSION, emptyArray()),
|
|
||||||
AUTOPLAY_INAUDIBLE(ID_AUTOPLAY_INAUDIBLE_PERMISSION, emptyArray());
|
|
||||||
|
|
||||||
fun isAndroidPermissionGranted(context: Context): Boolean {
|
fun isAndroidPermissionGranted(context: Context): Boolean {
|
||||||
return when (this) {
|
return context.isPermissionGranted(androidPermissionsList.asIterable())
|
||||||
CAMERA, LOCATION, MICROPHONE -> context.isPermissionGranted(androidPermissionsList.asIterable())
|
|
||||||
NOTIFICATION, AUTOPLAY_AUDIBLE, AUTOPLAY_INAUDIBLE -> true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("ComplexMethod")
|
@Suppress("ComplexMethod")
|
||||||
|
@ -78,7 +71,7 @@ enum class PhoneFeature(val id: Int, val androidPermissionsList: Array<String>)
|
||||||
sitePermissions: SitePermissions? = null,
|
sitePermissions: SitePermissions? = null,
|
||||||
settings: Settings? = null
|
settings: Settings? = null
|
||||||
): SitePermissions.Status {
|
): SitePermissions.Status {
|
||||||
val status = getStatus(sitePermissions) ?: settings?.let(::getAction)?.toStatus()
|
val status = sitePermissions?.get(this) ?: settings?.let(::getAction)?.toStatus()
|
||||||
return requireNotNull(status)
|
return requireNotNull(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,18 +107,6 @@ enum class PhoneFeature(val id: Int, val androidPermissionsList: Array<String>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getStatus(sitePermissions: SitePermissions?): SitePermissions.Status? {
|
|
||||||
sitePermissions ?: return null
|
|
||||||
return when (this) {
|
|
||||||
CAMERA -> sitePermissions.camera
|
|
||||||
LOCATION -> sitePermissions.location
|
|
||||||
MICROPHONE -> sitePermissions.microphone
|
|
||||||
NOTIFICATION -> sitePermissions.notification
|
|
||||||
AUTOPLAY_AUDIBLE -> sitePermissions.autoplayAudible
|
|
||||||
AUTOPLAY_INAUDIBLE -> sitePermissions.autoplayInaudible
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun findFeatureBy(permissions: Array<out String>): PhoneFeature? {
|
fun findFeatureBy(permissions: Array<out String>): PhoneFeature? {
|
||||||
return values().find { feature ->
|
return values().find { feature ->
|
||||||
|
|
|
@ -52,7 +52,7 @@ interface QuickSettingsController {
|
||||||
* Default behavior of [QuickSettingsController]. Other implementations are possible.
|
* Default behavior of [QuickSettingsController]. Other implementations are possible.
|
||||||
*
|
*
|
||||||
* @param context [Context] used for various Android interactions.
|
* @param context [Context] used for various Android interactions.
|
||||||
* @param quickSettingsStore [QuickSettingsFragmentStore] holding the [State] for all Views displayed
|
* @param quickSettingsStore [QuickSettingsFragmentStore] holding the State for all Views displayed
|
||||||
* in this Controller's Fragment.
|
* in this Controller's Fragment.
|
||||||
* @param coroutineScope [CoroutineScope] used for structed concurrency.
|
* @param coroutineScope [CoroutineScope] used for structed concurrency.
|
||||||
* @param navController NavController] used for navigation.
|
* @param navController NavController] used for navigation.
|
||||||
|
@ -88,21 +88,20 @@ class DefaultQuickSettingsController(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handlePermissionToggled(permission: WebsitePermission) {
|
override fun handlePermissionToggled(permission: WebsitePermission) {
|
||||||
val featureToggled = permission.getBackingFeature()
|
val featureToggled = permission.phoneFeature
|
||||||
|
|
||||||
when (permission.isBlockedByAndroid) {
|
when (permission.isBlockedByAndroid) {
|
||||||
true -> handleAndroidPermissionRequest(featureToggled.androidPermissionsList)
|
true -> handleAndroidPermissionRequest(featureToggled.androidPermissionsList)
|
||||||
false -> {
|
false -> {
|
||||||
val permissions = sitePermissions
|
val permissions = sitePermissions
|
||||||
if (permissions != null) {
|
if (permissions != null) {
|
||||||
val newPermissions = permissions.toggle(featureToggled).also {
|
val newPermissions = permissions.toggle(featureToggled)
|
||||||
handlePermissionsChange(it)
|
handlePermissionsChange(newPermissions)
|
||||||
}
|
|
||||||
sitePermissions = newPermissions
|
sitePermissions = newPermissions
|
||||||
|
|
||||||
quickSettingsStore.dispatch(
|
quickSettingsStore.dispatch(
|
||||||
WebsitePermissionAction.TogglePermission(
|
WebsitePermissionAction.TogglePermission(
|
||||||
permission,
|
featureToggled,
|
||||||
featureToggled.getActionLabel(context, newPermissions, settings),
|
featureToggled.getActionLabel(context, newPermissions, settings),
|
||||||
featureToggled.shouldBeEnabled(context, newPermissions, settings)
|
featureToggled.shouldBeEnabled(context, newPermissions, settings)
|
||||||
)
|
)
|
||||||
|
@ -117,7 +116,7 @@ class DefaultQuickSettingsController(
|
||||||
override fun handleAndroidPermissionGranted(feature: PhoneFeature) {
|
override fun handleAndroidPermissionGranted(feature: PhoneFeature) {
|
||||||
quickSettingsStore.dispatch(
|
quickSettingsStore.dispatch(
|
||||||
WebsitePermissionAction.TogglePermission(
|
WebsitePermissionAction.TogglePermission(
|
||||||
feature.getCorrespondingPermission(),
|
feature,
|
||||||
feature.getActionLabel(context, sitePermissions, settings),
|
feature.getActionLabel(context, sitePermissions, settings),
|
||||||
feature.shouldBeEnabled(context, sitePermissions, settings)
|
feature.shouldBeEnabled(context, sitePermissions, settings)
|
||||||
)
|
)
|
||||||
|
@ -150,56 +149,6 @@ class DefaultQuickSettingsController(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Each [WebsitePermission] is mapped after a [PhoneFeature].
|
|
||||||
*
|
|
||||||
* Get this [WebsitePermission]'s [PhoneFeature].
|
|
||||||
*/
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
||||||
fun WebsitePermission.getBackingFeature(): PhoneFeature = when (this) {
|
|
||||||
is WebsitePermission.Camera -> PhoneFeature.CAMERA
|
|
||||||
is WebsitePermission.Microphone -> PhoneFeature.MICROPHONE
|
|
||||||
is WebsitePermission.Notification -> PhoneFeature.NOTIFICATION
|
|
||||||
is WebsitePermission.Location -> PhoneFeature.LOCATION
|
|
||||||
is WebsitePermission.AutoplayAudible -> PhoneFeature.AUTOPLAY_AUDIBLE
|
|
||||||
is WebsitePermission.AutoplayInaudible -> PhoneFeature.AUTOPLAY_INAUDIBLE
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the specific [WebsitePermission] implementation which this [PhoneFeature] is tied to.
|
|
||||||
*
|
|
||||||
* **The result only informs about the type of [WebsitePermission].
|
|
||||||
* The resulting object's properties are just stubs and not dependable.**
|
|
||||||
*/
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
||||||
fun PhoneFeature.getCorrespondingPermission(): WebsitePermission {
|
|
||||||
val defaultStatus = ""
|
|
||||||
val defaultEnabled = false
|
|
||||||
val defaultVisible = false
|
|
||||||
val defaultBlockedByAndroid = false
|
|
||||||
|
|
||||||
return when (this) {
|
|
||||||
PhoneFeature.CAMERA -> WebsitePermission.Camera(
|
|
||||||
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
|
|
||||||
)
|
|
||||||
PhoneFeature.LOCATION -> WebsitePermission.Location(
|
|
||||||
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
|
|
||||||
)
|
|
||||||
PhoneFeature.MICROPHONE -> WebsitePermission.Microphone(
|
|
||||||
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
|
|
||||||
)
|
|
||||||
PhoneFeature.NOTIFICATION -> WebsitePermission.Notification(
|
|
||||||
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
|
|
||||||
)
|
|
||||||
PhoneFeature.AUTOPLAY_AUDIBLE -> WebsitePermission.AutoplayAudible(
|
|
||||||
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
|
|
||||||
)
|
|
||||||
PhoneFeature.AUTOPLAY_INAUDIBLE -> WebsitePermission.AutoplayInaudible(
|
|
||||||
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigate to toggle [SitePermissions] for the specified [PhoneFeature]
|
* Navigate to toggle [SitePermissions] for the specified [PhoneFeature]
|
||||||
*
|
*
|
||||||
|
@ -207,7 +156,7 @@ class DefaultQuickSettingsController(
|
||||||
*/
|
*/
|
||||||
private fun navigateToManagePhoneFeature(phoneFeature: PhoneFeature) {
|
private fun navigateToManagePhoneFeature(phoneFeature: PhoneFeature) {
|
||||||
val directions = QuickSettingsSheetDialogFragmentDirections
|
val directions = QuickSettingsSheetDialogFragmentDirections
|
||||||
.actionGlobalSitePermissionsManagePhoneFeature(phoneFeature.id)
|
.actionGlobalSitePermissionsManagePhoneFeature(phoneFeature)
|
||||||
navController.navigate(directions)
|
navController.navigate(directions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.settings.quicksettings
|
||||||
|
|
||||||
|
import mozilla.components.lib.state.Action
|
||||||
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent [Action] for all the [QuickSettingsFragmentState] changes.
|
||||||
|
*/
|
||||||
|
sealed class QuickSettingsFragmentAction : Action
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All possible [WebsiteInfoState] changes as result of user / system interactions.
|
||||||
|
*/
|
||||||
|
sealed class WebsiteInfoAction : QuickSettingsFragmentAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All possible [WebsitePermissionsState] changes as result of user / system interactions.
|
||||||
|
*/
|
||||||
|
sealed class WebsitePermissionAction : QuickSettingsFragmentAction() {
|
||||||
|
/**
|
||||||
|
* Change resulting from toggling a specific [WebsitePermission] for the current website.
|
||||||
|
*
|
||||||
|
* @param updatedFeature [PhoneFeature] backing a certain [WebsitePermission].
|
||||||
|
* Allows to easily identify which permission changed
|
||||||
|
* **Must be the name of one of the properties of [WebsitePermissionsState]**.
|
||||||
|
* @param updatedStatus [String] the new [WebsitePermission#status] which will be shown to the user.
|
||||||
|
* @param updatedEnabledStatus [Boolean] the new [WebsitePermission#enabled] which will be shown to the user.
|
||||||
|
*/
|
||||||
|
class TogglePermission(
|
||||||
|
val updatedFeature: PhoneFeature,
|
||||||
|
val updatedStatus: String,
|
||||||
|
val updatedEnabledStatus: Boolean
|
||||||
|
) : WebsitePermissionAction()
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.settings.quicksettings
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent Reducer for all [QuickSettingsFragmentState]s of all Views shown in this Fragment.
|
||||||
|
*/
|
||||||
|
fun quickSettingsFragmentReducer(
|
||||||
|
state: QuickSettingsFragmentState,
|
||||||
|
action: QuickSettingsFragmentAction
|
||||||
|
): QuickSettingsFragmentState {
|
||||||
|
return when (action) {
|
||||||
|
is WebsiteInfoAction -> {
|
||||||
|
// There is no possible action that can change this View's state while it is displayed to the user.
|
||||||
|
// Every time the View is recreated it starts with a fresh state. This is the only way to display
|
||||||
|
// something different.
|
||||||
|
state
|
||||||
|
}
|
||||||
|
is WebsitePermissionAction -> state.copy(
|
||||||
|
websitePermissionsState = WebsitePermissionsStateReducer.reduce(
|
||||||
|
state.websitePermissionsState,
|
||||||
|
action
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object WebsitePermissionsStateReducer {
|
||||||
|
/**
|
||||||
|
* Handles creating a new [WebsitePermissionsState] based on the specific [WebsitePermissionAction]
|
||||||
|
*/
|
||||||
|
fun reduce(
|
||||||
|
state: WebsitePermissionsState,
|
||||||
|
action: WebsitePermissionAction
|
||||||
|
): WebsitePermissionsState {
|
||||||
|
return when (action) {
|
||||||
|
is WebsitePermissionAction.TogglePermission -> {
|
||||||
|
val key = action.updatedFeature
|
||||||
|
val newWebsitePermission = state.getValue(key).copy(
|
||||||
|
status = action.updatedStatus,
|
||||||
|
isEnabled = action.updatedEnabledStatus
|
||||||
|
)
|
||||||
|
|
||||||
|
state + Pair(key, newWebsitePermission)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.settings.quicksettings
|
||||||
|
|
||||||
|
import androidx.annotation.ColorRes
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import mozilla.components.lib.state.State
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [State] containing all data displayed to the user by this Fragment.
|
||||||
|
*
|
||||||
|
* Partitioned further to contain mutiple states for each standalone View this Fragment holds.
|
||||||
|
*/
|
||||||
|
data class QuickSettingsFragmentState(
|
||||||
|
val webInfoState: WebsiteInfoState,
|
||||||
|
val websitePermissionsState: WebsitePermissionsState
|
||||||
|
) : State
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [State] to be rendered by [WebsiteInfoView] indicating whether the connection is secure or not.
|
||||||
|
*
|
||||||
|
* @param websiteUrl [String] the URL of the current web page.
|
||||||
|
* @param websiteTitle [String] the title of the current web page.
|
||||||
|
* @param websiteSecurityUiValues UI values to represent the security of the website.
|
||||||
|
*/
|
||||||
|
data class WebsiteInfoState(
|
||||||
|
val websiteUrl: String,
|
||||||
|
val websiteTitle: String,
|
||||||
|
val websiteSecurityUiValues: WebsiteSecurityUiValues,
|
||||||
|
val certificateName: String
|
||||||
|
) : State
|
||||||
|
|
||||||
|
enum class WebsiteSecurityUiValues(
|
||||||
|
@StringRes val securityInfoRes: Int,
|
||||||
|
@DrawableRes val iconRes: Int,
|
||||||
|
@ColorRes val iconTintRes: Int
|
||||||
|
) {
|
||||||
|
SECURE(
|
||||||
|
R.string.quick_settings_sheet_secure_connection,
|
||||||
|
R.drawable.mozac_ic_lock,
|
||||||
|
R.color.photonGreen50
|
||||||
|
),
|
||||||
|
INSECURE(
|
||||||
|
R.string.quick_settings_sheet_insecure_connection,
|
||||||
|
R.drawable.mozac_ic_globe,
|
||||||
|
R.color.photonRed50
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [State] to be rendered by [WebsitePermissionsView] displaying all explicitly allowed or blocked
|
||||||
|
* website permissions.
|
||||||
|
*/
|
||||||
|
typealias WebsitePermissionsState = Map<PhoneFeature, WebsitePermission>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper over a website permission encompassing all it's needed state to be rendered on the screen.
|
||||||
|
*
|
||||||
|
* Contains a limited number of implementations because there is a known, finite number of permissions
|
||||||
|
* we need to display to the user.
|
||||||
|
*
|
||||||
|
* @property status The *allowed* / *blocked* permission status to be shown to the user.
|
||||||
|
* @property isVisible Whether this permission should be shown to the user.
|
||||||
|
* @property isEnabled Visual indication about whether this permission is *enabled* / *disabled*
|
||||||
|
* @property isBlockedByAndroid Whether the corresponding *dangerous* Android permission is granted
|
||||||
|
* for the app by the user or not.
|
||||||
|
*/
|
||||||
|
data class WebsitePermission(
|
||||||
|
val phoneFeature: PhoneFeature,
|
||||||
|
val status: String,
|
||||||
|
val isVisible: Boolean,
|
||||||
|
val isEnabled: Boolean,
|
||||||
|
val isBlockedByAndroid: Boolean
|
||||||
|
)
|
|
@ -5,21 +5,18 @@
|
||||||
package org.mozilla.fenix.settings.quicksettings
|
package org.mozilla.fenix.settings.quicksettings
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.annotation.ColorRes
|
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||||
import mozilla.components.lib.state.Action
|
import mozilla.components.lib.state.Action
|
||||||
import mozilla.components.lib.state.Reducer
|
import mozilla.components.lib.state.Reducer
|
||||||
import mozilla.components.lib.state.State
|
import mozilla.components.lib.state.State
|
||||||
import mozilla.components.lib.state.Store
|
import mozilla.components.lib.state.Store
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.createStore
|
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.createStore
|
||||||
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
|
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
|
||||||
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeVisible
|
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeVisible
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
import java.util.EnumMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [QuickSettingsSheetDialogFragment]'s unique [Store].
|
* [QuickSettingsSheetDialogFragment]'s unique [Store].
|
||||||
|
@ -40,27 +37,6 @@ class QuickSettingsFragmentStore(
|
||||||
::quickSettingsFragmentReducer
|
::quickSettingsFragmentReducer
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
|
||||||
* String, Drawable & Drawable Tint color used to display that the current website connection is secured.
|
|
||||||
*/
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
||||||
val getSecuredWebsiteUiValues = Triple(
|
|
||||||
R.string.quick_settings_sheet_secure_connection,
|
|
||||||
R.drawable.mozac_ic_lock,
|
|
||||||
R.color.photonGreen50
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* String, Drawable & Drawable Tint color used to display that the current website connection is
|
|
||||||
* **not** secured.
|
|
||||||
*/
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
||||||
val getInsecureWebsiteUiValues = Triple(
|
|
||||||
R.string.quick_settings_sheet_insecure_connection,
|
|
||||||
R.drawable.mozac_ic_globe,
|
|
||||||
R.color.photonRed50
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an initial [QuickSettingsFragmentState] for all Views displayed by the
|
* Construct an initial [QuickSettingsFragmentState] for all Views displayed by the
|
||||||
* [QuickSettingsSheetDialogFragment].
|
* [QuickSettingsSheetDialogFragment].
|
||||||
|
@ -109,11 +85,8 @@ class QuickSettingsFragmentStore(
|
||||||
isSecured: Boolean,
|
isSecured: Boolean,
|
||||||
certificateName: String
|
certificateName: String
|
||||||
): WebsiteInfoState {
|
): WebsiteInfoState {
|
||||||
val (stringRes, iconRes, colorRes) = when (isSecured) {
|
val uiValues = if (isSecured) WebsiteSecurityUiValues.SECURE else WebsiteSecurityUiValues.INSECURE
|
||||||
true -> getSecuredWebsiteUiValues
|
return WebsiteInfoState(websiteUrl, websiteTitle, uiValues, certificateName)
|
||||||
false -> getInsecureWebsiteUiValues
|
|
||||||
}
|
|
||||||
return WebsiteInfoState(websiteUrl, websiteTitle, stringRes, iconRes, colorRes, certificateName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -132,26 +105,11 @@ class QuickSettingsFragmentStore(
|
||||||
permissions: SitePermissions?,
|
permissions: SitePermissions?,
|
||||||
settings: Settings
|
settings: Settings
|
||||||
): WebsitePermissionsState {
|
): WebsitePermissionsState {
|
||||||
val cameraPermission =
|
val state = EnumMap<PhoneFeature, WebsitePermission>(PhoneFeature::class.java)
|
||||||
PhoneFeature.CAMERA.toWebsitePermission(context, permissions, settings)
|
for (feature in PhoneFeature.values()) {
|
||||||
val microphonePermission =
|
state[feature] = feature.toWebsitePermission(context, permissions, settings)
|
||||||
PhoneFeature.MICROPHONE.toWebsitePermission(context, permissions, settings)
|
}
|
||||||
val notificationPermission =
|
return state
|
||||||
PhoneFeature.NOTIFICATION.toWebsitePermission(context, permissions, settings)
|
|
||||||
val locationPermission =
|
|
||||||
PhoneFeature.LOCATION.toWebsitePermission(context, permissions, settings)
|
|
||||||
val autoplayAudiblePermission =
|
|
||||||
PhoneFeature.AUTOPLAY_AUDIBLE.toWebsitePermission(context, permissions, settings)
|
|
||||||
val autoplayInaudiblePermission =
|
|
||||||
PhoneFeature.AUTOPLAY_INAUDIBLE.toWebsitePermission(context, permissions, settings)
|
|
||||||
val shouldBeVisible = cameraPermission.isVisible || microphonePermission.isVisible ||
|
|
||||||
notificationPermission.isVisible || locationPermission.isVisible
|
|
||||||
|
|
||||||
return WebsitePermissionsState(
|
|
||||||
shouldBeVisible, cameraPermission, microphonePermission,
|
|
||||||
notificationPermission, locationPermission, autoplayAudiblePermission,
|
|
||||||
autoplayInaudiblePermission
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,425 +121,13 @@ class QuickSettingsFragmentStore(
|
||||||
permissions: SitePermissions?,
|
permissions: SitePermissions?,
|
||||||
settings: Settings
|
settings: Settings
|
||||||
): WebsitePermission {
|
): WebsitePermission {
|
||||||
val status = getPermissionStatus(context, permissions, settings)
|
return WebsitePermission(
|
||||||
return when (this) {
|
phoneFeature = this,
|
||||||
PhoneFeature.CAMERA -> WebsitePermission.Camera(
|
status = getActionLabel(context, permissions, settings),
|
||||||
status.status, status.isVisible, status.isEnabled, status.isBlockedByAndroid
|
isVisible = shouldBeVisible(permissions, settings),
|
||||||
)
|
isEnabled = shouldBeEnabled(context, permissions, settings),
|
||||||
PhoneFeature.LOCATION -> WebsitePermission.Location(
|
isBlockedByAndroid = !isAndroidPermissionGranted(context)
|
||||||
status.status, status.isVisible, status.isEnabled, status.isBlockedByAndroid
|
|
||||||
)
|
|
||||||
PhoneFeature.MICROPHONE -> WebsitePermission.Microphone(
|
|
||||||
status.status, status.isVisible, status.isEnabled, status.isBlockedByAndroid
|
|
||||||
)
|
|
||||||
PhoneFeature.NOTIFICATION -> WebsitePermission.Notification(
|
|
||||||
status.status, status.isVisible, status.isEnabled, status.isBlockedByAndroid
|
|
||||||
)
|
|
||||||
PhoneFeature.AUTOPLAY_AUDIBLE -> WebsitePermission.AutoplayAudible(
|
|
||||||
status.status, status.isVisible, status.isEnabled, status.isBlockedByAndroid
|
|
||||||
)
|
|
||||||
PhoneFeature.AUTOPLAY_INAUDIBLE -> WebsitePermission.AutoplayInaudible(
|
|
||||||
status.status, status.isVisible, status.isEnabled, status.isBlockedByAndroid
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method for getting the [WebsitePermission] properties based on a specific [PhoneFeature].
|
|
||||||
*/
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
||||||
fun PhoneFeature.getPermissionStatus(
|
|
||||||
context: Context,
|
|
||||||
permissions: SitePermissions?,
|
|
||||||
settings: Settings
|
|
||||||
) = PermissionStatus(
|
|
||||||
status = getActionLabel(context, permissions, settings),
|
|
||||||
isVisible = shouldBeVisible(permissions, settings),
|
|
||||||
isEnabled = shouldBeEnabled(context, permissions, settings),
|
|
||||||
isBlockedByAndroid = !isAndroidPermissionGranted(context)
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class acting as a temporary container of [WebsitePermission] properties.
|
|
||||||
*/
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
||||||
data class PermissionStatus(
|
|
||||||
val status: String,
|
|
||||||
val isVisible: Boolean,
|
|
||||||
val isEnabled: Boolean,
|
|
||||||
val isBlockedByAndroid: Boolean
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
// States
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [State] containing all data displayed to the user by this Fragment.
|
|
||||||
*
|
|
||||||
* Partitioned further to contain mutiple states for each standalone View this Fragment holds.
|
|
||||||
*/
|
|
||||||
data class QuickSettingsFragmentState(
|
|
||||||
val webInfoState: WebsiteInfoState,
|
|
||||||
val websitePermissionsState: WebsitePermissionsState
|
|
||||||
) : State
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [State] to be rendered by [WebsiteInfoView] indicating whether the connection is secure or not.
|
|
||||||
*
|
|
||||||
* @param websiteUrl [String] the URL of the current web page.
|
|
||||||
* @param websiteTitle [String] the title of the current web page.
|
|
||||||
* @param securityInfoRes [StringRes] for the connection description.
|
|
||||||
* @param iconRes [DrawableRes] image indicating the connection status.
|
|
||||||
* @param iconTintRes [ColorRes] icon color.
|
|
||||||
*/
|
|
||||||
data class WebsiteInfoState(
|
|
||||||
val websiteUrl: String,
|
|
||||||
val websiteTitle: String,
|
|
||||||
@StringRes val securityInfoRes: Int,
|
|
||||||
@DrawableRes val iconRes: Int,
|
|
||||||
@ColorRes val iconTintRes: Int,
|
|
||||||
val certificateName: String
|
|
||||||
) : State
|
|
||||||
|
|
||||||
/**
|
|
||||||
* /**
|
|
||||||
* [State] to be rendered by [WebsitePermissionsView] displaying all explicitly allowed or blocked
|
|
||||||
* website permissions.
|
|
||||||
*
|
|
||||||
* @param isVisible [Boolean] whether this contains data that needs to be displayed to the user.
|
|
||||||
* @param camera [WebsitePermission] containing all information about the *camera* permission.
|
|
||||||
* @param microphone [WebsitePermission] containing all information about the *microphone* permission.
|
|
||||||
* @param notification [notification] containing all information about the *notification* permission.
|
|
||||||
* @param location [WebsitePermission] containing all information about the *location* permission.
|
|
||||||
*/
|
|
||||||
*/
|
|
||||||
data class WebsitePermissionsState(
|
|
||||||
val isVisible: Boolean,
|
|
||||||
val camera: WebsitePermission,
|
|
||||||
val microphone: WebsitePermission,
|
|
||||||
val notification: WebsitePermission,
|
|
||||||
val location: WebsitePermission,
|
|
||||||
val autoplayAudible: WebsitePermission,
|
|
||||||
val autoplayInaudible: WebsitePermission
|
|
||||||
) : State
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper over a website permission encompassing all it's needed state to be rendered on the screen.
|
|
||||||
*
|
|
||||||
* Contains a limited number of implementations because there is a known, finite number of permissions
|
|
||||||
* we need to display to the user.
|
|
||||||
*/
|
|
||||||
sealed class WebsitePermission {
|
|
||||||
/**
|
|
||||||
* The *allowed* / *blocked* permission status to be shown to the user.
|
|
||||||
*/
|
|
||||||
abstract val status: String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this permission should be shown to the user.
|
|
||||||
*/
|
|
||||||
abstract val isVisible: Boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visual indication about whether this permission is *enabled* / *disabled*
|
|
||||||
*/
|
|
||||||
abstract val isEnabled: Boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the corresponding *dangerous* Android permission is granted for the app by the user or not.
|
|
||||||
*/
|
|
||||||
abstract val isBlockedByAndroid: Boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method mimicking the default generated *copy()* method for a data class.
|
|
||||||
* Allows us using a familiar API in the reducer.
|
|
||||||
*/
|
|
||||||
abstract fun copy(
|
|
||||||
status: String = this.status,
|
|
||||||
isVisible: Boolean = this.isVisible,
|
|
||||||
isEnabled: Boolean = this.isEnabled,
|
|
||||||
isBlockedByAndroid: Boolean = this.isBlockedByAndroid
|
|
||||||
): WebsitePermission
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains all information about the *camera* permission.
|
|
||||||
*/
|
|
||||||
data class Camera(
|
|
||||||
override val status: String,
|
|
||||||
override val isVisible: Boolean,
|
|
||||||
override val isEnabled: Boolean,
|
|
||||||
override val isBlockedByAndroid: Boolean,
|
|
||||||
val name: String = "Camera" // helps to resolve the overload resolution ambiguity for the copy() method
|
|
||||||
) : WebsitePermission() {
|
|
||||||
override fun copy(
|
|
||||||
status: String,
|
|
||||||
isVisible: Boolean,
|
|
||||||
isEnabled: Boolean,
|
|
||||||
isBlockedByAndroid: Boolean
|
|
||||||
) = copy(
|
|
||||||
status = status,
|
|
||||||
isVisible = isVisible,
|
|
||||||
isEnabled = isEnabled,
|
|
||||||
isBlockedByAndroid = isBlockedByAndroid,
|
|
||||||
name = name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains all information about the *microphone* permission.
|
|
||||||
*/
|
|
||||||
data class Microphone(
|
|
||||||
override val status: String,
|
|
||||||
override val isVisible: Boolean,
|
|
||||||
override val isEnabled: Boolean,
|
|
||||||
override val isBlockedByAndroid: Boolean,
|
|
||||||
val name: String = "Microphone" // helps to resolve the overload resolution ambiguity for the copy() method
|
|
||||||
) : WebsitePermission() {
|
|
||||||
override fun copy(
|
|
||||||
status: String,
|
|
||||||
isVisible: Boolean,
|
|
||||||
isEnabled: Boolean,
|
|
||||||
isBlockedByAndroid: Boolean
|
|
||||||
) = copy(
|
|
||||||
status = status,
|
|
||||||
isVisible = isVisible,
|
|
||||||
isEnabled = isEnabled,
|
|
||||||
isBlockedByAndroid = isBlockedByAndroid,
|
|
||||||
name = name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains all information about the *notification* permission.
|
|
||||||
*/
|
|
||||||
data class Notification(
|
|
||||||
override val status: String,
|
|
||||||
override val isVisible: Boolean,
|
|
||||||
override val isEnabled: Boolean,
|
|
||||||
override val isBlockedByAndroid: Boolean,
|
|
||||||
val name: String = "Notification" // helps to resolve the overload resolution ambiguity for the copy() method
|
|
||||||
) : WebsitePermission() {
|
|
||||||
override fun copy(
|
|
||||||
status: String,
|
|
||||||
isVisible: Boolean,
|
|
||||||
isEnabled: Boolean,
|
|
||||||
isBlockedByAndroid: Boolean
|
|
||||||
) = copy(
|
|
||||||
status = status,
|
|
||||||
isVisible = isVisible,
|
|
||||||
isEnabled = isEnabled,
|
|
||||||
isBlockedByAndroid = isBlockedByAndroid,
|
|
||||||
name = name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains all information about the *location* permission.
|
|
||||||
*/
|
|
||||||
data class Location(
|
|
||||||
override val status: String,
|
|
||||||
override val isVisible: Boolean,
|
|
||||||
override val isEnabled: Boolean,
|
|
||||||
override val isBlockedByAndroid: Boolean,
|
|
||||||
val name: String = "Location" // helps to resolve the overload resolution ambiguity for the copy() method
|
|
||||||
) : WebsitePermission() {
|
|
||||||
override fun copy(
|
|
||||||
status: String,
|
|
||||||
isVisible: Boolean,
|
|
||||||
isEnabled: Boolean,
|
|
||||||
isBlockedByAndroid: Boolean
|
|
||||||
) = copy(
|
|
||||||
status = status,
|
|
||||||
isVisible = isVisible,
|
|
||||||
isEnabled = isEnabled,
|
|
||||||
isBlockedByAndroid = isBlockedByAndroid,
|
|
||||||
name = name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains all information about the *autoplay audible* permission.
|
|
||||||
*/
|
|
||||||
data class AutoplayAudible(
|
|
||||||
override val status: String,
|
|
||||||
override val isVisible: Boolean,
|
|
||||||
override val isEnabled: Boolean,
|
|
||||||
override val isBlockedByAndroid: Boolean,
|
|
||||||
val name: String = "AutoplayAudible" // helps to resolve the overload resolution ambiguity for the copy() method
|
|
||||||
) : WebsitePermission() {
|
|
||||||
override fun copy(
|
|
||||||
status: String,
|
|
||||||
isVisible: Boolean,
|
|
||||||
isEnabled: Boolean,
|
|
||||||
isBlockedByAndroid: Boolean
|
|
||||||
) = copy(
|
|
||||||
status = status,
|
|
||||||
isVisible = isVisible,
|
|
||||||
isEnabled = isEnabled,
|
|
||||||
isBlockedByAndroid = isBlockedByAndroid,
|
|
||||||
name = name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains all information about the *autoplay inaudible* permission.
|
|
||||||
*/
|
|
||||||
data class AutoplayInaudible(
|
|
||||||
override val status: String,
|
|
||||||
override val isVisible: Boolean,
|
|
||||||
override val isEnabled: Boolean,
|
|
||||||
override val isBlockedByAndroid: Boolean,
|
|
||||||
// helps to resolve the overload resolution ambiguity for the copy() method
|
|
||||||
val name: String = "AutoplayInaudible"
|
|
||||||
) : WebsitePermission() {
|
|
||||||
override fun copy(
|
|
||||||
status: String,
|
|
||||||
isVisible: Boolean,
|
|
||||||
isEnabled: Boolean,
|
|
||||||
isBlockedByAndroid: Boolean
|
|
||||||
) = copy(
|
|
||||||
status = status,
|
|
||||||
isVisible = isVisible,
|
|
||||||
isEnabled = isEnabled,
|
|
||||||
isBlockedByAndroid = isBlockedByAndroid,
|
|
||||||
name = name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
// Actions
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parent [Action] for all the [QuickSettingsFragmentState] changes.
|
|
||||||
*/
|
|
||||||
sealed class QuickSettingsFragmentAction : Action
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All possible [WebsiteInfoState] changes as result of user / system interactions.
|
|
||||||
*/
|
|
||||||
sealed class WebsiteInfoAction : QuickSettingsFragmentAction()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All possible [WebsitePermissionsState] changes as result of user / system interactions.
|
|
||||||
*/
|
|
||||||
sealed class WebsitePermissionAction : QuickSettingsFragmentAction() {
|
|
||||||
/**
|
|
||||||
* Change resulting from toggling a specific [WebsitePermission] for the current website.
|
|
||||||
*
|
|
||||||
* @param updatedFeature [PhoneFeature] backing a certain [WebsitePermission].
|
|
||||||
* Allows to easily identify which permission changed
|
|
||||||
* **Must be the name of one of the properties of [WebsitePermissionsState]**.
|
|
||||||
* @param updatedStatus [String] the new [WebsitePermission#status] which will be shown to the user.
|
|
||||||
* @param updatedEnabledStatus [Boolean] the new [WebsitePermission#enabled] which will be shown to the user.
|
|
||||||
*/
|
|
||||||
class TogglePermission(
|
|
||||||
val websitePermission: WebsitePermission,
|
|
||||||
val updatedStatus: String,
|
|
||||||
val updatedEnabledStatus: Boolean
|
|
||||||
) : WebsitePermissionAction()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
// Reducers
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parent [Reducer] for all [QuickSettingsFragmentState]s of all Views shown in this Fragment.
|
|
||||||
*/
|
|
||||||
fun quickSettingsFragmentReducer(
|
|
||||||
state: QuickSettingsFragmentState,
|
|
||||||
action: QuickSettingsFragmentAction
|
|
||||||
): QuickSettingsFragmentState {
|
|
||||||
return when (action) {
|
|
||||||
is WebsiteInfoAction -> state.copy(
|
|
||||||
webInfoState = WebsiteInfoStateReducer.reduce(
|
|
||||||
state.webInfoState,
|
|
||||||
action
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
is WebsitePermissionAction -> state.copy(
|
|
||||||
websitePermissionsState = WebsitePermissionsStateReducer.reduce(
|
|
||||||
state.websitePermissionsState,
|
|
||||||
action
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER") // the action paramater is unused
|
|
||||||
object WebsiteInfoStateReducer {
|
|
||||||
/**
|
|
||||||
* Handles creating a new [WebsiteInfoState] based on the specific [WebsiteInfoAction]
|
|
||||||
*/
|
|
||||||
fun reduce(
|
|
||||||
state: WebsiteInfoState,
|
|
||||||
action: WebsiteInfoAction
|
|
||||||
): WebsiteInfoState {
|
|
||||||
// There is no possible action that can change this View's state while it is displayed to the user.
|
|
||||||
// Everytime the View is recreated it starts with a fresh state. This is the only way to display
|
|
||||||
// something different.
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object WebsitePermissionsStateReducer {
|
|
||||||
/**
|
|
||||||
* Handles creating a new [WebsitePermissionsState] based on the specific [WebsitePermissionAction]
|
|
||||||
*/
|
|
||||||
fun reduce(
|
|
||||||
state: WebsitePermissionsState,
|
|
||||||
action: WebsitePermissionAction
|
|
||||||
): WebsitePermissionsState {
|
|
||||||
return when (action) {
|
|
||||||
is WebsitePermissionAction.TogglePermission -> {
|
|
||||||
when (action.websitePermission) {
|
|
||||||
is WebsitePermission.Camera -> state.copy(
|
|
||||||
camera = state.camera.copy(
|
|
||||||
status = action.updatedStatus,
|
|
||||||
isEnabled = action.updatedEnabledStatus
|
|
||||||
)
|
|
||||||
)
|
|
||||||
is WebsitePermission.Microphone -> state.copy(
|
|
||||||
microphone = state.microphone.copy(
|
|
||||||
status = action.updatedStatus,
|
|
||||||
isEnabled = action.updatedEnabledStatus
|
|
||||||
)
|
|
||||||
)
|
|
||||||
is WebsitePermission.Notification -> state.copy(
|
|
||||||
notification = state.notification.copy(
|
|
||||||
status = action.updatedStatus,
|
|
||||||
isEnabled = action.updatedEnabledStatus
|
|
||||||
)
|
|
||||||
)
|
|
||||||
is WebsitePermission.Location -> state.copy(
|
|
||||||
location = state.location.copy(
|
|
||||||
status = action.updatedStatus,
|
|
||||||
isEnabled = action.updatedEnabledStatus
|
|
||||||
)
|
|
||||||
)
|
|
||||||
is WebsitePermission.AutoplayAudible -> {
|
|
||||||
return state.copy(
|
|
||||||
autoplayAudible = state.autoplayAudible.copy(
|
|
||||||
status = action.updatedStatus,
|
|
||||||
isEnabled = action.updatedEnabledStatus
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is WebsitePermission.AutoplayInaudible -> {
|
|
||||||
return state.copy(
|
|
||||||
autoplayInaudible = state.autoplayInaudible.copy(
|
|
||||||
status = action.updatedStatus,
|
|
||||||
isEnabled = action.updatedEnabledStatus
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,11 @@ package org.mozilla.fenix.settings.quicksettings
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.ColorRes
|
import androidx.core.content.ContextCompat.getColor
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
import kotlinx.android.synthetic.main.quicksettings_website_info.view.*
|
import kotlinx.android.synthetic.main.quicksettings_website_info.view.*
|
||||||
|
import mozilla.components.support.ktx.android.content.getDrawableWithTint
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,7 +35,7 @@ class WebsiteInfoView(
|
||||||
fun update(state: WebsiteInfoState) {
|
fun update(state: WebsiteInfoState) {
|
||||||
bindUrl(state.websiteUrl)
|
bindUrl(state.websiteUrl)
|
||||||
bindTitle(state.websiteTitle)
|
bindTitle(state.websiteTitle)
|
||||||
bindSecurityInfo(state.securityInfoRes, state.iconRes, state.iconTintRes)
|
bindSecurityInfo(state.websiteSecurityUiValues)
|
||||||
bindCertificateName(state.certificateName)
|
bindCertificateName(state.certificateName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,14 +53,11 @@ class WebsiteInfoView(
|
||||||
view.certificateInfo.isVisible = cert.isNotEmpty()
|
view.certificateInfo.isVisible = cert.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindSecurityInfo(
|
private fun bindSecurityInfo(uiValues: WebsiteSecurityUiValues) {
|
||||||
@StringRes securityInfoRes: Int,
|
val tint = getColor(view.context, uiValues.iconTintRes)
|
||||||
@DrawableRes iconRes: Int,
|
view.securityInfo.setText(uiValues.securityInfoRes)
|
||||||
@ColorRes iconTintRes: Int
|
view.securityInfoIcon.setImageDrawable(
|
||||||
) {
|
view.context.getDrawableWithTint(uiValues.iconRes, tint)
|
||||||
val icon = AppCompatResources.getDrawable(view.context, iconRes)
|
)
|
||||||
icon?.setTint(ContextCompat.getColor(view.context, iconTintRes))
|
|
||||||
view.securityInfo.setText(securityInfoRes)
|
|
||||||
view.securityInfoIcon.setImageResource(iconRes)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,10 @@ import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.quicksettings_permissions.view.*
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
|
import java.util.EnumMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract declaring all possible user interactions with [WebsitePermissionsView]
|
* Contract declaring all possible user interactions with [WebsitePermissionsView]
|
||||||
|
@ -49,26 +52,31 @@ class WebsitePermissionsView(
|
||||||
val view: View = LayoutInflater.from(context)
|
val view: View = LayoutInflater.from(context)
|
||||||
.inflate(R.layout.quicksettings_permissions, containerView, true)
|
.inflate(R.layout.quicksettings_permissions, containerView, true)
|
||||||
|
|
||||||
|
private val permissionViews: Map<PhoneFeature, PermissionViewHolder> = EnumMap(mapOf(
|
||||||
|
PhoneFeature.CAMERA to PermissionViewHolder(view.cameraLabel, view.cameraStatus),
|
||||||
|
PhoneFeature.LOCATION to PermissionViewHolder(view.locationLabel, view.locationStatus),
|
||||||
|
PhoneFeature.MICROPHONE to PermissionViewHolder(view.microphoneLabel, view.microphoneStatus),
|
||||||
|
PhoneFeature.NOTIFICATION to PermissionViewHolder(view.notificationLabel, view.notificationStatus)
|
||||||
|
))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows changing what this View displays.
|
* Allows changing what this View displays.
|
||||||
*
|
*
|
||||||
* @param state [WebsitePermissionsState] to be rendered.
|
* @param state [WebsitePermissionsState] to be rendered.
|
||||||
*/
|
*/
|
||||||
fun update(state: WebsitePermissionsState) {
|
fun update(state: WebsitePermissionsState) {
|
||||||
if (state.isVisible) {
|
val isVisible = permissionViews.keys
|
||||||
|
.map { feature -> state.getValue(feature) }
|
||||||
|
.any { it.isVisible }
|
||||||
|
if (isVisible) {
|
||||||
interactor.onPermissionsShown()
|
interactor.onPermissionsShown()
|
||||||
}
|
}
|
||||||
|
|
||||||
// If more permissions are added into this View we can display them into a list
|
// If more permissions are added into this View we can display them into a list
|
||||||
// and also use DiffUtil to only update one item in case of a permission change
|
// and also use DiffUtil to only update one item in case of a permission change
|
||||||
bindPermission(state.camera,
|
for ((feature, views) in permissionViews) {
|
||||||
Pair(view.findViewById(R.id.cameraLabel), view.findViewById(R.id.cameraStatus)))
|
bindPermission(state.getValue(feature), views)
|
||||||
bindPermission(state.location,
|
}
|
||||||
Pair(view.findViewById(R.id.locationLabel), view.findViewById(R.id.locationStatus)))
|
|
||||||
bindPermission(state.microphone,
|
|
||||||
Pair(view.findViewById(R.id.microphoneLabel), view.findViewById(R.id.microphoneStatus)))
|
|
||||||
bindPermission(state.notification,
|
|
||||||
Pair(view.findViewById(R.id.notificationLabel), view.findViewById(R.id.notificationStatus)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,15 +84,15 @@ class WebsitePermissionsView(
|
||||||
* which will display permission's [icon, label, status] and register user inputs.
|
* which will display permission's [icon, label, status] and register user inputs.
|
||||||
*
|
*
|
||||||
* @param permissionState [WebsitePermission] specific permission that can be shown to the user.
|
* @param permissionState [WebsitePermission] specific permission that can be shown to the user.
|
||||||
* @param permissionViews Views that will render [WebsitePermission]'s state.
|
* @param viewHolder Views that will render [WebsitePermission]'s state.
|
||||||
*/
|
*/
|
||||||
private fun bindPermission(permissionState: WebsitePermission, permissionViews: Pair<TextView, TextView>) {
|
private fun bindPermission(permissionState: WebsitePermission, viewHolder: PermissionViewHolder) {
|
||||||
val (label, status) = permissionViews
|
viewHolder.label.isEnabled = permissionState.isEnabled
|
||||||
|
viewHolder.label.isVisible = permissionState.isVisible
|
||||||
status.text = permissionState.status
|
viewHolder.status.text = permissionState.status
|
||||||
label.isEnabled = permissionState.isEnabled
|
viewHolder.status.isVisible = permissionState.isVisible
|
||||||
label.isVisible = permissionState.isVisible
|
viewHolder.status.setOnClickListener { interactor.onPermissionToggled(permissionState) }
|
||||||
status.isVisible = permissionState.isVisible
|
|
||||||
status.setOnClickListener { interactor.onPermissionToggled(permissionState) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class PermissionViewHolder(val label: TextView, val status: TextView)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,13 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.settings.sitepermissions
|
package org.mozilla.fenix.settings.sitepermissions
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
|
import androidx.core.text.HtmlCompat
|
||||||
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.components.Components
|
import org.mozilla.fenix.components.Components
|
||||||
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to reload a session if a session with the given [origin] it is found.
|
* Try to reload a session if a session with the given [origin] it is found.
|
||||||
|
@ -15,3 +20,23 @@ internal fun Components.tryReloadTabBy(origin: String) {
|
||||||
val session = core.sessionManager.all.find { it.url.toUri().host == origin }
|
val session = core.sessionManager.all.find { it.url.toUri().host == origin }
|
||||||
useCases.sessionUseCases.reload(session)
|
useCases.sessionUseCases.reload(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun initBlockedByAndroidView(phoneFeature: PhoneFeature, blockedByAndroidView: View) {
|
||||||
|
val context = blockedByAndroidView.context
|
||||||
|
if (!phoneFeature.isAndroidPermissionGranted(context)) {
|
||||||
|
blockedByAndroidView.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
val descriptionLabel = blockedByAndroidView.findViewById<TextView>(R.id.blocked_by_android_feature_label)
|
||||||
|
val descriptionText = context.getString(
|
||||||
|
R.string.phone_feature_blocked_step_feature,
|
||||||
|
phoneFeature.getLabel(context)
|
||||||
|
)
|
||||||
|
descriptionLabel.text = HtmlCompat.fromHtml(descriptionText, HtmlCompat.FROM_HTML_MODE_COMPACT)
|
||||||
|
|
||||||
|
val permissionsLabel = blockedByAndroidView.findViewById<TextView>(R.id.blocked_by_android_permissions_label)
|
||||||
|
val permissionsText = context.getString(R.string.phone_feature_blocked_step_permissions)
|
||||||
|
permissionsLabel.text = HtmlCompat.fromHtml(permissionsText, HtmlCompat.FROM_HTML_MODE_COMPACT)
|
||||||
|
} else {
|
||||||
|
blockedByAndroidView.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ class SitePermissionsDetailsExceptionsFragment : PreferenceFragmentCompat() {
|
||||||
private fun navigateToPhoneFeature(phoneFeature: PhoneFeature) {
|
private fun navigateToPhoneFeature(phoneFeature: PhoneFeature) {
|
||||||
val directions =
|
val directions =
|
||||||
SitePermissionsDetailsExceptionsFragmentDirections.actionSitePermissionsToExceptionsToManagePhoneFeature(
|
SitePermissionsDetailsExceptionsFragmentDirections.actionSitePermissionsToExceptionsToManagePhoneFeature(
|
||||||
phoneFeatureId = phoneFeature.id,
|
phoneFeature = phoneFeature,
|
||||||
sitePermissions = sitePermissions
|
sitePermissions = sitePermissions
|
||||||
)
|
)
|
||||||
requireView().findNavController().navigate(directions)
|
requireView().findNavController().navigate(directions)
|
||||||
|
|
|
@ -77,7 +77,7 @@ class SitePermissionsFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
private fun navigateToPhoneFeature(phoneFeature: PhoneFeature) {
|
private fun navigateToPhoneFeature(phoneFeature: PhoneFeature) {
|
||||||
val directions = SitePermissionsFragmentDirections
|
val directions = SitePermissionsFragmentDirections
|
||||||
.actionSitePermissionsToManagePhoneFeatures(phoneFeature.id)
|
.actionSitePermissionsToManagePhoneFeatures(phoneFeature)
|
||||||
Navigation.findNavController(requireView()).navigate(directions)
|
Navigation.findNavController(requireView()).navigate(directions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,29 +28,22 @@ import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.requireComponents
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.ext.showToolbar
|
import org.mozilla.fenix.ext.showToolbar
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
|
||||||
import org.mozilla.fenix.settings.initBlockedByAndroidView
|
|
||||||
import org.mozilla.fenix.settings.setStartCheckedIndicator
|
import org.mozilla.fenix.settings.setStartCheckedIndicator
|
||||||
|
import org.mozilla.fenix.settings.update
|
||||||
|
|
||||||
@SuppressWarnings("TooManyFunctions")
|
@SuppressWarnings("TooManyFunctions")
|
||||||
class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment() {
|
class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment() {
|
||||||
|
|
||||||
private lateinit var phoneFeature: PhoneFeature
|
|
||||||
private lateinit var sitePermissions: SitePermissions
|
|
||||||
private lateinit var radioAllow: RadioButton
|
private lateinit var radioAllow: RadioButton
|
||||||
private lateinit var radioBlock: RadioButton
|
private lateinit var radioBlock: RadioButton
|
||||||
private lateinit var blockedByAndroidView: View
|
private lateinit var blockedByAndroidView: View
|
||||||
|
private val args by navArgs<SitePermissionsManageExceptionsPhoneFeatureFragmentArgs>()
|
||||||
val settings by lazy { requireContext().settings() }
|
val settings by lazy { requireContext().settings() }
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val args by navArgs<SitePermissionsManageExceptionsPhoneFeatureFragmentArgs>()
|
showToolbar(args.phoneFeature.getLabel(requireContext()))
|
||||||
|
|
||||||
phoneFeature = args.phoneFeatureId.toPhoneFeature()
|
|
||||||
sitePermissions = args.sitePermissions
|
|
||||||
|
|
||||||
showToolbar(phoneFeature.getLabel(requireContext()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
|
@ -71,7 +64,7 @@ class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment() {
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
initBlockedByAndroidView(phoneFeature, blockedByAndroidView)
|
initBlockedByAndroidView(args.phoneFeature, blockedByAndroidView)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initAskToAllowRadio(rootView: View) {
|
private fun initAskToAllowRadio(rootView: View) {
|
||||||
|
@ -87,7 +80,7 @@ class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun RadioButton.restoreState(status: SitePermissions.Status) {
|
private fun RadioButton.restoreState(status: SitePermissions.Status) {
|
||||||
if (phoneFeature.getStatus(sitePermissions) == status) {
|
if (args.phoneFeature.getStatus(args.sitePermissions) == status) {
|
||||||
this.isChecked = true
|
this.isChecked = true
|
||||||
this.setStartCheckedIndicator()
|
this.setStartCheckedIndicator()
|
||||||
}
|
}
|
||||||
|
@ -109,7 +102,7 @@ class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment() {
|
||||||
setMessage(R.string.confirm_clear_permission_site)
|
setMessage(R.string.confirm_clear_permission_site)
|
||||||
setTitle(R.string.clear_permission)
|
setTitle(R.string.clear_permission)
|
||||||
setPositiveButton(android.R.string.yes) { dialog: DialogInterface, _ ->
|
setPositiveButton(android.R.string.yes) { dialog: DialogInterface, _ ->
|
||||||
val defaultStatus = phoneFeature.getStatus(settings = settings)
|
val defaultStatus = args.phoneFeature.getStatus(settings = settings)
|
||||||
updatedSitePermissions(defaultStatus)
|
updatedSitePermissions(defaultStatus)
|
||||||
resetRadioButtonsStatus(defaultStatus)
|
resetRadioButtonsStatus(defaultStatus)
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
|
@ -147,23 +140,8 @@ class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment() {
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Int.toPhoneFeature(): PhoneFeature {
|
|
||||||
return requireNotNull(PhoneFeature.values().find { feature ->
|
|
||||||
this == feature.id
|
|
||||||
}) {
|
|
||||||
"$this is a invalid PhoneFeature"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updatedSitePermissions(status: SitePermissions.Status) {
|
private fun updatedSitePermissions(status: SitePermissions.Status) {
|
||||||
val updatedSitePermissions = when (phoneFeature) {
|
val updatedSitePermissions = args.sitePermissions.update(args.phoneFeature, status)
|
||||||
PhoneFeature.CAMERA -> sitePermissions.copy(camera = status)
|
|
||||||
PhoneFeature.LOCATION -> sitePermissions.copy(location = status)
|
|
||||||
PhoneFeature.MICROPHONE -> sitePermissions.copy(microphone = status)
|
|
||||||
PhoneFeature.NOTIFICATION -> sitePermissions.copy(notification = status)
|
|
||||||
PhoneFeature.AUTOPLAY_AUDIBLE -> sitePermissions.copy(autoplayAudible = status)
|
|
||||||
PhoneFeature.AUTOPLAY_INAUDIBLE -> sitePermissions.copy(autoplayInaudible = status)
|
|
||||||
}
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch(IO) {
|
viewLifecycleOwner.lifecycleScope.launch(IO) {
|
||||||
requireComponents.core.permissionStorage.updateSitePermissions(updatedSitePermissions)
|
requireComponents.core.permissionStorage.updateSitePermissions(updatedSitePermissions)
|
||||||
launch(Main) {
|
launch(Main) {
|
||||||
|
|
|
@ -20,10 +20,8 @@ import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.RadioButton
|
import android.widget.RadioButton
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import kotlinx.android.synthetic.main.fragment_manage_site_permissions_feature_phone.view.ask_to_allow_radio
|
import androidx.navigation.fragment.navArgs
|
||||||
import kotlinx.android.synthetic.main.fragment_manage_site_permissions_feature_phone.view.block_radio
|
import kotlinx.android.synthetic.main.fragment_manage_site_permissions_feature_phone.view.*
|
||||||
import kotlinx.android.synthetic.main.fragment_manage_site_permissions_feature_phone.view.fourth_radio
|
|
||||||
import kotlinx.android.synthetic.main.fragment_manage_site_permissions_feature_phone.view.third_radio
|
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ALLOWED
|
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ALLOWED
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ASK_TO_ALLOW
|
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ASK_TO_ALLOW
|
||||||
|
@ -31,10 +29,8 @@ import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.BL
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.ext.showToolbar
|
import org.mozilla.fenix.ext.showToolbar
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
|
||||||
import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY_AUDIBLE
|
import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY_AUDIBLE
|
||||||
import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY_INAUDIBLE
|
import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY_INAUDIBLE
|
||||||
import org.mozilla.fenix.settings.initBlockedByAndroidView
|
|
||||||
import org.mozilla.fenix.settings.setStartCheckedIndicator
|
import org.mozilla.fenix.settings.setStartCheckedIndicator
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
|
@ -45,19 +41,11 @@ const val AUTOPLAY_ALLOW_ALL = 3
|
||||||
|
|
||||||
@SuppressWarnings("TooManyFunctions")
|
@SuppressWarnings("TooManyFunctions")
|
||||||
class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
||||||
private lateinit var phoneFeature: PhoneFeature
|
|
||||||
private lateinit var settings: Settings
|
private val args by navArgs<SitePermissionsManagePhoneFeatureFragmentArgs>()
|
||||||
|
private val settings by lazy { requireContext().settings() }
|
||||||
private lateinit var blockedByAndroidView: View
|
private lateinit var blockedByAndroidView: View
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
phoneFeature = SitePermissionsManagePhoneFeatureFragmentArgs
|
|
||||||
.fromBundle(requireArguments())
|
|
||||||
.permission.toPhoneFeature()
|
|
||||||
settings = requireContext().settings()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
|
@ -80,13 +68,13 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
showToolbar(phoneFeature.getLabel(requireContext()))
|
showToolbar(args.phoneFeature.getLabel(requireContext()))
|
||||||
initBlockedByAndroidView(phoneFeature, blockedByAndroidView)
|
initBlockedByAndroidView(args.phoneFeature, blockedByAndroidView)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initFirstRadio(rootView: View) {
|
private fun initFirstRadio(rootView: View) {
|
||||||
with(rootView.ask_to_allow_radio) {
|
with(rootView.ask_to_allow_radio) {
|
||||||
if (phoneFeature == AUTOPLAY_AUDIBLE) {
|
if (args.phoneFeature == AUTOPLAY_AUDIBLE) {
|
||||||
// Disabled because GV does not allow this setting. TODO Reenable after
|
// Disabled because GV does not allow this setting. TODO Reenable after
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1621825 is fixed
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1621825 is fixed
|
||||||
// text = getString(R.string.preference_option_autoplay_allowed2)
|
// text = getString(R.string.preference_option_autoplay_allowed2)
|
||||||
|
@ -111,7 +99,7 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
||||||
|
|
||||||
private fun initSecondRadio(rootView: View) {
|
private fun initSecondRadio(rootView: View) {
|
||||||
with(rootView.block_radio) {
|
with(rootView.block_radio) {
|
||||||
if (phoneFeature == AUTOPLAY_AUDIBLE) {
|
if (args.phoneFeature == AUTOPLAY_AUDIBLE) {
|
||||||
text = getCombinedLabel(
|
text = getCombinedLabel(
|
||||||
getString(R.string.preference_option_autoplay_allowed_wifi_only2),
|
getString(R.string.preference_option_autoplay_allowed_wifi_only2),
|
||||||
getString(R.string.preference_option_autoplay_allowed_wifi_subtext)
|
getString(R.string.preference_option_autoplay_allowed_wifi_subtext)
|
||||||
|
@ -135,7 +123,7 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
||||||
|
|
||||||
private fun initThirdRadio(rootView: View) {
|
private fun initThirdRadio(rootView: View) {
|
||||||
with(rootView.third_radio) {
|
with(rootView.third_radio) {
|
||||||
if (phoneFeature == AUTOPLAY_AUDIBLE) {
|
if (args.phoneFeature == AUTOPLAY_AUDIBLE) {
|
||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
text = getString(R.string.preference_option_autoplay_block_audio2)
|
text = getString(R.string.preference_option_autoplay_block_audio2)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
|
@ -150,7 +138,7 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
||||||
|
|
||||||
private fun initFourthRadio(rootView: View) {
|
private fun initFourthRadio(rootView: View) {
|
||||||
with(rootView.fourth_radio) {
|
with(rootView.fourth_radio) {
|
||||||
if (phoneFeature == AUTOPLAY_AUDIBLE) {
|
if (args.phoneFeature == AUTOPLAY_AUDIBLE) {
|
||||||
visibility = View.VISIBLE
|
visibility = View.VISIBLE
|
||||||
text = getCombinedLabel(
|
text = getCombinedLabel(
|
||||||
getString(R.string.preference_option_autoplay_blocked3),
|
getString(R.string.preference_option_autoplay_blocked3),
|
||||||
|
@ -167,7 +155,7 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun RadioButton.restoreState(buttonAction: SitePermissionsRules.Action) {
|
private fun RadioButton.restoreState(buttonAction: SitePermissionsRules.Action) {
|
||||||
if (phoneFeature.getAction(settings) == buttonAction) {
|
if (args.phoneFeature.getAction(settings) == buttonAction) {
|
||||||
this.isChecked = true
|
this.isChecked = true
|
||||||
this.setStartCheckedIndicator()
|
this.setStartCheckedIndicator()
|
||||||
}
|
}
|
||||||
|
@ -181,7 +169,7 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveActionInSettings(action: SitePermissionsRules.Action) {
|
private fun saveActionInSettings(action: SitePermissionsRules.Action) {
|
||||||
settings.setSitePermissionsPhoneFeatureAction(phoneFeature, action)
|
settings.setSitePermissionsPhoneFeatureAction(args.phoneFeature, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -211,14 +199,6 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
||||||
initSettingsButton(blockedByAndroidView)
|
initSettingsButton(blockedByAndroidView)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Int.toPhoneFeature(): PhoneFeature {
|
|
||||||
return requireNotNull(PhoneFeature.values().find { feature ->
|
|
||||||
this == feature.id
|
|
||||||
}) {
|
|
||||||
"$this is a invalid PhoneFeature"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initSettingsButton(rootView: View) {
|
private fun initSettingsButton(rootView: View) {
|
||||||
val button = rootView.findViewById<Button>(R.id.settings_button)
|
val button = rootView.findViewById<Button>(R.id.settings_button)
|
||||||
button.setOnClickListener {
|
button.setOnClickListener {
|
||||||
|
|
|
@ -92,8 +92,8 @@
|
||||||
android:name="org.mozilla.fenix.settings.sitepermissions.SitePermissionsManagePhoneFeatureFragment"
|
android:name="org.mozilla.fenix.settings.sitepermissions.SitePermissionsManagePhoneFeatureFragment"
|
||||||
tools:layout="@layout/fragment_manage_site_permissions_feature_phone">
|
tools:layout="@layout/fragment_manage_site_permissions_feature_phone">
|
||||||
<argument
|
<argument
|
||||||
android:name="permission"
|
android:name="phoneFeature"
|
||||||
app:argType="integer" />
|
app:argType="org.mozilla.fenix.settings.PhoneFeature" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
|
@ -125,8 +125,8 @@
|
||||||
android:name="org.mozilla.fenix.settings.sitepermissions.SitePermissionsManageExceptionsPhoneFeatureFragment"
|
android:name="org.mozilla.fenix.settings.sitepermissions.SitePermissionsManageExceptionsPhoneFeatureFragment"
|
||||||
tools:layout="@layout/fragment_manage_site_permissions_feature_phone">
|
tools:layout="@layout/fragment_manage_site_permissions_feature_phone">
|
||||||
<argument
|
<argument
|
||||||
android:name="phoneFeatureId"
|
android:name="phoneFeature"
|
||||||
app:argType="integer" />
|
app:argType="org.mozilla.fenix.settings.PhoneFeature" />
|
||||||
<argument
|
<argument
|
||||||
android:name="sitePermissions"
|
android:name="sitePermissions"
|
||||||
app:argType="mozilla.components.feature.sitepermissions.SitePermissions" />
|
app:argType="mozilla.components.feature.sitepermissions.SitePermissions" />
|
||||||
|
|
|
@ -6,36 +6,33 @@ package org.mozilla.fenix.settings.quicksettings
|
||||||
|
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavDirections
|
import androidx.navigation.NavDirections
|
||||||
|
import io.mockk.MockKMatcherScope
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.mockkStatic
|
import io.mockk.spyk
|
||||||
import io.mockk.slot
|
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import io.mockk.verifyOrder
|
import io.mockk.verifyOrder
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.coroutines.test.TestCoroutineScope
|
import kotlinx.coroutines.test.TestCoroutineScope
|
||||||
|
import kotlinx.coroutines.test.runBlockingTest
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
import mozilla.components.feature.session.SessionUseCases
|
import mozilla.components.feature.session.SessionUseCases
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissions.Status.NO_DECISION
|
import mozilla.components.feature.sitepermissions.SitePermissions.Status.NO_DECISION
|
||||||
import mozilla.components.feature.tabs.TabsUseCases
|
import mozilla.components.feature.tabs.TabsUseCases
|
||||||
import mozilla.components.support.test.robolectric.testContext
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
import org.junit.Assert.assertArrayEquals
|
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertSame
|
import org.junit.Assert.assertSame
|
||||||
import org.junit.Assert.assertTrue
|
|
||||||
import org.junit.Ignore
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mozilla.fenix.components.PermissionStorage
|
import org.mozilla.fenix.components.PermissionStorage
|
||||||
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
|
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
|
||||||
import org.mozilla.fenix.settings.toggle
|
import org.mozilla.fenix.settings.toggle
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
|
||||||
|
|
||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
@RunWith(FenixRobolectricTestRunner::class)
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
|
@ -53,7 +50,7 @@ class DefaultQuickSettingsControllerTest {
|
||||||
private val requestPermissions = mockk<(Array<String>) -> Unit>(relaxed = true)
|
private val requestPermissions = mockk<(Array<String>) -> Unit>(relaxed = true)
|
||||||
private val displayPermissions = mockk<() -> Unit>(relaxed = true)
|
private val displayPermissions = mockk<() -> Unit>(relaxed = true)
|
||||||
private val dismiss = mockk<() -> Unit>(relaxed = true)
|
private val dismiss = mockk<() -> Unit>(relaxed = true)
|
||||||
private val controller = DefaultQuickSettingsController(
|
private val controller = spyk(DefaultQuickSettingsController(
|
||||||
context = context,
|
context = context,
|
||||||
quickSettingsStore = store,
|
quickSettingsStore = store,
|
||||||
coroutineScope = coroutinesScope,
|
coroutineScope = coroutinesScope,
|
||||||
|
@ -67,7 +64,7 @@ class DefaultQuickSettingsControllerTest {
|
||||||
requestRuntimePermissions = requestPermissions,
|
requestRuntimePermissions = requestPermissions,
|
||||||
displayPermissions = displayPermissions,
|
displayPermissions = displayPermissions,
|
||||||
dismiss = dismiss
|
dismiss = dismiss
|
||||||
)
|
))
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `handlePermissionsShown should delegate to an injected parameter`() {
|
fun `handlePermissionsShown should delegate to an injected parameter`() {
|
||||||
|
@ -81,58 +78,42 @@ class DefaultQuickSettingsControllerTest {
|
||||||
@Test
|
@Test
|
||||||
fun `handlePermissionToggled blocked by Android should handleAndroidPermissionRequest`() {
|
fun `handlePermissionToggled blocked by Android should handleAndroidPermissionRequest`() {
|
||||||
val cameraFeature = PhoneFeature.CAMERA
|
val cameraFeature = PhoneFeature.CAMERA
|
||||||
val websitePermission = mockk<WebsitePermission.Camera>()
|
val websitePermission = mockk<WebsitePermission>()
|
||||||
val androidPermissions = slot<Array<String>>()
|
every { websitePermission.phoneFeature } returns cameraFeature
|
||||||
every { websitePermission.isBlockedByAndroid } returns true
|
every { websitePermission.isBlockedByAndroid } returns true
|
||||||
|
|
||||||
controller.handlePermissionToggled(websitePermission)
|
controller.handlePermissionToggled(websitePermission)
|
||||||
|
|
||||||
verify {
|
verify {
|
||||||
controller.handleAndroidPermissionRequest(capture(androidPermissions))
|
controller.handleAndroidPermissionRequest(eqArray(cameraFeature.androidPermissionsList))
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(androidPermissions.isCaptured)
|
|
||||||
assertArrayEquals(cameraFeature.androidPermissionsList, androidPermissions.captured)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("Disabling because of intermittent failures https://github.com/mozilla-mobile/fenix/issues/8621")
|
|
||||||
fun `handlePermissionToggled allowed by Android should toggle the permissions and modify View's state`() {
|
fun `handlePermissionToggled allowed by Android should toggle the permissions and modify View's state`() {
|
||||||
val permissionName = "CAMERA"
|
val websitePermission = mockk<WebsitePermission>()
|
||||||
val websitePermission = mockk<WebsitePermission.Camera>()
|
every { websitePermission.phoneFeature } returns PhoneFeature.CAMERA
|
||||||
val toggledFeature = slot<PhoneFeature>()
|
|
||||||
val action = slot<WebsitePermissionAction>()
|
|
||||||
every { websitePermission.isBlockedByAndroid } returns false
|
every { websitePermission.isBlockedByAndroid } returns false
|
||||||
every { websitePermission.name } returns permissionName
|
|
||||||
every { store.dispatch(any()) } returns mockk()
|
every { store.dispatch(any()) } returns mockk()
|
||||||
// For using the SitePermissions.toggle(..) extension method we need a static mock of SitePermissions.
|
|
||||||
mockkStatic("org.mozilla.fenix.settings.ExtensionsKt")
|
|
||||||
|
|
||||||
controller.handlePermissionToggled(websitePermission)
|
controller.handlePermissionToggled(websitePermission)
|
||||||
|
|
||||||
// We want to verify that the Status is toggled and this event is passed to Controller also.
|
// We want to verify that the Status is toggled and this event is passed to Controller also.
|
||||||
assertSame(NO_DECISION, sitePermissions.camera)
|
assertSame(NO_DECISION, sitePermissions.camera)
|
||||||
verifyOrder {
|
verify {
|
||||||
val permission = sitePermissions.toggle(capture(toggledFeature))
|
controller.handlePermissionsChange(sitePermissions.toggle(PhoneFeature.CAMERA))
|
||||||
controller.handlePermissionsChange(permission)
|
|
||||||
}
|
}
|
||||||
// We should also modify View's state. Not necessarily as the last operation.
|
// We should also modify View's state. Not necessarily as the last operation.
|
||||||
verify {
|
verify {
|
||||||
store.dispatch(capture(action))
|
store.dispatch(match { action ->
|
||||||
|
PhoneFeature.CAMERA == (action as WebsitePermissionAction.TogglePermission).updatedFeature
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(toggledFeature.isCaptured)
|
|
||||||
assertSame(PhoneFeature.CAMERA, toggledFeature.captured)
|
|
||||||
|
|
||||||
assertTrue(action.isCaptured)
|
|
||||||
assertEquals(WebsitePermissionAction.TogglePermission::class, action.captured::class)
|
|
||||||
assertEquals(websitePermission::class,
|
|
||||||
(action.captured as WebsitePermissionAction.TogglePermission).websitePermission::class)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `handlePermissionToggled blocked by user should navigate to site permission manager`() {
|
fun `handlePermissionToggled blocked by user should navigate to site permission manager`() {
|
||||||
val websitePermission = mockk<WebsitePermission.Camera>()
|
val websitePermission = mockk<WebsitePermission>()
|
||||||
val invalidSitePermissionsController = DefaultQuickSettingsController(
|
val invalidSitePermissionsController = DefaultQuickSettingsController(
|
||||||
context = context,
|
context = context,
|
||||||
quickSettingsStore = store,
|
quickSettingsStore = store,
|
||||||
|
@ -149,6 +130,7 @@ class DefaultQuickSettingsControllerTest {
|
||||||
dismiss = dismiss
|
dismiss = dismiss
|
||||||
)
|
)
|
||||||
|
|
||||||
|
every { websitePermission.phoneFeature } returns PhoneFeature.CAMERA
|
||||||
every { websitePermission.isBlockedByAndroid } returns false
|
every { websitePermission.isBlockedByAndroid } returns false
|
||||||
every { navController.navigate(any<NavDirections>()) } just Runs
|
every { navController.navigate(any<NavDirections>()) } just Runs
|
||||||
|
|
||||||
|
@ -162,88 +144,44 @@ class DefaultQuickSettingsControllerTest {
|
||||||
@Test
|
@Test
|
||||||
fun `handleAndroidPermissionGranted should update the View's state`() {
|
fun `handleAndroidPermissionGranted should update the View's state`() {
|
||||||
val featureGranted = PhoneFeature.CAMERA
|
val featureGranted = PhoneFeature.CAMERA
|
||||||
val permission = with(controller) {
|
|
||||||
featureGranted.getCorrespondingPermission()
|
|
||||||
}
|
|
||||||
val permissionStatus = featureGranted.getActionLabel(context, sitePermissions, appSettings)
|
val permissionStatus = featureGranted.getActionLabel(context, sitePermissions, appSettings)
|
||||||
val permissionEnabled =
|
val permissionEnabled = featureGranted.shouldBeEnabled(context, sitePermissions, appSettings)
|
||||||
featureGranted.shouldBeEnabled(context, sitePermissions, appSettings)
|
|
||||||
val action = slot<QuickSettingsFragmentAction>()
|
|
||||||
every { store.dispatch(any()) } returns mockk()
|
every { store.dispatch(any()) } returns mockk()
|
||||||
|
|
||||||
controller.handleAndroidPermissionGranted(featureGranted)
|
controller.handleAndroidPermissionGranted(featureGranted)
|
||||||
|
|
||||||
verify {
|
verify {
|
||||||
store.dispatch(capture(action))
|
store.dispatch(withArg { action ->
|
||||||
|
action as WebsitePermissionAction.TogglePermission
|
||||||
|
assertEquals(featureGranted, action.updatedFeature)
|
||||||
|
assertEquals(permissionStatus, action.updatedStatus)
|
||||||
|
assertEquals(permissionEnabled, action.updatedEnabledStatus)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(action.isCaptured)
|
|
||||||
assertEquals(WebsitePermissionAction.TogglePermission::class, action.captured::class)
|
|
||||||
assertEquals(permission, (action.captured as WebsitePermissionAction.TogglePermission).websitePermission)
|
|
||||||
assertEquals(permissionStatus, (action.captured as WebsitePermissionAction.TogglePermission).updatedStatus)
|
|
||||||
assertEquals(permissionEnabled, (action.captured as WebsitePermissionAction.TogglePermission).updatedEnabledStatus)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `handleAndroidPermissionRequest should request from the injected callback`() {
|
fun `handleAndroidPermissionRequest should request from the injected callback`() {
|
||||||
val testPermissions = arrayOf("TestPermission")
|
val testPermissions = arrayOf("TestPermission")
|
||||||
val requiredPermissions = slot<Array<String>>()
|
|
||||||
// every { requestPermissions(capture(requiredPermissions)) } just Runs
|
|
||||||
|
|
||||||
controller.handleAndroidPermissionRequest(testPermissions)
|
controller.handleAndroidPermissionRequest(testPermissions)
|
||||||
|
|
||||||
verify { requestPermissions(capture(requiredPermissions)) }
|
verify { requestPermissions(eqArray(testPermissions)) }
|
||||||
|
|
||||||
assertTrue(requiredPermissions.isCaptured)
|
|
||||||
assertArrayEquals(testPermissions, requiredPermissions.captured)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
@Ignore("Intermittently failing; https://github.com/mozilla-mobile/fenix/issues/8621")
|
fun `handlePermissionsChange should store the updated permission and reload webpage`() = coroutinesScope.runBlockingTest {
|
||||||
fun `handlePermissionsChange should store the updated permission and reload webpage`() =
|
val testPermissions = mockk<SitePermissions>()
|
||||||
runBlocking {
|
|
||||||
val testPermissions = mockk<SitePermissions>()
|
|
||||||
val permissions = slot<SitePermissions>()
|
|
||||||
val session = slot<Session>()
|
|
||||||
|
|
||||||
controller.handlePermissionsChange(testPermissions)
|
controller.handlePermissionsChange(testPermissions)
|
||||||
|
|
||||||
verifyOrder {
|
verifyOrder {
|
||||||
permissionStorage.updateSitePermissions(capture(permissions))
|
permissionStorage.updateSitePermissions(testPermissions)
|
||||||
reload(capture(session))
|
reload(browserSession)
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue(permissions.isCaptured)
|
|
||||||
assertEquals(testPermissions, permissions.captured)
|
|
||||||
assertTrue(session.isCaptured)
|
|
||||||
assertEquals(browserSession, session.captured)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `WebsitePermission#getBackingFeature should return the PhoneFeature this permission is mapped from`() {
|
|
||||||
val cameraPermission = mockk<WebsitePermission.Camera>()
|
|
||||||
val microphonePermission = mockk<WebsitePermission.Microphone>()
|
|
||||||
val notificationPermission = mockk<WebsitePermission.Notification>()
|
|
||||||
val locationPermission = mockk<WebsitePermission.Location>()
|
|
||||||
|
|
||||||
with(controller) {
|
|
||||||
assertSame(PhoneFeature.CAMERA, cameraPermission.getBackingFeature())
|
|
||||||
assertSame(PhoneFeature.MICROPHONE, microphonePermission.getBackingFeature())
|
|
||||||
assertSame(PhoneFeature.NOTIFICATION, notificationPermission.getBackingFeature())
|
|
||||||
assertSame(PhoneFeature.LOCATION, locationPermission.getBackingFeature())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private inline fun <reified T> MockKMatcherScope.eqArray(value: Array<T>): Array<T> =
|
||||||
fun `PhoneFeature#getCorrespondingPermission should return the WebsitePermission which it maps to`() {
|
match { it contentEquals value }
|
||||||
with(controller) {
|
|
||||||
assertEquals(WebsitePermission.Camera::class, PhoneFeature.CAMERA.getCorrespondingPermission()::class)
|
|
||||||
assertEquals(WebsitePermission.Microphone::class, PhoneFeature.MICROPHONE.getCorrespondingPermission()::class)
|
|
||||||
assertEquals(WebsitePermission.Notification::class, PhoneFeature.NOTIFICATION.getCorrespondingPermission()::class)
|
|
||||||
assertEquals(WebsitePermission.Location::class, PhoneFeature.LOCATION.getCorrespondingPermission()::class)
|
|
||||||
assertEquals(WebsitePermission.AutoplayAudible::class, PhoneFeature.AUTOPLAY_AUDIBLE.getCorrespondingPermission()::class)
|
|
||||||
assertEquals(WebsitePermission.AutoplayInaudible::class, PhoneFeature.AUTOPLAY_INAUDIBLE.getCorrespondingPermission()::class)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,6 @@ import org.junit.runner.RunWith
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.getInsecureWebsiteUiValues
|
|
||||||
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.getPermissionStatus
|
|
||||||
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.getSecuredWebsiteUiValues
|
|
||||||
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.toWebsitePermission
|
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.toWebsitePermission
|
||||||
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
|
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
|
||||||
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeVisible
|
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeVisible
|
||||||
|
@ -38,12 +35,6 @@ class QuickSettingsFragmentStoreTest {
|
||||||
private val context = spyk(testContext)
|
private val context = spyk(testContext)
|
||||||
private val permissions = mockk<SitePermissions>()
|
private val permissions = mockk<SitePermissions>()
|
||||||
private val appSettings = mockk<Settings>()
|
private val appSettings = mockk<Settings>()
|
||||||
private val secureStringRes = R.string.quick_settings_sheet_secure_connection
|
|
||||||
private val secureDrawableRes = R.drawable.mozac_ic_lock
|
|
||||||
private val secureColorRes = R.color.photonGreen50
|
|
||||||
private val insecureStringRes = R.string.quick_settings_sheet_insecure_connection
|
|
||||||
private val insecureDrawableRes = R.drawable.mozac_ic_globe
|
|
||||||
private val insecureColorRes = R.color.photonRed50
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `createStore constructs a QuickSettingsFragmentState`() {
|
fun `createStore constructs a QuickSettingsFragmentState`() {
|
||||||
|
@ -72,9 +63,7 @@ class QuickSettingsFragmentStoreTest {
|
||||||
assertNotNull(state)
|
assertNotNull(state)
|
||||||
assertSame(websiteUrl, state.websiteUrl)
|
assertSame(websiteUrl, state.websiteUrl)
|
||||||
assertSame(websiteTitle, state.websiteTitle)
|
assertSame(websiteTitle, state.websiteTitle)
|
||||||
assertEquals(secureStringRes, state.securityInfoRes)
|
assertEquals(WebsiteSecurityUiValues.SECURE, state.websiteSecurityUiValues)
|
||||||
assertEquals(secureDrawableRes, state.iconRes)
|
|
||||||
assertEquals(secureColorRes, state.iconTintRes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -89,9 +78,7 @@ class QuickSettingsFragmentStoreTest {
|
||||||
assertNotNull(state)
|
assertNotNull(state)
|
||||||
assertSame(websiteUrl, state.websiteUrl)
|
assertSame(websiteUrl, state.websiteUrl)
|
||||||
assertSame(websiteTitle, state.websiteTitle)
|
assertSame(websiteTitle, state.websiteTitle)
|
||||||
assertEquals(insecureStringRes, state.securityInfoRes)
|
assertEquals(WebsiteSecurityUiValues.INSECURE, state.websiteSecurityUiValues)
|
||||||
assertEquals(insecureDrawableRes, state.iconRes)
|
|
||||||
assertEquals(insecureColorRes, state.iconTintRes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -118,12 +105,12 @@ class QuickSettingsFragmentStoreTest {
|
||||||
// Just need to know that the WebsitePermissionsState properties are initialized.
|
// Just need to know that the WebsitePermissionsState properties are initialized.
|
||||||
// Making sure they are correctly initialized is tested in the `initWebsitePermission` test.
|
// Making sure they are correctly initialized is tested in the `initWebsitePermission` test.
|
||||||
assertNotNull(state)
|
assertNotNull(state)
|
||||||
assertNotNull(state.camera)
|
assertNotNull(state[PhoneFeature.CAMERA])
|
||||||
assertNotNull(state.microphone)
|
assertNotNull(state[PhoneFeature.MICROPHONE])
|
||||||
assertNotNull(state.notification)
|
assertNotNull(state[PhoneFeature.NOTIFICATION])
|
||||||
assertNotNull(state.location)
|
assertNotNull(state[PhoneFeature.LOCATION])
|
||||||
assertNotNull(state.autoplayAudible)
|
assertNotNull(state[PhoneFeature.AUTOPLAY_AUDIBLE])
|
||||||
assertNotNull(state.autoplayInaudible)
|
assertNotNull(state[PhoneFeature.AUTOPLAY_INAUDIBLE])
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -142,7 +129,7 @@ class QuickSettingsFragmentStoreTest {
|
||||||
val websitePermission = cameraFeature.toWebsitePermission(context, permissions, appSettings)
|
val websitePermission = cameraFeature.toWebsitePermission(context, permissions, appSettings)
|
||||||
|
|
||||||
assertNotNull(websitePermission)
|
assertNotNull(websitePermission)
|
||||||
assertEquals(WebsitePermission.Camera::class, websitePermission::class)
|
assertEquals(cameraFeature, websitePermission.phoneFeature)
|
||||||
assertEquals(allowedStatus, websitePermission.status)
|
assertEquals(allowedStatus, websitePermission.status)
|
||||||
assertTrue(websitePermission.isVisible)
|
assertTrue(websitePermission.isVisible)
|
||||||
assertTrue(websitePermission.isEnabled)
|
assertTrue(websitePermission.isEnabled)
|
||||||
|
@ -154,7 +141,7 @@ class QuickSettingsFragmentStoreTest {
|
||||||
val phoneFeature = PhoneFeature.CAMERA
|
val phoneFeature = PhoneFeature.CAMERA
|
||||||
every { permissions.camera } returns SitePermissions.Status.NO_DECISION
|
every { permissions.camera } returns SitePermissions.Status.NO_DECISION
|
||||||
|
|
||||||
val permissionsStatus = phoneFeature.getPermissionStatus(context, permissions, appSettings)
|
val permissionsStatus = phoneFeature.toWebsitePermission(context, permissions, appSettings)
|
||||||
|
|
||||||
verify {
|
verify {
|
||||||
// Verifying phoneFeature.getActionLabel gets "Status(child of #2#4).ordinal()) was not called"
|
// Verifying phoneFeature.getActionLabel gets "Status(child of #2#4).ordinal()) was not called"
|
||||||
|
@ -174,12 +161,6 @@ class QuickSettingsFragmentStoreTest {
|
||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
fun `TogglePermission should only modify status and visibility of a specific WebsitePermissionsState`() =
|
fun `TogglePermission should only modify status and visibility of a specific WebsitePermissionsState`() =
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val cameraPermissionName = "Camera"
|
|
||||||
val microphonePermissionName = "Microphone"
|
|
||||||
val notificationPermissionName = "Notification"
|
|
||||||
val locationPermissionName = "Location"
|
|
||||||
val autoplayAudiblePermissionName = "AutoplayAudible"
|
|
||||||
val autoplayInaudiblePermissionName = "AutoplayInaudible"
|
|
||||||
val initialCameraStatus = "initialCameraStatus"
|
val initialCameraStatus = "initialCameraStatus"
|
||||||
val initialMicStatus = "initialMicStatus"
|
val initialMicStatus = "initialMicStatus"
|
||||||
val initialNotificationStatus = "initialNotificationStatus"
|
val initialNotificationStatus = "initialNotificationStatus"
|
||||||
|
@ -192,31 +173,37 @@ class QuickSettingsFragmentStoreTest {
|
||||||
val defaultEnabledStatus = true
|
val defaultEnabledStatus = true
|
||||||
val defaultBlockedByAndroidStatus = true
|
val defaultBlockedByAndroidStatus = true
|
||||||
val websiteInfoState = mockk<WebsiteInfoState>()
|
val websiteInfoState = mockk<WebsiteInfoState>()
|
||||||
val initialWebsitePermissionsState = WebsitePermissionsState(
|
val baseWebsitePermission = WebsitePermission(
|
||||||
|
phoneFeature = PhoneFeature.CAMERA,
|
||||||
|
status = "",
|
||||||
isVisible = true,
|
isVisible = true,
|
||||||
camera = WebsitePermission.Camera(
|
isEnabled = true,
|
||||||
initialCameraStatus, defaultVisibilityStatus,
|
isBlockedByAndroid = true
|
||||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, cameraPermissionName
|
)
|
||||||
|
val initialWebsitePermissionsState = mapOf(
|
||||||
|
PhoneFeature.CAMERA to baseWebsitePermission.copy(
|
||||||
|
phoneFeature = PhoneFeature.CAMERA,
|
||||||
|
status = initialCameraStatus
|
||||||
),
|
),
|
||||||
microphone = WebsitePermission.Microphone(
|
PhoneFeature.MICROPHONE to baseWebsitePermission.copy(
|
||||||
initialMicStatus, defaultVisibilityStatus,
|
phoneFeature = PhoneFeature.MICROPHONE,
|
||||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, microphonePermissionName
|
status = initialMicStatus
|
||||||
),
|
),
|
||||||
notification = WebsitePermission.Notification(
|
PhoneFeature.NOTIFICATION to baseWebsitePermission.copy(
|
||||||
initialNotificationStatus, defaultVisibilityStatus,
|
phoneFeature = PhoneFeature.NOTIFICATION,
|
||||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, notificationPermissionName
|
status = initialNotificationStatus
|
||||||
),
|
),
|
||||||
location = WebsitePermission.Location(
|
PhoneFeature.LOCATION to baseWebsitePermission.copy(
|
||||||
initialLocationStatus, defaultVisibilityStatus,
|
phoneFeature = PhoneFeature.LOCATION,
|
||||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, locationPermissionName
|
status = initialLocationStatus
|
||||||
),
|
),
|
||||||
autoplayAudible = WebsitePermission.AutoplayAudible(
|
PhoneFeature.AUTOPLAY_AUDIBLE to baseWebsitePermission.copy(
|
||||||
initialAutoplayAudibleStatus, defaultVisibilityStatus,
|
phoneFeature = PhoneFeature.AUTOPLAY_AUDIBLE,
|
||||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, autoplayAudiblePermissionName
|
status = initialAutoplayAudibleStatus
|
||||||
),
|
),
|
||||||
autoplayInaudible = WebsitePermission.AutoplayInaudible(
|
PhoneFeature.AUTOPLAY_INAUDIBLE to baseWebsitePermission.copy(
|
||||||
initialAutoplayInaudibleStatus, defaultVisibilityStatus,
|
phoneFeature = PhoneFeature.AUTOPLAY_INAUDIBLE,
|
||||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, autoplayInaudiblePermissionName
|
status = initialAutoplayInaudibleStatus
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val initialState = QuickSettingsFragmentState(
|
val initialState = QuickSettingsFragmentState(
|
||||||
|
@ -226,7 +213,7 @@ class QuickSettingsFragmentStoreTest {
|
||||||
|
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
WebsitePermissionAction.TogglePermission(
|
WebsitePermissionAction.TogglePermission(
|
||||||
mockk<WebsitePermission.Microphone>(),
|
PhoneFeature.MICROPHONE,
|
||||||
updatedMicrophoneStatus,
|
updatedMicrophoneStatus,
|
||||||
updatedMicrophoneEnabledStatus
|
updatedMicrophoneEnabledStatus
|
||||||
)
|
)
|
||||||
|
@ -237,53 +224,35 @@ class QuickSettingsFragmentStoreTest {
|
||||||
assertNotSame(initialWebsitePermissionsState, store.state.websitePermissionsState)
|
assertNotSame(initialWebsitePermissionsState, store.state.websitePermissionsState)
|
||||||
assertSame(websiteInfoState, store.state.webInfoState)
|
assertSame(websiteInfoState, store.state.webInfoState)
|
||||||
|
|
||||||
assertNotNull(store.state.websitePermissionsState.camera)
|
assertNotNull(store.state.websitePermissionsState[PhoneFeature.CAMERA])
|
||||||
assertEquals(cameraPermissionName, (store.state.websitePermissionsState.camera as WebsitePermission.Camera).name)
|
assertEquals(PhoneFeature.CAMERA, store.state.websitePermissionsState.getValue(PhoneFeature.CAMERA).phoneFeature)
|
||||||
assertEquals(initialCameraStatus, store.state.websitePermissionsState.camera.status)
|
assertEquals(initialCameraStatus, store.state.websitePermissionsState.getValue(PhoneFeature.CAMERA).status)
|
||||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.camera.isVisible)
|
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.getValue(PhoneFeature.CAMERA).isVisible)
|
||||||
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.camera.isEnabled)
|
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.getValue(PhoneFeature.CAMERA).isEnabled)
|
||||||
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.camera.isBlockedByAndroid)
|
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.getValue(PhoneFeature.CAMERA).isBlockedByAndroid)
|
||||||
|
|
||||||
assertNotNull(store.state.websitePermissionsState.microphone)
|
assertNotNull(store.state.websitePermissionsState[PhoneFeature.MICROPHONE])
|
||||||
assertEquals(microphonePermissionName, (store.state.websitePermissionsState.microphone as WebsitePermission.Microphone).name)
|
assertEquals(PhoneFeature.MICROPHONE, store.state.websitePermissionsState.getValue(PhoneFeature.MICROPHONE).phoneFeature)
|
||||||
|
|
||||||
// Only the following two properties must have been changed!
|
// Only the following two properties must have been changed!
|
||||||
assertEquals(updatedMicrophoneStatus, store.state.websitePermissionsState.microphone.status)
|
assertEquals(updatedMicrophoneStatus, store.state.websitePermissionsState.getValue(PhoneFeature.MICROPHONE).status)
|
||||||
assertEquals(updatedMicrophoneEnabledStatus, store.state.websitePermissionsState.microphone.isEnabled)
|
assertEquals(updatedMicrophoneEnabledStatus, store.state.websitePermissionsState.getValue(PhoneFeature.MICROPHONE).isEnabled)
|
||||||
|
|
||||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.microphone.isVisible)
|
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.getValue(PhoneFeature.MICROPHONE).isVisible)
|
||||||
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.microphone.isBlockedByAndroid)
|
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.getValue(PhoneFeature.MICROPHONE).isBlockedByAndroid)
|
||||||
|
|
||||||
assertNotNull(store.state.websitePermissionsState.notification)
|
assertNotNull(store.state.websitePermissionsState[PhoneFeature.NOTIFICATION])
|
||||||
assertEquals(notificationPermissionName, (store.state.websitePermissionsState.notification as WebsitePermission.Notification).name)
|
assertEquals(PhoneFeature.NOTIFICATION, store.state.websitePermissionsState.getValue(PhoneFeature.NOTIFICATION).phoneFeature)
|
||||||
assertEquals(initialNotificationStatus, store.state.websitePermissionsState.notification.status)
|
assertEquals(initialNotificationStatus, store.state.websitePermissionsState.getValue(PhoneFeature.NOTIFICATION).status)
|
||||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.notification.isVisible)
|
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.getValue(PhoneFeature.NOTIFICATION).isVisible)
|
||||||
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.notification.isEnabled)
|
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.getValue(PhoneFeature.NOTIFICATION).isEnabled)
|
||||||
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.notification.isBlockedByAndroid)
|
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.getValue(PhoneFeature.NOTIFICATION).isBlockedByAndroid)
|
||||||
|
|
||||||
assertNotNull(store.state.websitePermissionsState.location)
|
assertNotNull(store.state.websitePermissionsState[PhoneFeature.LOCATION])
|
||||||
assertEquals(locationPermissionName, (store.state.websitePermissionsState.location as WebsitePermission.Location).name)
|
assertEquals(PhoneFeature.LOCATION, store.state.websitePermissionsState.getValue(PhoneFeature.LOCATION).phoneFeature)
|
||||||
assertEquals(initialLocationStatus, store.state.websitePermissionsState.location.status)
|
assertEquals(initialLocationStatus, store.state.websitePermissionsState.getValue(PhoneFeature.LOCATION).status)
|
||||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.location.isVisible)
|
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.getValue(PhoneFeature.LOCATION).isVisible)
|
||||||
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.location.isEnabled)
|
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.getValue(PhoneFeature.LOCATION).isEnabled)
|
||||||
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.location.isBlockedByAndroid)
|
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.getValue(PhoneFeature.LOCATION).isBlockedByAndroid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `getSecuredWebsiteUiValues() should return the right values`() {
|
|
||||||
val uiValues = getSecuredWebsiteUiValues
|
|
||||||
|
|
||||||
assertEquals(secureStringRes, uiValues.first)
|
|
||||||
assertEquals(secureDrawableRes, uiValues.second)
|
|
||||||
assertEquals(secureColorRes, uiValues.third)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `getInsecureWebsiteUiValues() should return the right values`() {
|
|
||||||
val uiValues = getInsecureWebsiteUiValues
|
|
||||||
|
|
||||||
assertEquals(insecureStringRes, uiValues.first)
|
|
||||||
assertEquals(insecureDrawableRes, uiValues.second)
|
|
||||||
assertEquals(insecureColorRes, uiValues.third)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue