Simplify `PhoneFeature` code (#10810)
parent
74948cb3f1
commit
1a19b06227
|
@ -4,26 +4,33 @@
|
|||
|
||||
package org.mozilla.fenix.settings
|
||||
|
||||
import android.view.View
|
||||
import android.widget.RadioButton
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.preference.Preference
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelative
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.theme.ThemeManager
|
||||
|
||||
fun SitePermissions.toggle(featurePhone: PhoneFeature): SitePermissions {
|
||||
return when (featurePhone) {
|
||||
PhoneFeature.CAMERA -> copy(camera = camera.toggle())
|
||||
PhoneFeature.LOCATION -> copy(location = location.toggle())
|
||||
PhoneFeature.MICROPHONE -> copy(microphone = microphone.toggle())
|
||||
PhoneFeature.NOTIFICATION -> copy(notification = notification.toggle())
|
||||
PhoneFeature.AUTOPLAY_AUDIBLE -> copy(autoplayAudible = autoplayAudible.toggle())
|
||||
PhoneFeature.AUTOPLAY_INAUDIBLE -> copy(autoplayInaudible = autoplayInaudible.toggle())
|
||||
}
|
||||
return update(featurePhone, get(featurePhone).toggle())
|
||||
}
|
||||
|
||||
fun SitePermissions.get(field: PhoneFeature) = when (field) {
|
||||
PhoneFeature.CAMERA -> camera
|
||||
PhoneFeature.LOCATION -> location
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
* 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.RECORD_AUDIO
|
||||
import android.content.Context
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.StringRes
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
||||
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 android.Manifest.permission.CAMERA as CAMERA_PERMISSION
|
||||
|
||||
const val ID_CAMERA_PERMISSION = 0
|
||||
const val ID_LOCATION_PERMISSION = 1
|
||||
const val ID_MICROPHONE_PERMISSION = 2
|
||||
const val ID_NOTIFICATION_PERMISSION = 3
|
||||
const val ID_AUTOPLAY_AUDIBLE_PERMISSION = 4
|
||||
const val ID_AUTOPLAY_INAUDIBLE_PERMISSION = 5
|
||||
|
||||
enum class PhoneFeature(val id: Int, val androidPermissionsList: Array<String>) {
|
||||
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());
|
||||
@Parcelize
|
||||
enum class PhoneFeature(val androidPermissionsList: Array<String>) : Parcelable {
|
||||
CAMERA(arrayOf(CAMERA_PERMISSION)),
|
||||
LOCATION(arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION)),
|
||||
MICROPHONE(arrayOf(RECORD_AUDIO)),
|
||||
NOTIFICATION(emptyArray()),
|
||||
AUTOPLAY_AUDIBLE(emptyArray()),
|
||||
AUTOPLAY_INAUDIBLE(emptyArray());
|
||||
|
||||
fun isAndroidPermissionGranted(context: Context): Boolean {
|
||||
return when (this) {
|
||||
CAMERA, LOCATION, MICROPHONE -> context.isPermissionGranted(androidPermissionsList.asIterable())
|
||||
NOTIFICATION, AUTOPLAY_AUDIBLE, AUTOPLAY_INAUDIBLE -> true
|
||||
}
|
||||
return context.isPermissionGranted(androidPermissionsList.asIterable())
|
||||
}
|
||||
|
||||
@Suppress("ComplexMethod")
|
||||
|
@ -78,7 +71,7 @@ enum class PhoneFeature(val id: Int, val androidPermissionsList: Array<String>)
|
|||
sitePermissions: SitePermissions? = null,
|
||||
settings: Settings? = null
|
||||
): SitePermissions.Status {
|
||||
val status = getStatus(sitePermissions) ?: settings?.let(::getAction)?.toStatus()
|
||||
val status = sitePermissions?.get(this) ?: settings?.let(::getAction)?.toStatus()
|
||||
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 {
|
||||
fun findFeatureBy(permissions: Array<out String>): PhoneFeature? {
|
||||
return values().find { feature ->
|
||||
|
|
|
@ -52,7 +52,7 @@ interface QuickSettingsController {
|
|||
* Default behavior of [QuickSettingsController]. Other implementations are possible.
|
||||
*
|
||||
* @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.
|
||||
* @param coroutineScope [CoroutineScope] used for structed concurrency.
|
||||
* @param navController NavController] used for navigation.
|
||||
|
@ -88,21 +88,20 @@ class DefaultQuickSettingsController(
|
|||
}
|
||||
|
||||
override fun handlePermissionToggled(permission: WebsitePermission) {
|
||||
val featureToggled = permission.getBackingFeature()
|
||||
val featureToggled = permission.phoneFeature
|
||||
|
||||
when (permission.isBlockedByAndroid) {
|
||||
true -> handleAndroidPermissionRequest(featureToggled.androidPermissionsList)
|
||||
false -> {
|
||||
val permissions = sitePermissions
|
||||
if (permissions != null) {
|
||||
val newPermissions = permissions.toggle(featureToggled).also {
|
||||
handlePermissionsChange(it)
|
||||
}
|
||||
val newPermissions = permissions.toggle(featureToggled)
|
||||
handlePermissionsChange(newPermissions)
|
||||
sitePermissions = newPermissions
|
||||
|
||||
quickSettingsStore.dispatch(
|
||||
WebsitePermissionAction.TogglePermission(
|
||||
permission,
|
||||
featureToggled,
|
||||
featureToggled.getActionLabel(context, newPermissions, settings),
|
||||
featureToggled.shouldBeEnabled(context, newPermissions, settings)
|
||||
)
|
||||
|
@ -117,7 +116,7 @@ class DefaultQuickSettingsController(
|
|||
override fun handleAndroidPermissionGranted(feature: PhoneFeature) {
|
||||
quickSettingsStore.dispatch(
|
||||
WebsitePermissionAction.TogglePermission(
|
||||
feature.getCorrespondingPermission(),
|
||||
feature,
|
||||
feature.getActionLabel(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]
|
||||
*
|
||||
|
@ -207,7 +156,7 @@ class DefaultQuickSettingsController(
|
|||
*/
|
||||
private fun navigateToManagePhoneFeature(phoneFeature: PhoneFeature) {
|
||||
val directions = QuickSettingsSheetDialogFragmentDirections
|
||||
.actionGlobalSitePermissionsManagePhoneFeature(phoneFeature.id)
|
||||
.actionGlobalSitePermissionsManagePhoneFeature(phoneFeature)
|
||||
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
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import mozilla.components.lib.state.Action
|
||||
import mozilla.components.lib.state.Reducer
|
||||
import mozilla.components.lib.state.State
|
||||
import mozilla.components.lib.state.Store
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.settings.PhoneFeature
|
||||
import org.mozilla.fenix.settings.quicksettings.QuickSettingsFragmentStore.Companion.createStore
|
||||
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
|
||||
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeVisible
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import java.util.EnumMap
|
||||
|
||||
/**
|
||||
* [QuickSettingsSheetDialogFragment]'s unique [Store].
|
||||
|
@ -40,27 +37,6 @@ class QuickSettingsFragmentStore(
|
|||
::quickSettingsFragmentReducer
|
||||
) {
|
||||
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
|
||||
* [QuickSettingsSheetDialogFragment].
|
||||
|
@ -109,11 +85,8 @@ class QuickSettingsFragmentStore(
|
|||
isSecured: Boolean,
|
||||
certificateName: String
|
||||
): WebsiteInfoState {
|
||||
val (stringRes, iconRes, colorRes) = when (isSecured) {
|
||||
true -> getSecuredWebsiteUiValues
|
||||
false -> getInsecureWebsiteUiValues
|
||||
}
|
||||
return WebsiteInfoState(websiteUrl, websiteTitle, stringRes, iconRes, colorRes, certificateName)
|
||||
val uiValues = if (isSecured) WebsiteSecurityUiValues.SECURE else WebsiteSecurityUiValues.INSECURE
|
||||
return WebsiteInfoState(websiteUrl, websiteTitle, uiValues, certificateName)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,26 +105,11 @@ class QuickSettingsFragmentStore(
|
|||
permissions: SitePermissions?,
|
||||
settings: Settings
|
||||
): WebsitePermissionsState {
|
||||
val cameraPermission =
|
||||
PhoneFeature.CAMERA.toWebsitePermission(context, permissions, settings)
|
||||
val microphonePermission =
|
||||
PhoneFeature.MICROPHONE.toWebsitePermission(context, permissions, settings)
|
||||
val notificationPermission =
|
||||
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
|
||||
)
|
||||
val state = EnumMap<PhoneFeature, WebsitePermission>(PhoneFeature::class.java)
|
||||
for (feature in PhoneFeature.values()) {
|
||||
state[feature] = feature.toWebsitePermission(context, permissions, settings)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -163,425 +121,13 @@ class QuickSettingsFragmentStore(
|
|||
permissions: SitePermissions?,
|
||||
settings: Settings
|
||||
): WebsitePermission {
|
||||
val status = getPermissionStatus(context, permissions, settings)
|
||||
return when (this) {
|
||||
PhoneFeature.CAMERA -> WebsitePermission.Camera(
|
||||
status.status, status.isVisible, status.isEnabled, status.isBlockedByAndroid
|
||||
)
|
||||
PhoneFeature.LOCATION -> WebsitePermission.Location(
|
||||
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
|
||||
return WebsitePermission(
|
||||
phoneFeature = this,
|
||||
status = getActionLabel(context, permissions, settings),
|
||||
isVisible = shouldBeVisible(permissions, settings),
|
||||
isEnabled = shouldBeEnabled(context, permissions, settings),
|
||||
isBlockedByAndroid = !isAndroidPermissionGranted(context)
|
||||
)
|
||||
)
|
||||
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.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.ContextCompat.getColor
|
||||
import androidx.core.view.isVisible
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.quicksettings_website_info.view.*
|
||||
import mozilla.components.support.ktx.android.content.getDrawableWithTint
|
||||
import org.mozilla.fenix.R
|
||||
|
||||
/**
|
||||
|
@ -38,7 +35,7 @@ class WebsiteInfoView(
|
|||
fun update(state: WebsiteInfoState) {
|
||||
bindUrl(state.websiteUrl)
|
||||
bindTitle(state.websiteTitle)
|
||||
bindSecurityInfo(state.securityInfoRes, state.iconRes, state.iconTintRes)
|
||||
bindSecurityInfo(state.websiteSecurityUiValues)
|
||||
bindCertificateName(state.certificateName)
|
||||
}
|
||||
|
||||
|
@ -56,14 +53,11 @@ class WebsiteInfoView(
|
|||
view.certificateInfo.isVisible = cert.isNotEmpty()
|
||||
}
|
||||
|
||||
private fun bindSecurityInfo(
|
||||
@StringRes securityInfoRes: Int,
|
||||
@DrawableRes iconRes: Int,
|
||||
@ColorRes iconTintRes: Int
|
||||
) {
|
||||
val icon = AppCompatResources.getDrawable(view.context, iconRes)
|
||||
icon?.setTint(ContextCompat.getColor(view.context, iconTintRes))
|
||||
view.securityInfo.setText(securityInfoRes)
|
||||
view.securityInfoIcon.setImageResource(iconRes)
|
||||
private fun bindSecurityInfo(uiValues: WebsiteSecurityUiValues) {
|
||||
val tint = getColor(view.context, uiValues.iconTintRes)
|
||||
view.securityInfo.setText(uiValues.securityInfoRes)
|
||||
view.securityInfoIcon.setImageDrawable(
|
||||
view.context.getDrawableWithTint(uiValues.iconRes, tint)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,10 @@ import android.view.ViewGroup
|
|||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.quicksettings_permissions.view.*
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.settings.PhoneFeature
|
||||
import java.util.EnumMap
|
||||
|
||||
/**
|
||||
* Contract declaring all possible user interactions with [WebsitePermissionsView]
|
||||
|
@ -49,26 +52,31 @@ class WebsitePermissionsView(
|
|||
val view: View = LayoutInflater.from(context)
|
||||
.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.
|
||||
*
|
||||
* @param state [WebsitePermissionsState] to be rendered.
|
||||
*/
|
||||
fun update(state: WebsitePermissionsState) {
|
||||
if (state.isVisible) {
|
||||
val isVisible = permissionViews.keys
|
||||
.map { feature -> state.getValue(feature) }
|
||||
.any { it.isVisible }
|
||||
if (isVisible) {
|
||||
interactor.onPermissionsShown()
|
||||
}
|
||||
|
||||
// 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
|
||||
bindPermission(state.camera,
|
||||
Pair(view.findViewById(R.id.cameraLabel), view.findViewById(R.id.cameraStatus)))
|
||||
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)))
|
||||
for ((feature, views) in permissionViews) {
|
||||
bindPermission(state.getValue(feature), views)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,15 +84,15 @@ class WebsitePermissionsView(
|
|||
* 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 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>) {
|
||||
val (label, status) = permissionViews
|
||||
|
||||
status.text = permissionState.status
|
||||
label.isEnabled = permissionState.isEnabled
|
||||
label.isVisible = permissionState.isVisible
|
||||
status.isVisible = permissionState.isVisible
|
||||
status.setOnClickListener { interactor.onPermissionToggled(permissionState) }
|
||||
private fun bindPermission(permissionState: WebsitePermission, viewHolder: PermissionViewHolder) {
|
||||
viewHolder.label.isEnabled = permissionState.isEnabled
|
||||
viewHolder.label.isVisible = permissionState.isVisible
|
||||
viewHolder.status.text = permissionState.status
|
||||
viewHolder.status.isVisible = permissionState.isVisible
|
||||
viewHolder.status.setOnClickListener { interactor.onPermissionToggled(permissionState) }
|
||||
}
|
||||
|
||||
data class PermissionViewHolder(val label: TextView, val status: TextView)
|
||||
}
|
||||
|
|
|
@ -4,8 +4,13 @@
|
|||
|
||||
package org.mozilla.fenix.settings.sitepermissions
|
||||
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
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.settings.PhoneFeature
|
||||
|
||||
/**
|
||||
* 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 }
|
||||
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) {
|
||||
val directions =
|
||||
SitePermissionsDetailsExceptionsFragmentDirections.actionSitePermissionsToExceptionsToManagePhoneFeature(
|
||||
phoneFeatureId = phoneFeature.id,
|
||||
phoneFeature = phoneFeature,
|
||||
sitePermissions = sitePermissions
|
||||
)
|
||||
requireView().findNavController().navigate(directions)
|
||||
|
|
|
@ -77,7 +77,7 @@ class SitePermissionsFragment : PreferenceFragmentCompat() {
|
|||
|
||||
private fun navigateToPhoneFeature(phoneFeature: PhoneFeature) {
|
||||
val directions = SitePermissionsFragmentDirections
|
||||
.actionSitePermissionsToManagePhoneFeatures(phoneFeature.id)
|
||||
.actionSitePermissionsToManagePhoneFeatures(phoneFeature)
|
||||
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.settings
|
||||
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.update
|
||||
|
||||
@SuppressWarnings("TooManyFunctions")
|
||||
class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment() {
|
||||
|
||||
private lateinit var phoneFeature: PhoneFeature
|
||||
private lateinit var sitePermissions: SitePermissions
|
||||
private lateinit var radioAllow: RadioButton
|
||||
private lateinit var radioBlock: RadioButton
|
||||
private lateinit var blockedByAndroidView: View
|
||||
private val args by navArgs<SitePermissionsManageExceptionsPhoneFeatureFragmentArgs>()
|
||||
val settings by lazy { requireContext().settings() }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val args by navArgs<SitePermissionsManageExceptionsPhoneFeatureFragmentArgs>()
|
||||
|
||||
phoneFeature = args.phoneFeatureId.toPhoneFeature()
|
||||
sitePermissions = args.sitePermissions
|
||||
|
||||
showToolbar(phoneFeature.getLabel(requireContext()))
|
||||
showToolbar(args.phoneFeature.getLabel(requireContext()))
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
|
@ -71,7 +64,7 @@ class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment() {
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
initBlockedByAndroidView(phoneFeature, blockedByAndroidView)
|
||||
initBlockedByAndroidView(args.phoneFeature, blockedByAndroidView)
|
||||
}
|
||||
|
||||
private fun initAskToAllowRadio(rootView: View) {
|
||||
|
@ -87,7 +80,7 @@ class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun RadioButton.restoreState(status: SitePermissions.Status) {
|
||||
if (phoneFeature.getStatus(sitePermissions) == status) {
|
||||
if (args.phoneFeature.getStatus(args.sitePermissions) == status) {
|
||||
this.isChecked = true
|
||||
this.setStartCheckedIndicator()
|
||||
}
|
||||
|
@ -109,7 +102,7 @@ class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment() {
|
|||
setMessage(R.string.confirm_clear_permission_site)
|
||||
setTitle(R.string.clear_permission)
|
||||
setPositiveButton(android.R.string.yes) { dialog: DialogInterface, _ ->
|
||||
val defaultStatus = phoneFeature.getStatus(settings = settings)
|
||||
val defaultStatus = args.phoneFeature.getStatus(settings = settings)
|
||||
updatedSitePermissions(defaultStatus)
|
||||
resetRadioButtonsStatus(defaultStatus)
|
||||
dialog.dismiss()
|
||||
|
@ -147,23 +140,8 @@ class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment() {
|
|||
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) {
|
||||
val updatedSitePermissions = when (phoneFeature) {
|
||||
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)
|
||||
}
|
||||
val updatedSitePermissions = args.sitePermissions.update(args.phoneFeature, status)
|
||||
viewLifecycleOwner.lifecycleScope.launch(IO) {
|
||||
requireComponents.core.permissionStorage.updateSitePermissions(updatedSitePermissions)
|
||||
launch(Main) {
|
||||
|
|
|
@ -20,10 +20,8 @@ import android.view.ViewGroup
|
|||
import android.widget.Button
|
||||
import android.widget.RadioButton
|
||||
import androidx.fragment.app.Fragment
|
||||
import kotlinx.android.synthetic.main.fragment_manage_site_permissions_feature_phone.view.ask_to_allow_radio
|
||||
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.fourth_radio
|
||||
import kotlinx.android.synthetic.main.fragment_manage_site_permissions_feature_phone.view.third_radio
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import kotlinx.android.synthetic.main.fragment_manage_site_permissions_feature_phone.view.*
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ALLOWED
|
||||
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.ext.settings
|
||||
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_INAUDIBLE
|
||||
import org.mozilla.fenix.settings.initBlockedByAndroidView
|
||||
import org.mozilla.fenix.settings.setStartCheckedIndicator
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
|
||||
|
@ -45,19 +41,11 @@ const val AUTOPLAY_ALLOW_ALL = 3
|
|||
|
||||
@SuppressWarnings("TooManyFunctions")
|
||||
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
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
phoneFeature = SitePermissionsManagePhoneFeatureFragmentArgs
|
||||
.fromBundle(requireArguments())
|
||||
.permission.toPhoneFeature()
|
||||
settings = requireContext().settings()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
@ -80,13 +68,13 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
showToolbar(phoneFeature.getLabel(requireContext()))
|
||||
initBlockedByAndroidView(phoneFeature, blockedByAndroidView)
|
||||
showToolbar(args.phoneFeature.getLabel(requireContext()))
|
||||
initBlockedByAndroidView(args.phoneFeature, blockedByAndroidView)
|
||||
}
|
||||
|
||||
private fun initFirstRadio(rootView: View) {
|
||||
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
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1621825 is fixed
|
||||
// text = getString(R.string.preference_option_autoplay_allowed2)
|
||||
|
@ -111,7 +99,7 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
|||
|
||||
private fun initSecondRadio(rootView: View) {
|
||||
with(rootView.block_radio) {
|
||||
if (phoneFeature == AUTOPLAY_AUDIBLE) {
|
||||
if (args.phoneFeature == AUTOPLAY_AUDIBLE) {
|
||||
text = getCombinedLabel(
|
||||
getString(R.string.preference_option_autoplay_allowed_wifi_only2),
|
||||
getString(R.string.preference_option_autoplay_allowed_wifi_subtext)
|
||||
|
@ -135,7 +123,7 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
|||
|
||||
private fun initThirdRadio(rootView: View) {
|
||||
with(rootView.third_radio) {
|
||||
if (phoneFeature == AUTOPLAY_AUDIBLE) {
|
||||
if (args.phoneFeature == AUTOPLAY_AUDIBLE) {
|
||||
visibility = View.VISIBLE
|
||||
text = getString(R.string.preference_option_autoplay_block_audio2)
|
||||
setOnClickListener {
|
||||
|
@ -150,7 +138,7 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
|||
|
||||
private fun initFourthRadio(rootView: View) {
|
||||
with(rootView.fourth_radio) {
|
||||
if (phoneFeature == AUTOPLAY_AUDIBLE) {
|
||||
if (args.phoneFeature == AUTOPLAY_AUDIBLE) {
|
||||
visibility = View.VISIBLE
|
||||
text = getCombinedLabel(
|
||||
getString(R.string.preference_option_autoplay_blocked3),
|
||||
|
@ -167,7 +155,7 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun RadioButton.restoreState(buttonAction: SitePermissionsRules.Action) {
|
||||
if (phoneFeature.getAction(settings) == buttonAction) {
|
||||
if (args.phoneFeature.getAction(settings) == buttonAction) {
|
||||
this.isChecked = true
|
||||
this.setStartCheckedIndicator()
|
||||
}
|
||||
|
@ -181,7 +169,7 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun saveActionInSettings(action: SitePermissionsRules.Action) {
|
||||
settings.setSitePermissionsPhoneFeatureAction(phoneFeature, action)
|
||||
settings.setSitePermissionsPhoneFeatureAction(args.phoneFeature, action)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -211,14 +199,6 @@ class SitePermissionsManagePhoneFeatureFragment : Fragment() {
|
|||
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) {
|
||||
val button = rootView.findViewById<Button>(R.id.settings_button)
|
||||
button.setOnClickListener {
|
||||
|
|
|
@ -92,8 +92,8 @@
|
|||
android:name="org.mozilla.fenix.settings.sitepermissions.SitePermissionsManagePhoneFeatureFragment"
|
||||
tools:layout="@layout/fragment_manage_site_permissions_feature_phone">
|
||||
<argument
|
||||
android:name="permission"
|
||||
app:argType="integer" />
|
||||
android:name="phoneFeature"
|
||||
app:argType="org.mozilla.fenix.settings.PhoneFeature" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
@ -125,8 +125,8 @@
|
|||
android:name="org.mozilla.fenix.settings.sitepermissions.SitePermissionsManageExceptionsPhoneFeatureFragment"
|
||||
tools:layout="@layout/fragment_manage_site_permissions_feature_phone">
|
||||
<argument
|
||||
android:name="phoneFeatureId"
|
||||
app:argType="integer" />
|
||||
android:name="phoneFeature"
|
||||
app:argType="org.mozilla.fenix.settings.PhoneFeature" />
|
||||
<argument
|
||||
android:name="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.NavDirections
|
||||
import io.mockk.MockKMatcherScope
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.slot
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import io.mockk.verifyOrder
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.TestCoroutineScope
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.feature.session.SessionUseCases
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions.Status.NO_DECISION
|
||||
import mozilla.components.feature.tabs.TabsUseCases
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertSame
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.components.PermissionStorage
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.settings.PhoneFeature
|
||||
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
|
||||
import org.mozilla.fenix.settings.toggle
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
|
@ -53,7 +50,7 @@ class DefaultQuickSettingsControllerTest {
|
|||
private val requestPermissions = mockk<(Array<String>) -> Unit>(relaxed = true)
|
||||
private val displayPermissions = mockk<() -> Unit>(relaxed = true)
|
||||
private val dismiss = mockk<() -> Unit>(relaxed = true)
|
||||
private val controller = DefaultQuickSettingsController(
|
||||
private val controller = spyk(DefaultQuickSettingsController(
|
||||
context = context,
|
||||
quickSettingsStore = store,
|
||||
coroutineScope = coroutinesScope,
|
||||
|
@ -67,7 +64,7 @@ class DefaultQuickSettingsControllerTest {
|
|||
requestRuntimePermissions = requestPermissions,
|
||||
displayPermissions = displayPermissions,
|
||||
dismiss = dismiss
|
||||
)
|
||||
))
|
||||
|
||||
@Test
|
||||
fun `handlePermissionsShown should delegate to an injected parameter`() {
|
||||
|
@ -81,58 +78,42 @@ class DefaultQuickSettingsControllerTest {
|
|||
@Test
|
||||
fun `handlePermissionToggled blocked by Android should handleAndroidPermissionRequest`() {
|
||||
val cameraFeature = PhoneFeature.CAMERA
|
||||
val websitePermission = mockk<WebsitePermission.Camera>()
|
||||
val androidPermissions = slot<Array<String>>()
|
||||
val websitePermission = mockk<WebsitePermission>()
|
||||
every { websitePermission.phoneFeature } returns cameraFeature
|
||||
every { websitePermission.isBlockedByAndroid } returns true
|
||||
|
||||
controller.handlePermissionToggled(websitePermission)
|
||||
|
||||
verify {
|
||||
controller.handleAndroidPermissionRequest(capture(androidPermissions))
|
||||
controller.handleAndroidPermissionRequest(eqArray(cameraFeature.androidPermissionsList))
|
||||
}
|
||||
|
||||
assertTrue(androidPermissions.isCaptured)
|
||||
assertArrayEquals(cameraFeature.androidPermissionsList, androidPermissions.captured)
|
||||
}
|
||||
|
||||
@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`() {
|
||||
val permissionName = "CAMERA"
|
||||
val websitePermission = mockk<WebsitePermission.Camera>()
|
||||
val toggledFeature = slot<PhoneFeature>()
|
||||
val action = slot<WebsitePermissionAction>()
|
||||
val websitePermission = mockk<WebsitePermission>()
|
||||
every { websitePermission.phoneFeature } returns PhoneFeature.CAMERA
|
||||
every { websitePermission.isBlockedByAndroid } returns false
|
||||
every { websitePermission.name } returns permissionName
|
||||
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)
|
||||
|
||||
// We want to verify that the Status is toggled and this event is passed to Controller also.
|
||||
assertSame(NO_DECISION, sitePermissions.camera)
|
||||
verifyOrder {
|
||||
val permission = sitePermissions.toggle(capture(toggledFeature))
|
||||
controller.handlePermissionsChange(permission)
|
||||
verify {
|
||||
controller.handlePermissionsChange(sitePermissions.toggle(PhoneFeature.CAMERA))
|
||||
}
|
||||
// We should also modify View's state. Not necessarily as the last operation.
|
||||
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
|
||||
fun `handlePermissionToggled blocked by user should navigate to site permission manager`() {
|
||||
val websitePermission = mockk<WebsitePermission.Camera>()
|
||||
val websitePermission = mockk<WebsitePermission>()
|
||||
val invalidSitePermissionsController = DefaultQuickSettingsController(
|
||||
context = context,
|
||||
quickSettingsStore = store,
|
||||
|
@ -149,6 +130,7 @@ class DefaultQuickSettingsControllerTest {
|
|||
dismiss = dismiss
|
||||
)
|
||||
|
||||
every { websitePermission.phoneFeature } returns PhoneFeature.CAMERA
|
||||
every { websitePermission.isBlockedByAndroid } returns false
|
||||
every { navController.navigate(any<NavDirections>()) } just Runs
|
||||
|
||||
|
@ -162,88 +144,44 @@ class DefaultQuickSettingsControllerTest {
|
|||
@Test
|
||||
fun `handleAndroidPermissionGranted should update the View's state`() {
|
||||
val featureGranted = PhoneFeature.CAMERA
|
||||
val permission = with(controller) {
|
||||
featureGranted.getCorrespondingPermission()
|
||||
}
|
||||
val permissionStatus = featureGranted.getActionLabel(context, sitePermissions, appSettings)
|
||||
val permissionEnabled =
|
||||
featureGranted.shouldBeEnabled(context, sitePermissions, appSettings)
|
||||
val action = slot<QuickSettingsFragmentAction>()
|
||||
val permissionEnabled = featureGranted.shouldBeEnabled(context, sitePermissions, appSettings)
|
||||
every { store.dispatch(any()) } returns mockk()
|
||||
|
||||
controller.handleAndroidPermissionGranted(featureGranted)
|
||||
|
||||
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
|
||||
fun `handleAndroidPermissionRequest should request from the injected callback`() {
|
||||
val testPermissions = arrayOf("TestPermission")
|
||||
val requiredPermissions = slot<Array<String>>()
|
||||
// every { requestPermissions(capture(requiredPermissions)) } just Runs
|
||||
|
||||
controller.handleAndroidPermissionRequest(testPermissions)
|
||||
|
||||
verify { requestPermissions(capture(requiredPermissions)) }
|
||||
|
||||
assertTrue(requiredPermissions.isCaptured)
|
||||
assertArrayEquals(testPermissions, requiredPermissions.captured)
|
||||
verify { requestPermissions(eqArray(testPermissions)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExperimentalCoroutinesApi
|
||||
@Ignore("Intermittently failing; https://github.com/mozilla-mobile/fenix/issues/8621")
|
||||
fun `handlePermissionsChange should store the updated permission and reload webpage`() =
|
||||
runBlocking {
|
||||
val testPermissions = mockk<SitePermissions>()
|
||||
val permissions = slot<SitePermissions>()
|
||||
val session = slot<Session>()
|
||||
fun `handlePermissionsChange should store the updated permission and reload webpage`() = coroutinesScope.runBlockingTest {
|
||||
val testPermissions = mockk<SitePermissions>()
|
||||
|
||||
controller.handlePermissionsChange(testPermissions)
|
||||
controller.handlePermissionsChange(testPermissions)
|
||||
|
||||
verifyOrder {
|
||||
permissionStorage.updateSitePermissions(capture(permissions))
|
||||
reload(capture(session))
|
||||
}
|
||||
|
||||
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())
|
||||
verifyOrder {
|
||||
permissionStorage.updateSitePermissions(testPermissions)
|
||||
reload(browserSession)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `PhoneFeature#getCorrespondingPermission should return the WebsitePermission which it maps to`() {
|
||||
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)
|
||||
}
|
||||
}
|
||||
private inline fun <reified T> MockKMatcherScope.eqArray(value: Array<T>): Array<T> =
|
||||
match { it contentEquals value }
|
||||
}
|
||||
|
|
|
@ -24,9 +24,6 @@ import org.junit.runner.RunWith
|
|||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
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.ext.shouldBeEnabled
|
||||
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeVisible
|
||||
|
@ -38,12 +35,6 @@ class QuickSettingsFragmentStoreTest {
|
|||
private val context = spyk(testContext)
|
||||
private val permissions = mockk<SitePermissions>()
|
||||
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
|
||||
fun `createStore constructs a QuickSettingsFragmentState`() {
|
||||
|
@ -72,9 +63,7 @@ class QuickSettingsFragmentStoreTest {
|
|||
assertNotNull(state)
|
||||
assertSame(websiteUrl, state.websiteUrl)
|
||||
assertSame(websiteTitle, state.websiteTitle)
|
||||
assertEquals(secureStringRes, state.securityInfoRes)
|
||||
assertEquals(secureDrawableRes, state.iconRes)
|
||||
assertEquals(secureColorRes, state.iconTintRes)
|
||||
assertEquals(WebsiteSecurityUiValues.SECURE, state.websiteSecurityUiValues)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -89,9 +78,7 @@ class QuickSettingsFragmentStoreTest {
|
|||
assertNotNull(state)
|
||||
assertSame(websiteUrl, state.websiteUrl)
|
||||
assertSame(websiteTitle, state.websiteTitle)
|
||||
assertEquals(insecureStringRes, state.securityInfoRes)
|
||||
assertEquals(insecureDrawableRes, state.iconRes)
|
||||
assertEquals(insecureColorRes, state.iconTintRes)
|
||||
assertEquals(WebsiteSecurityUiValues.INSECURE, state.websiteSecurityUiValues)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -118,12 +105,12 @@ class QuickSettingsFragmentStoreTest {
|
|||
// Just need to know that the WebsitePermissionsState properties are initialized.
|
||||
// Making sure they are correctly initialized is tested in the `initWebsitePermission` test.
|
||||
assertNotNull(state)
|
||||
assertNotNull(state.camera)
|
||||
assertNotNull(state.microphone)
|
||||
assertNotNull(state.notification)
|
||||
assertNotNull(state.location)
|
||||
assertNotNull(state.autoplayAudible)
|
||||
assertNotNull(state.autoplayInaudible)
|
||||
assertNotNull(state[PhoneFeature.CAMERA])
|
||||
assertNotNull(state[PhoneFeature.MICROPHONE])
|
||||
assertNotNull(state[PhoneFeature.NOTIFICATION])
|
||||
assertNotNull(state[PhoneFeature.LOCATION])
|
||||
assertNotNull(state[PhoneFeature.AUTOPLAY_AUDIBLE])
|
||||
assertNotNull(state[PhoneFeature.AUTOPLAY_INAUDIBLE])
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -142,7 +129,7 @@ class QuickSettingsFragmentStoreTest {
|
|||
val websitePermission = cameraFeature.toWebsitePermission(context, permissions, appSettings)
|
||||
|
||||
assertNotNull(websitePermission)
|
||||
assertEquals(WebsitePermission.Camera::class, websitePermission::class)
|
||||
assertEquals(cameraFeature, websitePermission.phoneFeature)
|
||||
assertEquals(allowedStatus, websitePermission.status)
|
||||
assertTrue(websitePermission.isVisible)
|
||||
assertTrue(websitePermission.isEnabled)
|
||||
|
@ -154,7 +141,7 @@ class QuickSettingsFragmentStoreTest {
|
|||
val phoneFeature = PhoneFeature.CAMERA
|
||||
every { permissions.camera } returns SitePermissions.Status.NO_DECISION
|
||||
|
||||
val permissionsStatus = phoneFeature.getPermissionStatus(context, permissions, appSettings)
|
||||
val permissionsStatus = phoneFeature.toWebsitePermission(context, permissions, appSettings)
|
||||
|
||||
verify {
|
||||
// Verifying phoneFeature.getActionLabel gets "Status(child of #2#4).ordinal()) was not called"
|
||||
|
@ -174,12 +161,6 @@ class QuickSettingsFragmentStoreTest {
|
|||
@ExperimentalCoroutinesApi
|
||||
fun `TogglePermission should only modify status and visibility of a specific WebsitePermissionsState`() =
|
||||
runBlocking {
|
||||
val cameraPermissionName = "Camera"
|
||||
val microphonePermissionName = "Microphone"
|
||||
val notificationPermissionName = "Notification"
|
||||
val locationPermissionName = "Location"
|
||||
val autoplayAudiblePermissionName = "AutoplayAudible"
|
||||
val autoplayInaudiblePermissionName = "AutoplayInaudible"
|
||||
val initialCameraStatus = "initialCameraStatus"
|
||||
val initialMicStatus = "initialMicStatus"
|
||||
val initialNotificationStatus = "initialNotificationStatus"
|
||||
|
@ -192,31 +173,37 @@ class QuickSettingsFragmentStoreTest {
|
|||
val defaultEnabledStatus = true
|
||||
val defaultBlockedByAndroidStatus = true
|
||||
val websiteInfoState = mockk<WebsiteInfoState>()
|
||||
val initialWebsitePermissionsState = WebsitePermissionsState(
|
||||
val baseWebsitePermission = WebsitePermission(
|
||||
phoneFeature = PhoneFeature.CAMERA,
|
||||
status = "",
|
||||
isVisible = true,
|
||||
camera = WebsitePermission.Camera(
|
||||
initialCameraStatus, defaultVisibilityStatus,
|
||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, cameraPermissionName
|
||||
isEnabled = true,
|
||||
isBlockedByAndroid = true
|
||||
)
|
||||
val initialWebsitePermissionsState = mapOf(
|
||||
PhoneFeature.CAMERA to baseWebsitePermission.copy(
|
||||
phoneFeature = PhoneFeature.CAMERA,
|
||||
status = initialCameraStatus
|
||||
),
|
||||
microphone = WebsitePermission.Microphone(
|
||||
initialMicStatus, defaultVisibilityStatus,
|
||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, microphonePermissionName
|
||||
PhoneFeature.MICROPHONE to baseWebsitePermission.copy(
|
||||
phoneFeature = PhoneFeature.MICROPHONE,
|
||||
status = initialMicStatus
|
||||
),
|
||||
notification = WebsitePermission.Notification(
|
||||
initialNotificationStatus, defaultVisibilityStatus,
|
||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, notificationPermissionName
|
||||
PhoneFeature.NOTIFICATION to baseWebsitePermission.copy(
|
||||
phoneFeature = PhoneFeature.NOTIFICATION,
|
||||
status = initialNotificationStatus
|
||||
),
|
||||
location = WebsitePermission.Location(
|
||||
initialLocationStatus, defaultVisibilityStatus,
|
||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, locationPermissionName
|
||||
PhoneFeature.LOCATION to baseWebsitePermission.copy(
|
||||
phoneFeature = PhoneFeature.LOCATION,
|
||||
status = initialLocationStatus
|
||||
),
|
||||
autoplayAudible = WebsitePermission.AutoplayAudible(
|
||||
initialAutoplayAudibleStatus, defaultVisibilityStatus,
|
||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, autoplayAudiblePermissionName
|
||||
PhoneFeature.AUTOPLAY_AUDIBLE to baseWebsitePermission.copy(
|
||||
phoneFeature = PhoneFeature.AUTOPLAY_AUDIBLE,
|
||||
status = initialAutoplayAudibleStatus
|
||||
),
|
||||
autoplayInaudible = WebsitePermission.AutoplayInaudible(
|
||||
initialAutoplayInaudibleStatus, defaultVisibilityStatus,
|
||||
defaultEnabledStatus, defaultBlockedByAndroidStatus, autoplayInaudiblePermissionName
|
||||
PhoneFeature.AUTOPLAY_INAUDIBLE to baseWebsitePermission.copy(
|
||||
phoneFeature = PhoneFeature.AUTOPLAY_INAUDIBLE,
|
||||
status = initialAutoplayInaudibleStatus
|
||||
)
|
||||
)
|
||||
val initialState = QuickSettingsFragmentState(
|
||||
|
@ -226,7 +213,7 @@ class QuickSettingsFragmentStoreTest {
|
|||
|
||||
store.dispatch(
|
||||
WebsitePermissionAction.TogglePermission(
|
||||
mockk<WebsitePermission.Microphone>(),
|
||||
PhoneFeature.MICROPHONE,
|
||||
updatedMicrophoneStatus,
|
||||
updatedMicrophoneEnabledStatus
|
||||
)
|
||||
|
@ -237,53 +224,35 @@ class QuickSettingsFragmentStoreTest {
|
|||
assertNotSame(initialWebsitePermissionsState, store.state.websitePermissionsState)
|
||||
assertSame(websiteInfoState, store.state.webInfoState)
|
||||
|
||||
assertNotNull(store.state.websitePermissionsState.camera)
|
||||
assertEquals(cameraPermissionName, (store.state.websitePermissionsState.camera as WebsitePermission.Camera).name)
|
||||
assertEquals(initialCameraStatus, store.state.websitePermissionsState.camera.status)
|
||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.camera.isVisible)
|
||||
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.camera.isEnabled)
|
||||
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.camera.isBlockedByAndroid)
|
||||
assertNotNull(store.state.websitePermissionsState[PhoneFeature.CAMERA])
|
||||
assertEquals(PhoneFeature.CAMERA, store.state.websitePermissionsState.getValue(PhoneFeature.CAMERA).phoneFeature)
|
||||
assertEquals(initialCameraStatus, store.state.websitePermissionsState.getValue(PhoneFeature.CAMERA).status)
|
||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.getValue(PhoneFeature.CAMERA).isVisible)
|
||||
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.getValue(PhoneFeature.CAMERA).isEnabled)
|
||||
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.getValue(PhoneFeature.CAMERA).isBlockedByAndroid)
|
||||
|
||||
assertNotNull(store.state.websitePermissionsState.microphone)
|
||||
assertEquals(microphonePermissionName, (store.state.websitePermissionsState.microphone as WebsitePermission.Microphone).name)
|
||||
assertNotNull(store.state.websitePermissionsState[PhoneFeature.MICROPHONE])
|
||||
assertEquals(PhoneFeature.MICROPHONE, store.state.websitePermissionsState.getValue(PhoneFeature.MICROPHONE).phoneFeature)
|
||||
|
||||
// Only the following two properties must have been changed!
|
||||
assertEquals(updatedMicrophoneStatus, store.state.websitePermissionsState.microphone.status)
|
||||
assertEquals(updatedMicrophoneEnabledStatus, store.state.websitePermissionsState.microphone.isEnabled)
|
||||
assertEquals(updatedMicrophoneStatus, store.state.websitePermissionsState.getValue(PhoneFeature.MICROPHONE).status)
|
||||
assertEquals(updatedMicrophoneEnabledStatus, store.state.websitePermissionsState.getValue(PhoneFeature.MICROPHONE).isEnabled)
|
||||
|
||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.microphone.isVisible)
|
||||
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.microphone.isBlockedByAndroid)
|
||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.getValue(PhoneFeature.MICROPHONE).isVisible)
|
||||
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.getValue(PhoneFeature.MICROPHONE).isBlockedByAndroid)
|
||||
|
||||
assertNotNull(store.state.websitePermissionsState.notification)
|
||||
assertEquals(notificationPermissionName, (store.state.websitePermissionsState.notification as WebsitePermission.Notification).name)
|
||||
assertEquals(initialNotificationStatus, store.state.websitePermissionsState.notification.status)
|
||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.notification.isVisible)
|
||||
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.notification.isEnabled)
|
||||
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.notification.isBlockedByAndroid)
|
||||
assertNotNull(store.state.websitePermissionsState[PhoneFeature.NOTIFICATION])
|
||||
assertEquals(PhoneFeature.NOTIFICATION, store.state.websitePermissionsState.getValue(PhoneFeature.NOTIFICATION).phoneFeature)
|
||||
assertEquals(initialNotificationStatus, store.state.websitePermissionsState.getValue(PhoneFeature.NOTIFICATION).status)
|
||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.getValue(PhoneFeature.NOTIFICATION).isVisible)
|
||||
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.getValue(PhoneFeature.NOTIFICATION).isEnabled)
|
||||
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.getValue(PhoneFeature.NOTIFICATION).isBlockedByAndroid)
|
||||
|
||||
assertNotNull(store.state.websitePermissionsState.location)
|
||||
assertEquals(locationPermissionName, (store.state.websitePermissionsState.location as WebsitePermission.Location).name)
|
||||
assertEquals(initialLocationStatus, store.state.websitePermissionsState.location.status)
|
||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.location.isVisible)
|
||||
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.location.isEnabled)
|
||||
assertEquals(defaultBlockedByAndroidStatus, store.state.websitePermissionsState.location.isBlockedByAndroid)
|
||||
assertNotNull(store.state.websitePermissionsState[PhoneFeature.LOCATION])
|
||||
assertEquals(PhoneFeature.LOCATION, store.state.websitePermissionsState.getValue(PhoneFeature.LOCATION).phoneFeature)
|
||||
assertEquals(initialLocationStatus, store.state.websitePermissionsState.getValue(PhoneFeature.LOCATION).status)
|
||||
assertEquals(defaultVisibilityStatus, store.state.websitePermissionsState.getValue(PhoneFeature.LOCATION).isVisible)
|
||||
assertEquals(defaultEnabledStatus, store.state.websitePermissionsState.getValue(PhoneFeature.LOCATION).isEnabled)
|
||||
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