1
0
Fork 0

For #6354 - Removes ETP Experiment, Removes Feature Flags, Sets Strict Default

master
Emily Kager 2019-11-05 16:10:13 -08:00 committed by Emily Kager
parent 1ff5a1934e
commit d9615108ee
21 changed files with 179 additions and 719 deletions

View File

@ -1,53 +0,0 @@
/* 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
import android.content.Context
import mozilla.components.service.experiments.Experiments
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
object ExperimentsManager {
fun optOutEtpExperiment(context: Context) {
// If a user can see the ETP categories we don't want to change their settings
if (FeatureFlags.etpCategories) return
// Release user has opted out of ETP experiment, reset them to current default (strict)
context.settings().setUseStrictTrackingProtection()
context.components.useCases.settingsUseCases.updateTrackingProtection(
context.components.core.createTrackingProtectionPolicy()
)
}
fun initEtpExperiment(context: Context) {
// When the `fenix-etp-5651` experiment is active, set up ETP settings and GV policy.
// Note that this will not take effect the first time the application has launched,
// since there won't be enough time for the experiments library to get a list of experiments.
// It will take effect the second time the application is launched.
Experiments.withExperiment("fenix-etp-5651") { branchName ->
when (branchName) {
"control_strict" -> {
context.settings().setUseStrictTrackingProtection()
context.components.useCases.settingsUseCases.updateTrackingProtection(
context.components.core.createTrackingProtectionPolicy()
)
}
"treatment_standard" -> {
context.settings().setUseStandardTrackingProtection()
context.components.core.createTrackingProtectionPolicy()
context.components.useCases.settingsUseCases.updateTrackingProtection(
context.components.core.createTrackingProtectionPolicy()
)
}
else -> {
// No branch matches so we're defaulting to strict
context.settings().setUseStrictTrackingProtection()
context.components.useCases.settingsUseCases.updateTrackingProtection(
context.components.core.createTrackingProtectionPolicy()
)
}
}
}
}
}

View File

@ -24,11 +24,6 @@ object FeatureFlags {
*/
const val mediaIntegration = true
/**
* Displays the categories blocked by ETP in a panel in the toolbar
*/
val etpCategories = Config.channel.isNightlyOrDebug
/**
* Gives option in Settings to disable auto play media
*/

View File

@ -42,7 +42,6 @@ import java.io.File
open class FenixApplication : Application() {
lateinit var fretboard: Fretboard
lateinit var experimentLoader: Deferred<Boolean>
var experimentLoaderComplete: Boolean = false
open val components by lazy { Components(this) }
@ -87,10 +86,6 @@ open class FenixApplication : Application() {
httpClient = lazy(LazyThreadSafetyMode.NONE) { components.core.client }
)
)
} else {
// We should make a better way to opt out for when we have more experiments
// See https://github.com/mozilla-mobile/fenix/issues/6278
ExperimentsManager.optOutEtpExperiment(this)
}
// When the `fenix-test-2019-08-05` experiment is active, record its branch in Glean
@ -103,8 +98,6 @@ open class FenixApplication : Application() {
ExperimentsMetrics.activeExperiment.set(branchName)
}
ExperimentsManager.initEtpExperiment(this)
setupLeakCanary()
if (settings().isTelemetryEnabled) {
components.analytics.metrics.start()

View File

@ -42,7 +42,6 @@ import mozilla.components.lib.state.ext.consumeFrom
import mozilla.components.support.base.feature.BackHandler
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import org.jetbrains.anko.dimen
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.readermode.DefaultReaderModeController
@ -217,7 +216,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
sessionId = session.id,
url = session.url,
isSecured = session.securityInfo.secure,
isTrackingProtectionOn = session.trackerBlockingEnabled,
sitePermissions = sitePermissions,
gravity = getAppropriateLayoutGravity()
)
@ -360,9 +358,6 @@ class BrowserFragment : BaseBrowserFragment(), BackHandler {
}
private fun showTrackingProtectionOnboarding() {
if (!FeatureFlags.etpCategories) {
return
}
context?.let {
val layout = LayoutInflater.from(it)
.inflate(R.layout.tracking_protection_onboarding_popup, null)

View File

@ -20,7 +20,6 @@ import mozilla.components.feature.toolbar.ToolbarPresenter
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
import mozilla.components.support.base.feature.LifecycleAwareFeature
import mozilla.components.support.ktx.android.view.hideKeyboard
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
@ -62,19 +61,22 @@ class ToolbarIntegration(
val lottieDrawable = LottieDrawable()
lottieDrawable.composition = result
toolbar.display.indicators = if (
context.settings().shouldUseTrackingProtection && FeatureFlags.etpCategories
) {
listOf(
DisplayToolbar.Indicators.TRACKING_PROTECTION,
DisplayToolbar.Indicators.SECURITY,
DisplayToolbar.Indicators.EMPTY)
} else {
listOf(DisplayToolbar.Indicators.SECURITY, DisplayToolbar.Indicators.EMPTY)
}
toolbar.display.indicators =
if (context.settings().shouldUseTrackingProtection) {
listOf(
DisplayToolbar.Indicators.TRACKING_PROTECTION,
DisplayToolbar.Indicators.SECURITY,
DisplayToolbar.Indicators.EMPTY
)
} else {
listOf(
DisplayToolbar.Indicators.SECURITY,
DisplayToolbar.Indicators.EMPTY
)
}
toolbar.display.displayIndicatorSeparator =
context.settings().shouldUseTrackingProtection && FeatureFlags.etpCategories
context.settings().shouldUseTrackingProtection
toolbar.display.icons = toolbar.display.icons.copy(
emptyIcon = AppCompatResources.getDrawable(

View File

@ -18,7 +18,6 @@ import mozilla.components.browser.toolbar.display.DisplayToolbar
import mozilla.components.feature.customtabs.CustomTabsToolbarFeature
import mozilla.components.support.base.feature.BackHandler
import mozilla.components.support.base.feature.LifecycleAwareFeature
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R
import org.mozilla.fenix.components.toolbar.ToolbarMenu
import org.mozilla.fenix.ext.settings
@ -66,7 +65,7 @@ class CustomTabsIntegration(
lottieDrawable.composition = result
toolbar.display.displayIndicatorSeparator = false
if (activity.settings().shouldUseTrackingProtection && FeatureFlags.etpCategories) {
if (activity.settings().shouldUseTrackingProtection) {
toolbar.display.indicators = listOf(
DisplayToolbar.Indicators.SECURITY,
DisplayToolbar.Indicators.TRACKING_PROTECTION

View File

@ -157,7 +157,6 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), BackHandler {
sessionId = session.id,
url = session.url,
isSecured = session.securityInfo.secure,
isTrackingProtectionOn = session.trackerBlockingEnabled,
sitePermissions = sitePermissions,
gravity = getAppropriateLayoutGravity()
)

View File

@ -11,7 +11,6 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
@ -88,9 +87,8 @@ class TrackingProtectionFragment : PreferenceFragmentCompat() {
}
private fun bindStrict() {
val keyStrict = getString(R.string.pref_key_tracking_protection_strict)
val keyStrict = getString(R.string.pref_key_tracking_protection_strict_default)
radioStrict = requireNotNull(findPreference(keyStrict))
radioStrict.isVisible = FeatureFlags.etpCategories
radioStrict.onPreferenceChangeListener = object : SharedPreferenceUpdater() {
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
if (newValue == true) {
@ -114,9 +112,8 @@ class TrackingProtectionFragment : PreferenceFragmentCompat() {
}
private fun bindStandard() {
val keyStandard = getString(R.string.pref_key_tracking_protection_standard)
val keyStandard = getString(R.string.pref_key_tracking_protection_standard_option)
radioStandard = requireNotNull(findPreference(keyStandard))
radioStandard.isVisible = FeatureFlags.etpCategories
radioStandard.onPreferenceChangeListener = object : SharedPreferenceUpdater() {
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
if (newValue == true) {

View File

@ -9,19 +9,13 @@ import androidx.annotation.VisibleForTesting
import androidx.navigation.NavController
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.launch
import mozilla.components.browser.session.Session
import mozilla.components.feature.session.SessionUseCases.ReloadUrlUseCase
import mozilla.components.feature.session.TrackingProtectionUseCases
import mozilla.components.feature.sitepermissions.SitePermissions
import mozilla.components.feature.tabs.TabsUseCases.AddNewTabUseCase
import mozilla.components.support.base.feature.OnNeedToRequestPermissions
import org.mozilla.fenix.browser.BrowserFragment
import org.mozilla.fenix.components.PermissionStorage
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.settings.PhoneFeature
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
import org.mozilla.fenix.settings.toggle
@ -34,29 +28,6 @@ import org.mozilla.fenix.utils.Settings
* complex Android interactions or communication with other features.
*/
interface QuickSettingsController {
/**
* Handles turning on/off tracking protection.
*
* */
fun handleTrackingProtectionToggled(trackingEnabled: Boolean)
/**
* Handles showing the tracking protection settings.
*/
fun handleTrackingProtectionSettingsSelected()
/**
* Handles reporting a webcompat issue for the indicated website.
*
* @param websiteUrl [String] the URL of the web page for which to report a site issue.
*/
fun handleReportTrackingProblem(websiteUrl: String)
/**
* Handles the case of the [TrackingProtectionView] needed to be displayed to the user.
*/
fun handleTrackingProtectionShown()
/**
* Handles the case of the [WebsitePermissionsView] needed to be displayed to the user.
*/
@ -94,10 +65,8 @@ interface QuickSettingsController {
* @param requestRuntimePermissions [OnNeedToRequestPermissions] callback allowing for requesting
* specific Android runtime permissions.
* @param reportSiteIssue callback allowing to report an issue with the current web page.
* @param displayTrackingProtection callback for when the [TrackingProtectionView] needs to be displayed.
* @param displayPermissions callback for when [WebsitePermissionsView] needs to be displayed.
* @param dismiss callback allowing to request this entire Fragment to be dismissed.
* @param trackingProtectionUseCases usecase allowing us to add or remove tracking protection exceptions
*/
@Suppress("TooManyFunctions")
class DefaultQuickSettingsController(
@ -113,55 +82,9 @@ class DefaultQuickSettingsController(
private val addNewTab: AddNewTabUseCase,
private val requestRuntimePermissions: OnNeedToRequestPermissions = { },
private val reportSiteIssue: () -> Unit,
private val displayTrackingProtection: () -> Unit,
private val displayPermissions: () -> Unit,
private val dismiss: () -> Unit,
private val trackingProtectionUseCases: TrackingProtectionUseCases
private val dismiss: () -> Unit
) : QuickSettingsController {
override fun handleTrackingProtectionToggled(
trackingEnabled: Boolean
) {
session?.let {
if (trackingEnabled) {
trackingProtectionUseCases.removeException(it)
} else {
context.metrics.track(Event.TrackingProtectionException)
trackingProtectionUseCases.addException(it)
}
}
reload(session)
quickSettingsStore.dispatch(
TrackingProtectionAction.TrackingProtectionToggled(trackingEnabled)
)
}
override fun handleTrackingProtectionSettingsSelected() {
val directions =
QuickSettingsSheetDialogFragmentDirections
.actionQuickSettingsSheetDialogFragmentToTrackingProtectionFragment()
navController.navigate(directions)
}
@ExperimentalCoroutinesApi
@UseExperimental(ObsoleteCoroutinesApi::class)
override fun handleReportTrackingProblem(websiteUrl: String) {
val reportUrl = String.format(BrowserFragment.REPORT_SITE_ISSUE_URL, websiteUrl)
addNewTab(reportUrl)
if (session?.isCustomTabSession() == true) {
reportSiteIssue()
}
dismiss()
}
override fun handleTrackingProtectionShown() {
displayTrackingProtection()
}
override fun handlePermissionsShown() {
displayPermissions()
}

View File

@ -14,9 +14,9 @@ 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.FeatureFlags
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
@ -68,8 +68,6 @@ class QuickSettingsFragmentStore(
* @param context [Context] used for access to various Android resources.
* @param websiteUrl [String] the URL of the current web page.
* @param isSecured [Boolean] whether the connection is secured (TLS) or not.
* @param isTrackingProtectionOn [Boolean] whether the "Standard" (as in not "Strict")
* tracking protection is enabled for the current website or not.
* @param permissions [SitePermissions]? list of website permissions and their status.
* @param settings [Settings] application settings.
*/
@ -78,40 +76,19 @@ class QuickSettingsFragmentStore(
context: Context,
websiteUrl: String,
isSecured: Boolean,
isTrackingProtectionOn: Boolean,
permissions: SitePermissions?,
settings: Settings
) = QuickSettingsFragmentStore(
QuickSettingsFragmentState(
trackingProtectionState = createTrackingProtectionState(websiteUrl, isTrackingProtectionOn, settings),
webInfoState = createWebsiteInfoState(websiteUrl, isSecured),
websitePermissionsState = createWebsitePermissionState(context, permissions, settings)
websitePermissionsState = createWebsitePermissionState(
context,
permissions,
settings
)
)
)
/**
* Construct an initial [TrackingProtectionState] to be rendered by [TrackingProtectionView]
* based on the current state of the app / website.
*
* Users can modify the returned [TrackingProtectionState] after it is initially displayed.
*
* @param websiteUrl [String] the URL of the current web page.
* @param isTrackingProtectionOn [Boolean] whether the "Standard" (as in not "Strict")
* tracking protection is enabled for the current website or not.
* @param settings [Settings] application settings.
*/
@VisibleForTesting
fun createTrackingProtectionState(
websiteUrl: String,
isTrackingProtectionOn: Boolean,
settings: Settings
) = TrackingProtectionState(
isVisible = FeatureFlags.etpCategories.not(),
isTrackingProtectionEnabledPerApp = settings.shouldUseTrackingProtection,
websiteUrl = websiteUrl,
isTrackingProtectionEnabledPerWebsite = isTrackingProtectionOn
)
/**
* Construct an initial [WebsiteInfoState] to be rendered by [WebsiteInfoView]
* based on the current website's status and connection.
@ -149,14 +126,19 @@ 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 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 shouldBeVisible = cameraPermission.isVisible || microphonePermission.isVisible ||
notificationPermission.isVisible || locationPermission.isVisible
return WebsitePermissionsState(shouldBeVisible, cameraPermission, microphonePermission,
return WebsitePermissionsState(
shouldBeVisible, cameraPermission, microphonePermission,
notificationPermission, locationPermission
)
}
@ -227,28 +209,10 @@ class QuickSettingsFragmentStore(
* Partitioned further to contain mutiple states for each standalone View this Fragment holds.
*/
data class QuickSettingsFragmentState(
val trackingProtectionState: TrackingProtectionState,
val webInfoState: WebsiteInfoState,
val websitePermissionsState: WebsitePermissionsState
) : State
/**
* [State] to be rendered by [TrackingProtectionView] indicating the app is blocking certain tracking
* functionality or not.
*
* @param isVisible [Boolean] whether this contains data that needs to be displayed to the user.
* @param websiteUrl [String] the URL of the current web page.
* @param isTrackingProtectionEnabledPerApp [Boolean] whether tracking protection is on/off globally.
* @param isTrackingProtectionEnabledPerWebsite [Boolean] whether the "Standard" (as in not "Strict")
* tracking protection is enabled for the current website or not.
*/
data class TrackingProtectionState(
val isVisible: Boolean,
val websiteUrl: String,
val isTrackingProtectionEnabledPerApp: Boolean,
val isTrackingProtectionEnabledPerWebsite: Boolean
) : State
/**
* [State] to be rendered by [WebsiteInfoView] indicating whether the connection is secure or not.
*
@ -428,16 +392,6 @@ sealed class WebsitePermission {
*/
sealed class QuickSettingsFragmentAction : Action
/**
* All possible [TrackingProtectionState] changes as result of user / system interactions.
*/
sealed class TrackingProtectionAction : QuickSettingsFragmentAction() {
/**
* Change resulting from toggling the tracking protection status for the current website.
*/
class TrackingProtectionToggled(val trackingEnabled: Boolean) : TrackingProtectionAction()
}
/**
* All possible [WebsiteInfoState] changes as result of user / system interactions.
*/
@ -475,12 +429,6 @@ fun quickSettingsFragmentReducer(
action: QuickSettingsFragmentAction
): QuickSettingsFragmentState {
return when (action) {
is TrackingProtectionAction -> state.copy(
trackingProtectionState = TrackingProtectionStateReducer.reduce(
state.trackingProtectionState,
action
)
)
is WebsiteInfoAction -> state.copy(
webInfoState = WebsiteInfoStateReducer.reduce(
state.webInfoState,
@ -496,22 +444,6 @@ fun quickSettingsFragmentReducer(
}
}
object TrackingProtectionStateReducer {
/**
* Handles creating a new [TrackingProtectionState] based on the specific [TrackingProtectionAction]
*/
fun reduce(
state: TrackingProtectionState,
action: TrackingProtectionAction
): TrackingProtectionState {
return when (action) {
is TrackingProtectionAction.TrackingProtectionToggled -> state.copy(
isTrackingProtectionEnabledPerWebsite = action.trackingEnabled
)
}
}
}
@Suppress("UNUSED_PARAMETER") // the action paramater is unused
object WebsiteInfoStateReducer {
/**

View File

@ -15,24 +15,7 @@ package org.mozilla.fenix.settings.quicksettings
*/
class QuickSettingsInteractor(
private val controller: QuickSettingsController
) : WebsitePermissionInteractor, TrackingProtectionInteractor {
override fun onReportProblemSelected(websiteUrl: String) {
controller.handleReportTrackingProblem(websiteUrl)
}
override fun onProtectionToggled(trackingEnabled: Boolean) {
controller.handleTrackingProtectionToggled(trackingEnabled)
}
override fun onProtectionSettingsSelected() {
controller.handleTrackingProtectionSettingsSelected()
}
override fun onTrackingProtectionShown() {
controller.handleTrackingProtectionShown()
}
) : WebsitePermissionInteractor {
override fun onPermissionsShown() {
controller.handlePermissionsShown()
}

View File

@ -26,7 +26,6 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
import kotlinx.android.synthetic.main.fragment_quick_settings_dialog_sheet.*
import kotlinx.android.synthetic.main.fragment_quick_settings_dialog_sheet.view.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import mozilla.components.feature.session.TrackingProtectionUseCases
import mozilla.components.lib.state.ext.consumeFrom
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.IntentReceiverActivity
@ -47,7 +46,6 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
private lateinit var quickSettingsController: QuickSettingsController
private lateinit var websiteInfoView: WebsiteInfoView
private lateinit var websitePermissionsView: WebsitePermissionsView
private lateinit var websiteTrackingProtectionView: TrackingProtectionView
private lateinit var interactor: QuickSettingsInteractor
private val safeArguments get() = requireNotNull(arguments)
private val promptGravity: Int by lazy {
@ -70,7 +68,6 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
context = context,
websiteUrl = args.url,
isSecured = args.isSecured,
isTrackingProtectionOn = args.isTrackingProtectionOn,
permissions = args.sitePermissions,
settings = Settings.getInstance(context)
)
@ -90,19 +87,12 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
requestPermissions(permissions, REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS)
},
reportSiteIssue = ::launchIntentReceiver,
displayTrackingProtection = ::showTrackingProtectionView,
displayPermissions = ::showPermissionsView,
dismiss = ::dismiss,
trackingProtectionUseCases = TrackingProtectionUseCases(
context.components.core.sessionManager,
context.components.core.engine
)
dismiss = ::dismiss
)
interactor = QuickSettingsInteractor(quickSettingsController)
websiteTrackingProtectionView =
TrackingProtectionView(rootView.trackingProtectionLayout, interactor)
websiteInfoView = WebsiteInfoView(rootView.websiteInfoLayout)
websitePermissionsView =
WebsitePermissionsView(rootView.websitePermissionsLayout, interactor)
@ -143,7 +133,6 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
consumeFrom(quickSettingsStore) {
websiteInfoView.update(it.webInfoState)
websiteTrackingProtectionView.update(it.trackingProtectionState)
websitePermissionsView.update(it.websitePermissionsState)
}
}
@ -181,10 +170,6 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
private fun arePermissionsGranted(requestCode: Int, grantResults: IntArray) =
requestCode == REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS && grantResults.all { it == PERMISSION_GRANTED }
private fun showTrackingProtectionView() {
trackingProtectionGroup.isVisible = true
}
private fun showPermissionsView() {
websitePermissionsGroup.isVisible = true
}

View File

@ -1,91 +0,0 @@
/* 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 android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.isVisible
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.quicksettings_tracking_protection.*
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds
import org.mozilla.fenix.R
/**
* Contract declaring all possible user interactions with [TrackingProtectionView]
*/
interface TrackingProtectionInteractor {
/**
* Indicates the user wants to report a problem with the current website.
*/
fun onReportProblemSelected(websiteUrl: String)
/**
* Indicates the user want to toggle the tracking protection on / off.
*/
fun onProtectionToggled(trackingEnabled: Boolean)
/**
* Indicates the user want to see all tracking protection settings.
*/
fun onProtectionSettingsSelected()
/**
* Indicates the tracking protection status for the current website is shown to the user.
*/
fun onTrackingProtectionShown()
}
/**
* MVI View that knows to display a "normal" (as in not "enhanced") tracking protection panel
* containing the tracking protection status and also allowing on / off toggling.
*
* @param containerView [ViewGroup] in which this View will inflate itself.
* @param interactor [TrackingProtectionInteractor] which will have delegated to all user interactions.
*/
class TrackingProtectionView(
override val containerView: ViewGroup,
val interactor: TrackingProtectionInteractor
) : LayoutContainer {
val view: View = LayoutInflater.from(containerView.context)
.inflate(R.layout.quicksettings_tracking_protection, containerView, true)
init {
trackingProtectionSwitch.putCompoundDrawablesRelativeWithIntrinsicBounds(
start = AppCompatResources.getDrawable(
containerView.context,
R.drawable.ic_tracking_protection
)
)
}
/**
* Allows changing what this View displays.
*
* @param state [TrackingProtectionState] to be rendered.
*/
fun update(state: TrackingProtectionState) {
if (state.isVisible) {
interactor.onTrackingProtectionShown()
}
reportSiteIssueAction.setOnClickListener { interactor.onReportProblemSelected(state.websiteUrl) }
trackingProtectionAction.isVisible = !state.isTrackingProtectionEnabledPerApp
if (!state.isTrackingProtectionEnabledPerApp) {
trackingProtectionAction.setOnClickListener { interactor.onProtectionSettingsSelected() }
}
trackingProtectionSwitch.isChecked = state.isTrackingProtectionEnabledPerWebsite
trackingProtectionSwitch.isEnabled = state.isTrackingProtectionEnabledPerApp
if (state.isTrackingProtectionEnabledPerApp) {
trackingProtectionSwitch.setOnCheckedChangeListener { _, isChecked ->
interactor.onProtectionToggled(isChecked)
}
}
}
}

View File

@ -197,36 +197,10 @@ class Settings private constructor(
)
val useStrictTrackingProtection by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_strict),
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_strict_default),
true
)
fun setUseStrictTrackingProtection() {
preferences.edit()
.putBoolean(
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_standard),
false
)
.putBoolean(
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_strict),
true
)
.apply()
}
fun setUseStandardTrackingProtection() {
preferences.edit()
.putBoolean(
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_standard),
true
)
.putBoolean(
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_strict),
false
)
.apply()
}
var shouldDeleteBrowsingDataOnQuit by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_delete_browsing_data_on_quit),
default = false

View File

@ -22,12 +22,6 @@
android:id="@+id/websiteInfoLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/trackingProtectionDivider" />
<FrameLayout
android:id="@+id/trackingProtectionLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/webSitePermissionsDivider" />
<FrameLayout
@ -45,23 +39,6 @@
android:background="?neutralFaded"
app:layout_constraintBottom_toTopOf="@id/websitePermissionsLayout" />
<View
android:id="@+id/trackingProtectionDivider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="?neutralFaded"
app:layout_constraintBottom_toTopOf="@id/trackingProtectionLayout" />
<androidx.constraintlayout.widget.Group
android:id="@+id/trackingProtectionGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="trackingProtectionLayout,trackingProtectionDivider"
tools:visibility="visible" />
<androidx.constraintlayout.widget.Group
android:id="@+id/websitePermissionsGroup"
android:layout_width="wrap_content"

View File

@ -564,8 +564,7 @@
</dialog>
<dialog
android:id="@+id/quickSettingsSheetDialogFragment"
android:name="org.mozilla.fenix.settings.quicksettings.QuickSettingsSheetDialogFragment"
android:label="QuickSettingsSheetDialogFragment">
android:name="org.mozilla.fenix.settings.quicksettings.QuickSettingsSheetDialogFragment">
<argument
android:name="sessionId"
app:argType="string" />
@ -575,9 +574,6 @@
<argument
android:name="isSecured"
app:argType="boolean" />
<argument
android:name="isTrackingProtectionOn"
app:argType="boolean" />
<argument
android:name="sitePermissions"
app:argType="mozilla.components.feature.sitepermissions.SitePermissions"
@ -586,11 +582,6 @@
android:name="gravity"
android:defaultValue="80"
app:argType="integer" />
<action
android:id="@+id/action_quickSettingsSheetDialogFragment_to_trackingProtectionFragment"
app:destination="@id/trackingProtectionFragment"
app:popUpTo="@id/quickSettingsSheetDialogFragment"
app:popUpToInclusive="true" />
</dialog>
<fragment
android:id="@+id/accountProblemFragment"

View File

@ -97,8 +97,8 @@
<string name="pref_key_tracking_protection_settings" translatable="false">pref_key_tracking_protection_settings</string>
<string name="pref_key_tracking_protection" translatable="false">pref_key_tracking_protection</string>
<string name="pref_key_tracking_protection_exceptions" translatable="false">pref_key_tracking_protection_exceptions</string>
<string name="pref_key_tracking_protection_standard" translatable="false">pref_key_tracking_protection_standard</string>
<string name="pref_key_tracking_protection_strict" translatable="false">pref_key_tracking_protection_strict</string>
<string name="pref_key_tracking_protection_standard_option" translatable="false">pref_key_tracking_protection_standard_option</string>
<string name="pref_key_tracking_protection_strict_default" translatable="false">pref_key_tracking_protection_strict_default</string>
<string name="pref_key_tracking_protection_onboarding" translatable="false">pref_key_tracking_protection_onboarding</string>
<!-- Logins Settings -->

View File

@ -18,17 +18,15 @@
<org.mozilla.fenix.settings.RadioButtonInfoPreference
android:defaultValue="false"
android:dependency="@string/pref_key_tracking_protection"
android:key="@string/pref_key_tracking_protection_standard"
android:key="@string/pref_key_tracking_protection_standard_option"
android:summary="@string/preference_enhanced_tracking_protection_standard_description_2"
android:title="@string/preference_enhanced_tracking_protection_standard_option"
app:isPreferenceVisible="false" />
android:title="@string/preference_enhanced_tracking_protection_standard_option" />
<org.mozilla.fenix.settings.RadioButtonInfoPreference
android:defaultValue="true"
android:dependency="@string/pref_key_tracking_protection"
android:key="@string/pref_key_tracking_protection_strict"
android:key="@string/pref_key_tracking_protection_strict_default"
android:summary="@string/preference_enhanced_tracking_protection_strict_default_description"
android:title="@string/preference_enhanced_tracking_protection_strict_default"
app:isPreferenceVisible="false" />
android:title="@string/preference_enhanced_tracking_protection_strict_default" />
<Preference
android:icon="@drawable/ic_internet"
android:key="@string/pref_key_tracking_protection_exceptions"

View File

@ -24,7 +24,6 @@ import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.runBlocking
import mozilla.components.browser.session.Session
import mozilla.components.feature.session.SessionUseCases
import mozilla.components.feature.session.TrackingProtectionUseCases
import mozilla.components.feature.sitepermissions.SitePermissions
import mozilla.components.feature.sitepermissions.SitePermissions.Status.NO_DECISION
import mozilla.components.feature.tabs.TabsUseCases
@ -32,10 +31,7 @@ import mozilla.components.support.test.robolectric.testContext
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.TestApplication
import org.mozilla.fenix.browser.BrowserFragment
import org.mozilla.fenix.components.PermissionStorage
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.settings.PhoneFeature
import org.mozilla.fenix.settings.quicksettings.ext.shouldBeEnabled
import org.mozilla.fenix.settings.toggle
@ -59,10 +55,8 @@ class DefaultQuickSettingsControllerTest {
private val addNewTab = mockk<TabsUseCases.AddNewTabUseCase>(relaxed = true)
private val requestPermissions = mockk<(Array<String>) -> Unit>(relaxed = true)
private val reportIssue = mockk<() -> Unit>(relaxed = true)
private val displayTrackingProtection = mockk<() -> Unit>(relaxed = true)
private val displayPermissions = mockk<() -> Unit>(relaxed = true)
private val dismiss = mockk<() -> Unit>(relaxed = true)
private val trackingProtectionUseCases = mockk<TrackingProtectionUseCases>(relaxed = true)
private val controller = DefaultQuickSettingsController(
context = context,
quickSettingsStore = store,
@ -76,99 +70,10 @@ class DefaultQuickSettingsControllerTest {
addNewTab = addNewTab,
requestRuntimePermissions = requestPermissions,
reportSiteIssue = reportIssue,
displayTrackingProtection = displayTrackingProtection,
displayPermissions = displayPermissions,
dismiss = dismiss,
trackingProtectionUseCases = trackingProtectionUseCases
dismiss = dismiss
)
@Test
fun `handleTrackingProtectionToggled should toggle tracking and reload website`() {
val session = slot<Session>()
every { store.dispatch(any()) } returns mockk()
controller.handleTrackingProtectionToggled(false)
verifyOrder {
trackingProtectionUseCases.addException(capture(session))
context.metrics.track(Event.TrackingProtectionException)
reload(capture(session))
}
assertAll {
assertThat(session.isCaptured).isTrue()
assertThat(session.captured).isEqualTo(browserSession)
}
}
@Test
fun `handleTrackingProtectionSettingsSelected should navigate to TrackingProtectionFragment`() {
controller.handleTrackingProtectionSettingsSelected()
verify {
navController.navigate(
QuickSettingsSheetDialogFragmentDirections
.actionQuickSettingsSheetDialogFragmentToTrackingProtectionFragment()
)
}
}
@Test
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
fun `handleReportTrackingProblem should open a report issue webpage and dismiss when in normal mode`() {
val websiteWithIssuesUrl = "https://host.com/page1"
val testReportUrl =
String.format(BrowserFragment.REPORT_SITE_ISSUE_URL, websiteWithIssuesUrl)
val reportUrl = slot<String>()
// `handleReportTrackingProblem` will behave differently depending on `isCustomTabSession`
every { browserSession.isCustomTabSession() } returns false
controller.handleReportTrackingProblem(websiteWithIssuesUrl)
verify {
addNewTab(capture(reportUrl))
dismiss()
}
assertAll {
assertThat(reportUrl.isCaptured).isTrue()
assertThat(reportUrl.captured).isEqualTo(testReportUrl)
}
}
@Test
@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
fun `handleReportTrackingProblem should open a report issue in browser from custom tab and dismiss`() {
val websiteWithIssuesUrl = "https://host.com/page1"
val testReportUrl =
String.format(BrowserFragment.REPORT_SITE_ISSUE_URL, websiteWithIssuesUrl)
val reportUrl = slot<String>()
// `handleReportTrackingProblem` will behave differently depending on `isCustomTabSession`
every { browserSession.isCustomTabSession() } returns true
controller.handleReportTrackingProblem(websiteWithIssuesUrl)
verify {
addNewTab(capture(reportUrl))
reportIssue()
dismiss()
}
assertAll {
assertThat(reportUrl.isCaptured).isTrue()
assertThat(reportUrl.captured).isEqualTo(testReportUrl)
}
}
@Test
fun `handleTrackingProtectionShown should delegate to an injected parameter`() {
controller.handleTrackingProtectionShown()
verify {
displayTrackingProtection()
}
}
@Test
fun `handlePermissionsShown should delegate to an injected parameter`() {
controller.handlePermissionsShown()

View File

@ -10,7 +10,6 @@ import assertk.assertThat
import assertk.assertions.isEqualTo
import assertk.assertions.isFalse
import assertk.assertions.isInstanceOf
import assertk.assertions.isNotEqualTo
import assertk.assertions.isNotNull
import assertk.assertions.isNotSameAs
import assertk.assertions.isSameAs
@ -56,17 +55,15 @@ class QuickSettingsFragmentStoreTest {
fun `createStore constructs a QuickSettingsFragmentState`() {
val settings = mockk<Settings>(relaxed = true)
val permissions = mockk<SitePermissions>(relaxed = true)
every { settings.shouldUseTrackingProtection } returns true
val store = QuickSettingsFragmentStore.createStore(
context, "url", true, true, permissions, settings
context, "url", true, permissions, settings
)
assertAll {
assertThat(store).isNotNull()
assertThat(store.state).isNotNull()
assertThat(store.state.webInfoState).isNotNull()
assertThat(store.state.trackingProtectionState).isNotNull()
assertThat(store.state.websitePermissionsState).isNotNull()
}
}
@ -103,29 +100,15 @@ class QuickSettingsFragmentStoreTest {
}
}
@Test
fun `createTrackingProtectionState helps in constructing an initial TrackingProtectionState for it's Store`() {
val websiteUrl = "https://host.com/pageThatShouldUseTrackingProtection"
val trackingPerWebsiteStatus = true
val trackingPerAppStatus = true
every { appSettings.shouldUseTrackingProtection } returns trackingPerAppStatus
val state = QuickSettingsFragmentStore.createTrackingProtectionState(
websiteUrl, trackingPerWebsiteStatus, appSettings
)
assertAll {
assertThat(state).isNotNull()
assertThat(state).isNotNull()
assertThat(state.websiteUrl).isSameAs(websiteUrl)
assertThat(state.isTrackingProtectionEnabledPerWebsite).isSameAs(trackingPerWebsiteStatus)
assertThat(state.isTrackingProtectionEnabledPerApp).isEqualTo(trackingPerAppStatus)
}
}
@Test
fun `createWebsitePermissionState helps in constructing an initial WebsitePermissionState for it's Store`() {
every { context.checkPermission(any(), any(), any()) }.returns(PackageManager.PERMISSION_GRANTED)
every {
context.checkPermission(
any(),
any(),
any()
)
}.returns(PackageManager.PERMISSION_GRANTED)
every { permissions.camera } returns SitePermissions.Status.ALLOWED
every { permissions.microphone } returns SitePermissions.Status.NO_DECISION
every { permissions.notification } returns SitePermissions.Status.BLOCKED
@ -150,7 +133,13 @@ class QuickSettingsFragmentStoreTest {
fun `PhoneFeature#toWebsitePermission helps in constructing the right WebsitePermission`() {
val cameraFeature = PhoneFeature.CAMERA
val allowedStatus = testContext.getString(R.string.preference_option_phone_feature_allowed)
every { context.checkPermission(any(), any(), any()) }.returns(PackageManager.PERMISSION_GRANTED)
every {
context.checkPermission(
any(),
any(),
any()
)
}.returns(PackageManager.PERMISSION_GRANTED)
every { permissions.camera } returns SitePermissions.Status.ALLOWED
val websitePermission = cameraFeature.toWebsitePermission(context, permissions, appSettings)
@ -187,117 +176,135 @@ class QuickSettingsFragmentStoreTest {
}
}
@ExperimentalCoroutinesApi
@Test
fun `TrackingProtectionToggled should update only the tracking enabled status`() = runBlocking {
val initialUrl = "https://host.com/page1"
val initialTrackingPerApp = true
val initialTrackingPerWebsite = true
val updatedTrackingPerWebsite = false
val appSettings = mockk<Settings>()
every { appSettings.shouldUseTrackingProtection } returns initialTrackingPerApp
val initialTrackingProtectionState = QuickSettingsFragmentStore.createTrackingProtectionState(
initialUrl, initialTrackingPerWebsite, appSettings
)
val initialWebsiteInfoState = mockk<WebsiteInfoState>()
val initialWebsitePermissionsState = mockk<WebsitePermissionsState>()
val store = QuickSettingsFragmentStore(QuickSettingsFragmentState(
initialTrackingProtectionState, initialWebsiteInfoState, initialWebsitePermissionsState
))
store.dispatch(TrackingProtectionAction.TrackingProtectionToggled(updatedTrackingPerWebsite)).join()
assertAll {
assertThat(store.state.webInfoState).isSameAs(initialWebsiteInfoState)
assertThat(store.state.websitePermissionsState).isSameAs(initialWebsitePermissionsState)
assertThat(store.state.trackingProtectionState).isNotSameAs(initialTrackingProtectionState)
assertThat(store.state.trackingProtectionState.isTrackingProtectionEnabledPerWebsite)
.isNotEqualTo(initialTrackingPerWebsite)
assertThat(store.state.trackingProtectionState.isTrackingProtectionEnabledPerWebsite)
.isEqualTo(updatedTrackingPerWebsite)
assertThat(store.state.trackingProtectionState.isTrackingProtectionEnabledPerApp)
.isSameAs(initialTrackingPerApp)
assertThat(store.state.trackingProtectionState.websiteUrl).isSameAs(initialUrl)
}
}
@Test
@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 initialCameraStatus = "initialCameraStatus"
val initialMicStatus = "initialMicStatus"
val initialNotificationStatus = "initialNotificationStatus"
val initialLocationStatus = "initialLocationStatus"
val updatedMicrophoneStatus = "updatedNotificationStatus"
val updatedMicrophoneEnabledStatus = false
val defaultVisibilityStatus = true
val defaultEnabledStatus = true
val defaultBlockedByAndroidStatus = true
val websiteInfoState = mockk<WebsiteInfoState>()
val trackingProtectionState = mockk<TrackingProtectionState>()
val initialWebsitePermissionsState = WebsitePermissionsState(
isVisible = true,
camera = WebsitePermission.Camera(initialCameraStatus, defaultVisibilityStatus,
defaultEnabledStatus, defaultBlockedByAndroidStatus, cameraPermissionName),
microphone = WebsitePermission.Microphone(initialMicStatus, defaultVisibilityStatus,
defaultEnabledStatus, defaultBlockedByAndroidStatus, microphonePermissionName),
notification = WebsitePermission.Notification(initialNotificationStatus, defaultVisibilityStatus,
defaultEnabledStatus, defaultBlockedByAndroidStatus, notificationPermissionName),
location = WebsitePermission.Location(initialLocationStatus, defaultVisibilityStatus,
defaultEnabledStatus, defaultBlockedByAndroidStatus, locationPermissionName)
)
val initialState = QuickSettingsFragmentState(
trackingProtectionState, websiteInfoState, initialWebsitePermissionsState
)
val store = QuickSettingsFragmentStore(initialState)
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 initialCameraStatus = "initialCameraStatus"
val initialMicStatus = "initialMicStatus"
val initialNotificationStatus = "initialNotificationStatus"
val initialLocationStatus = "initialLocationStatus"
val updatedMicrophoneStatus = "updatedNotificationStatus"
val updatedMicrophoneEnabledStatus = false
val defaultVisibilityStatus = true
val defaultEnabledStatus = true
val defaultBlockedByAndroidStatus = true
val websiteInfoState = mockk<WebsiteInfoState>()
val initialWebsitePermissionsState = WebsitePermissionsState(
isVisible = true,
camera = WebsitePermission.Camera(
initialCameraStatus, defaultVisibilityStatus,
defaultEnabledStatus, defaultBlockedByAndroidStatus, cameraPermissionName
),
microphone = WebsitePermission.Microphone(
initialMicStatus, defaultVisibilityStatus,
defaultEnabledStatus, defaultBlockedByAndroidStatus, microphonePermissionName
),
notification = WebsitePermission.Notification(
initialNotificationStatus, defaultVisibilityStatus,
defaultEnabledStatus, defaultBlockedByAndroidStatus, notificationPermissionName
),
location = WebsitePermission.Location(
initialLocationStatus, defaultVisibilityStatus,
defaultEnabledStatus, defaultBlockedByAndroidStatus, locationPermissionName
)
)
val initialState = QuickSettingsFragmentState(
websiteInfoState, initialWebsitePermissionsState
)
val store = QuickSettingsFragmentStore(initialState)
store.dispatch(WebsitePermissionAction.TogglePermission(
mockk<WebsitePermission.Microphone>(), updatedMicrophoneStatus, updatedMicrophoneEnabledStatus)
).join()
store.dispatch(
WebsitePermissionAction.TogglePermission(
mockk<WebsitePermission.Microphone>(),
updatedMicrophoneStatus,
updatedMicrophoneEnabledStatus
)
).join()
assertAll {
assertThat(store.state).isNotNull()
assertThat(store.state).isNotSameAs(initialState)
assertThat(store.state.websitePermissionsState).isNotSameAs(initialWebsitePermissionsState)
assertThat(store.state.webInfoState).isSameAs(websiteInfoState)
assertThat(store.state.trackingProtectionState).isSameAs(trackingProtectionState)
assertAll {
assertThat(store.state).isNotNull()
assertThat(store.state).isNotSameAs(initialState)
assertThat(store.state.websitePermissionsState).isNotSameAs(
initialWebsitePermissionsState
)
assertThat(store.state.webInfoState).isSameAs(websiteInfoState)
assertThat(store.state.websitePermissionsState.camera).isNotNull()
assertThat((store.state.websitePermissionsState.camera as WebsitePermission.Camera).name).isEqualTo(cameraPermissionName)
assertThat(store.state.websitePermissionsState.camera.status).isEqualTo(initialCameraStatus)
assertThat(store.state.websitePermissionsState.camera.isVisible).isEqualTo(defaultVisibilityStatus)
assertThat(store.state.websitePermissionsState.camera.isEnabled).isEqualTo(defaultEnabledStatus)
assertThat(store.state.websitePermissionsState.camera.isBlockedByAndroid).isEqualTo(defaultBlockedByAndroidStatus)
assertThat(store.state.websitePermissionsState.camera).isNotNull()
assertThat((store.state.websitePermissionsState.camera as WebsitePermission.Camera).name).isEqualTo(
cameraPermissionName
)
assertThat(store.state.websitePermissionsState.camera.status).isEqualTo(
initialCameraStatus
)
assertThat(store.state.websitePermissionsState.camera.isVisible).isEqualTo(
defaultVisibilityStatus
)
assertThat(store.state.websitePermissionsState.camera.isEnabled).isEqualTo(
defaultEnabledStatus
)
assertThat(store.state.websitePermissionsState.camera.isBlockedByAndroid).isEqualTo(
defaultBlockedByAndroidStatus
)
assertThat(store.state.websitePermissionsState.microphone).isNotNull()
assertThat((store.state.websitePermissionsState.microphone as WebsitePermission.Microphone).name).isEqualTo(microphonePermissionName)
// Only the following two properties must have been changed!
assertThat(store.state.websitePermissionsState.microphone.status).isEqualTo(updatedMicrophoneStatus)
assertThat(store.state.websitePermissionsState.microphone.isEnabled).isEqualTo(updatedMicrophoneEnabledStatus)
assertThat(store.state.websitePermissionsState.microphone).isNotNull()
assertThat((store.state.websitePermissionsState.microphone as WebsitePermission.Microphone).name).isEqualTo(
microphonePermissionName
)
// Only the following two properties must have been changed!
assertThat(store.state.websitePermissionsState.microphone.status).isEqualTo(
updatedMicrophoneStatus
)
assertThat(store.state.websitePermissionsState.microphone.isEnabled).isEqualTo(
updatedMicrophoneEnabledStatus
)
assertThat(store.state.websitePermissionsState.microphone.isVisible).isEqualTo(defaultVisibilityStatus)
assertThat(store.state.websitePermissionsState.microphone.isBlockedByAndroid).isEqualTo(defaultBlockedByAndroidStatus)
assertThat(store.state.websitePermissionsState.microphone.isVisible).isEqualTo(
defaultVisibilityStatus
)
assertThat(store.state.websitePermissionsState.microphone.isBlockedByAndroid).isEqualTo(
defaultBlockedByAndroidStatus
)
assertThat(store.state.websitePermissionsState.notification).isNotNull()
assertThat((store.state.websitePermissionsState.notification as WebsitePermission.Notification).name).isEqualTo(notificationPermissionName)
assertThat(store.state.websitePermissionsState.notification.status).isEqualTo(initialNotificationStatus)
assertThat(store.state.websitePermissionsState.notification.isVisible).isEqualTo(defaultVisibilityStatus)
assertThat(store.state.websitePermissionsState.notification.isEnabled).isEqualTo(defaultEnabledStatus)
assertThat(store.state.websitePermissionsState.notification.isBlockedByAndroid).isEqualTo(defaultBlockedByAndroidStatus)
assertThat(store.state.websitePermissionsState.notification).isNotNull()
assertThat((store.state.websitePermissionsState.notification as WebsitePermission.Notification).name).isEqualTo(
notificationPermissionName
)
assertThat(store.state.websitePermissionsState.notification.status).isEqualTo(
initialNotificationStatus
)
assertThat(store.state.websitePermissionsState.notification.isVisible).isEqualTo(
defaultVisibilityStatus
)
assertThat(store.state.websitePermissionsState.notification.isEnabled).isEqualTo(
defaultEnabledStatus
)
assertThat(store.state.websitePermissionsState.notification.isBlockedByAndroid).isEqualTo(
defaultBlockedByAndroidStatus
)
assertThat(store.state.websitePermissionsState.location).isNotNull()
assertThat((store.state.websitePermissionsState.location as WebsitePermission.Location).name).isEqualTo(locationPermissionName)
assertThat(store.state.websitePermissionsState.location.status).isEqualTo(initialLocationStatus)
assertThat(store.state.websitePermissionsState.location.isVisible).isEqualTo(defaultVisibilityStatus)
assertThat(store.state.websitePermissionsState.location.isEnabled).isEqualTo(defaultEnabledStatus)
assertThat(store.state.websitePermissionsState.location.isBlockedByAndroid).isEqualTo(defaultBlockedByAndroidStatus)
assertThat(store.state.websitePermissionsState.location).isNotNull()
assertThat((store.state.websitePermissionsState.location as WebsitePermission.Location).name).isEqualTo(
locationPermissionName
)
assertThat(store.state.websitePermissionsState.location.status).isEqualTo(
initialLocationStatus
)
assertThat(store.state.websitePermissionsState.location.isVisible).isEqualTo(
defaultVisibilityStatus
)
assertThat(store.state.websitePermissionsState.location.isEnabled).isEqualTo(
defaultEnabledStatus
)
assertThat(store.state.websitePermissionsState.location.isBlockedByAndroid).isEqualTo(
defaultBlockedByAndroidStatus
)
}
}
}
@Test
fun `getSecuredWebsiteUiValues() should return the right values`() {

View File

@ -11,63 +11,12 @@ import assertk.assertions.isTrue
import io.mockk.mockk
import io.mockk.slot
import io.mockk.verify
import io.mockk.verifyAll
import org.junit.Test
class QuickSettingsInteractorTest {
private val controller = mockk<QuickSettingsController>(relaxed = true)
private val interactor = QuickSettingsInteractor(controller)
@Test
fun `onReportProblemSelected should delegate the controller`() {
val websiteUrl = "https://host.com/page1"
val url = slot<String>()
interactor.onReportProblemSelected(websiteUrl)
verify {
controller.handleReportTrackingProblem(capture(url))
}
assertAll {
assertThat(url.isCaptured).isTrue()
assertThat(url.captured).isEqualTo(websiteUrl)
}
}
@Test
fun `onProtectionToggled should delegate the controller`() {
val trackingEnabled = true
val trackingStatus = slot<Boolean>()
interactor.onProtectionToggled(trackingEnabled)
verifyAll {
controller.handleTrackingProtectionToggled(capture(trackingStatus))
}
assertAll {
assertThat(trackingStatus.isCaptured).isTrue()
assertThat(trackingStatus.captured).isEqualTo(trackingEnabled)
}
}
@Test
fun `onProtectionSettingsSelected should delegate the controller`() {
interactor.onProtectionSettingsSelected()
verify {
controller.handleTrackingProtectionSettingsSelected()
}
}
@Test
fun `onTrackingProtectionShown should delegate the controller`() {
interactor.onTrackingProtectionShown()
verify {
controller.handleTrackingProtectionShown()
}
}
@Test
fun `onPermissionsShown should delegate the controller`() {
interactor.onPermissionsShown()