Tests and cleanup for tracking protection
parent
9ef4d9bdae
commit
50441e28f1
|
@ -17,10 +17,11 @@ import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.getPreferenceKey
|
import org.mozilla.fenix.ext.getPreferenceKey
|
||||||
import org.mozilla.fenix.ext.metrics
|
|
||||||
import org.mozilla.fenix.ext.nav
|
import org.mozilla.fenix.ext.nav
|
||||||
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.ext.showToolbar
|
import org.mozilla.fenix.ext.showToolbar
|
||||||
|
import org.mozilla.fenix.trackingprotection.TrackingProtectionMode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the toggle for tracking protection, options for tracking protection policy and a button
|
* Displays the toggle for tracking protection, options for tracking protection policy and a button
|
||||||
|
@ -34,9 +35,6 @@ class TrackingProtectionFragment : PreferenceFragmentCompat() {
|
||||||
requireView().findNavController().navigate(directions)
|
requireView().findNavController().navigate(directions)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
private lateinit var radioStrict: RadioButtonInfoPreference
|
|
||||||
private lateinit var radioStandard: RadioButtonInfoPreference
|
|
||||||
private lateinit var radioCustom: RadioButtonInfoPreference
|
|
||||||
private lateinit var customCookies: CheckBoxPreference
|
private lateinit var customCookies: CheckBoxPreference
|
||||||
private lateinit var customCookiesSelect: DropDownPreference
|
private lateinit var customCookiesSelect: DropDownPreference
|
||||||
private lateinit var customTracking: CheckBoxPreference
|
private lateinit var customTracking: CheckBoxPreference
|
||||||
|
@ -46,10 +44,10 @@ class TrackingProtectionFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.tracking_protection_preferences, rootKey)
|
setPreferencesFromResource(R.xml.tracking_protection_preferences, rootKey)
|
||||||
bindStrict()
|
val radioStrict = bindTrackingProtectionRadio(TrackingProtectionMode.STRICT)
|
||||||
bindStandard()
|
val radioStandard = bindTrackingProtectionRadio(TrackingProtectionMode.STANDARD)
|
||||||
bindCustom()
|
val radioCustom = bindCustom()
|
||||||
setupRadioGroups()
|
setupRadioGroups(radioStrict, radioStandard, radioCustom)
|
||||||
updateCustomOptionsVisibility()
|
updateCustomOptionsVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,79 +94,42 @@ class TrackingProtectionFragment : PreferenceFragmentCompat() {
|
||||||
preferenceExceptions?.onPreferenceClickListener = exceptionsClickListener
|
preferenceExceptions?.onPreferenceClickListener = exceptionsClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindStrict() {
|
private fun bindTrackingProtectionRadio(
|
||||||
val keyStrict = getString(R.string.pref_key_tracking_protection_strict_default)
|
mode: TrackingProtectionMode
|
||||||
radioStrict = requireNotNull(findPreference(keyStrict))
|
): RadioButtonInfoPreference {
|
||||||
radioStrict.contentDescription =
|
val radio = requireNotNull(findPreference<RadioButtonInfoPreference>(
|
||||||
getString(R.string.preference_enhanced_tracking_protection_strict_info_button)
|
getPreferenceKey(mode.preferenceKey)
|
||||||
|
))
|
||||||
|
radio.contentDescription = getString(mode.contentDescriptionRes)
|
||||||
|
|
||||||
radioStrict.onClickListener {
|
val metrics = requireComponents.analytics.metrics
|
||||||
|
radio.onClickListener {
|
||||||
updateCustomOptionsVisibility()
|
updateCustomOptionsVisibility()
|
||||||
updateTrackingProtectionPolicy()
|
updateTrackingProtectionPolicy()
|
||||||
context?.metrics?.track(
|
when (mode) {
|
||||||
Event.TrackingProtectionSettingChanged(
|
TrackingProtectionMode.STANDARD ->
|
||||||
Event.TrackingProtectionSettingChanged.Setting.STRICT
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
radioStrict.onInfoClickListener {
|
|
||||||
nav(
|
|
||||||
R.id.trackingProtectionFragment,
|
|
||||||
TrackingProtectionFragmentDirections
|
|
||||||
.actionTrackingProtectionFragmentToTrackingProtectionBlockingFragment(
|
|
||||||
getString(R.string.preference_enhanced_tracking_protection_strict_default)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindStandard() {
|
|
||||||
val keyStandard = getString(R.string.pref_key_tracking_protection_standard_option)
|
|
||||||
radioStandard = requireNotNull(findPreference(keyStandard))
|
|
||||||
radioStandard.contentDescription =
|
|
||||||
getString(R.string.preference_enhanced_tracking_protection_standard_info_button)
|
|
||||||
|
|
||||||
radioStandard.onClickListener {
|
|
||||||
updateCustomOptionsVisibility()
|
|
||||||
updateTrackingProtectionPolicy()
|
|
||||||
context?.metrics?.track(
|
|
||||||
Event.TrackingProtectionSettingChanged(
|
|
||||||
Event.TrackingProtectionSettingChanged.Setting.STANDARD
|
Event.TrackingProtectionSettingChanged.Setting.STANDARD
|
||||||
)
|
TrackingProtectionMode.STRICT ->
|
||||||
)
|
Event.TrackingProtectionSettingChanged.Setting.STRICT
|
||||||
|
TrackingProtectionMode.CUSTOM -> null
|
||||||
|
}?.let { setting ->
|
||||||
|
metrics.track(Event.TrackingProtectionSettingChanged(setting))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
radioStandard.onInfoClickListener {
|
radio.onInfoClickListener {
|
||||||
nav(
|
nav(
|
||||||
R.id.trackingProtectionFragment,
|
R.id.trackingProtectionFragment,
|
||||||
TrackingProtectionFragmentDirections
|
TrackingProtectionFragmentDirections
|
||||||
.actionTrackingProtectionFragmentToTrackingProtectionBlockingFragment(
|
.actionTrackingProtectionFragmentToTrackingProtectionBlockingFragment(mode)
|
||||||
getString(R.string.preference_enhanced_tracking_protection_standard_option)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return radio
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindCustom() {
|
private fun bindCustom(): RadioButtonInfoPreference {
|
||||||
val keyCustom = getString(R.string.pref_key_tracking_protection_custom_option)
|
val radio = bindTrackingProtectionRadio(TrackingProtectionMode.CUSTOM)
|
||||||
radioCustom = requireNotNull(findPreference(keyCustom))
|
|
||||||
radioCustom.contentDescription =
|
|
||||||
getString(R.string.preference_enhanced_tracking_protection_custom_info_button)
|
|
||||||
|
|
||||||
radioCustom.onClickListener {
|
|
||||||
updateCustomOptionsVisibility()
|
|
||||||
updateTrackingProtectionPolicy()
|
|
||||||
}
|
|
||||||
radioCustom.onInfoClickListener {
|
|
||||||
nav(
|
|
||||||
R.id.trackingProtectionFragment,
|
|
||||||
TrackingProtectionFragmentDirections
|
|
||||||
.actionTrackingProtectionFragmentToTrackingProtectionBlockingFragment(
|
|
||||||
getString(R.string.preference_enhanced_tracking_protection_custom)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
customCookies = requireNotNull(
|
customCookies = requireNotNull(
|
||||||
findPreference(
|
findPreference(
|
||||||
|
@ -254,6 +215,8 @@ class TrackingProtectionFragment : PreferenceFragmentCompat() {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCustomOptionsVisibility()
|
updateCustomOptionsVisibility()
|
||||||
|
|
||||||
|
return radio
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateTrackingProtectionPolicy() {
|
private fun updateTrackingProtectionPolicy() {
|
||||||
|
@ -265,7 +228,11 @@ class TrackingProtectionFragment : PreferenceFragmentCompat() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRadioGroups() {
|
private fun setupRadioGroups(
|
||||||
|
radioStrict: RadioButtonInfoPreference,
|
||||||
|
radioStandard: RadioButtonInfoPreference,
|
||||||
|
radioCustom: RadioButtonInfoPreference
|
||||||
|
) {
|
||||||
radioStandard.addToRadioGroup(radioStrict)
|
radioStandard.addToRadioGroup(radioStrict)
|
||||||
radioStrict.addToRadioGroup(radioStandard)
|
radioStrict.addToRadioGroup(radioStandard)
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,7 @@ class SwitchWithDescription @JvmOverloads constructor(
|
||||||
R.drawable.ic_tracking_protection
|
R.drawable.ic_tracking_protection
|
||||||
)
|
)
|
||||||
switch_widget.putCompoundDrawablesRelativeWithIntrinsicBounds(
|
switch_widget.putCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||||
start = AppCompatResources.getDrawable(
|
start = AppCompatResources.getDrawable(context, id)
|
||||||
context,
|
|
||||||
id
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
trackingProtectionCategoryTitle.text = resources.getString(
|
trackingProtectionCategoryTitle.text = resources.getString(
|
||||||
getResourceId(
|
getResourceId(
|
||||||
|
|
|
@ -53,7 +53,7 @@ class TrackerBuckets {
|
||||||
/**
|
/**
|
||||||
* Gets the tracker URLs for a given category.
|
* Gets the tracker URLs for a given category.
|
||||||
*/
|
*/
|
||||||
operator fun get(key: TrackingProtectionCategory, blocked: Boolean) =
|
fun get(key: TrackingProtectionCategory, blocked: Boolean) =
|
||||||
if (blocked) buckets.blockedBucketMap[key].orEmpty() else buckets.loadedBucketMap[key].orEmpty()
|
if (blocked) buckets.blockedBucketMap[key].orEmpty() else buckets.loadedBucketMap[key].orEmpty()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -18,42 +18,33 @@ class TrackingProtectionBlockingFragment :
|
||||||
Fragment(R.layout.fragment_tracking_protection_blocking) {
|
Fragment(R.layout.fragment_tracking_protection_blocking) {
|
||||||
|
|
||||||
private val args: TrackingProtectionBlockingFragmentArgs by navArgs()
|
private val args: TrackingProtectionBlockingFragmentArgs by navArgs()
|
||||||
private var isCustomProtection: Boolean = false
|
private val settings by lazy { requireContext().settings() }
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
isCustomProtection = requireContext().settings().useCustomTrackingProtection
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
when (args.protectionMode) {
|
when (args.protectionMode) {
|
||||||
|
TrackingProtectionMode.STANDARD -> {
|
||||||
getString(R.string.preference_enhanced_tracking_protection_standard_option) -> {
|
|
||||||
category_tracking_content.isVisible = false
|
category_tracking_content.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
getString(R.string.preference_enhanced_tracking_protection_strict) -> return
|
TrackingProtectionMode.STRICT -> {}
|
||||||
|
|
||||||
getString(R.string.preference_enhanced_tracking_protection_custom) -> {
|
TrackingProtectionMode.CUSTOM -> {
|
||||||
category_fingerprinters.isVisible =
|
category_fingerprinters.isVisible =
|
||||||
requireContext().settings().blockFingerprintersInCustomTrackingProtection
|
settings.blockFingerprintersInCustomTrackingProtection
|
||||||
category_cryptominers.isVisible =
|
category_cryptominers.isVisible =
|
||||||
requireContext().settings().blockCryptominersInCustomTrackingProtection
|
settings.blockCryptominersInCustomTrackingProtection
|
||||||
category_cookies.isVisible =
|
category_cookies.isVisible =
|
||||||
requireContext().settings().blockCookiesInCustomTrackingProtection
|
settings.blockCookiesInCustomTrackingProtection
|
||||||
category_tracking_content.isVisible =
|
category_tracking_content.isVisible =
|
||||||
requireContext().settings().blockTrackingContentInCustomTrackingProtection
|
settings.blockTrackingContentInCustomTrackingProtection
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
showToolbar(args.protectionMode)
|
showToolbar(getString(args.protectionMode.titleRes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.mozilla.fenix.trackingprotection
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.content.withStyledAttributes
|
import androidx.core.content.withStyledAttributes
|
||||||
import kotlinx.android.synthetic.main.tracking_protection_category.view.*
|
import kotlinx.android.synthetic.main.tracking_protection_category.view.*
|
||||||
|
@ -30,7 +31,7 @@ class TrackingProtectionCategoryItem @JvmOverloads constructor(
|
||||||
R.styleable.TrackingProtectionCategory_categoryItemIcon,
|
R.styleable.TrackingProtectionCategory_categoryItemIcon,
|
||||||
R.drawable.ic_cryptominers
|
R.drawable.ic_cryptominers
|
||||||
)
|
)
|
||||||
trackingProtectionCategoryIcon?.background = resources.getDrawable(id, context.theme)
|
trackingProtectionCategoryIcon?.background = AppCompatResources.getDrawable(context, id)
|
||||||
trackingProtectionCategoryTitle?.text = resources.getString(
|
trackingProtectionCategoryTitle?.text = resources.getString(
|
||||||
getResourceId(
|
getResourceId(
|
||||||
R.styleable.TrackingProtectionCategory_categoryItemTitle,
|
R.styleable.TrackingProtectionCategory_categoryItemTitle,
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* 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.trackingprotection
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import kotlinx.android.parcel.Parcelize
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
enum class TrackingProtectionMode(
|
||||||
|
@StringRes val preferenceKey: Int,
|
||||||
|
@StringRes val titleRes: Int,
|
||||||
|
@StringRes val contentDescriptionRes: Int
|
||||||
|
) : Parcelable {
|
||||||
|
|
||||||
|
STANDARD(
|
||||||
|
preferenceKey = R.string.pref_key_tracking_protection_standard_option,
|
||||||
|
titleRes = R.string.preference_enhanced_tracking_protection_standard_option,
|
||||||
|
contentDescriptionRes = R.string.preference_enhanced_tracking_protection_standard_info_button
|
||||||
|
),
|
||||||
|
STRICT(
|
||||||
|
preferenceKey = R.string.pref_key_tracking_protection_strict_default,
|
||||||
|
titleRes = R.string.preference_enhanced_tracking_protection_strict,
|
||||||
|
contentDescriptionRes = R.string.preference_enhanced_tracking_protection_strict_info_button
|
||||||
|
),
|
||||||
|
CUSTOM(
|
||||||
|
preferenceKey = R.string.pref_key_tracking_protection_custom_option,
|
||||||
|
titleRes = R.string.preference_enhanced_tracking_protection_custom,
|
||||||
|
contentDescriptionRes = R.string.preference_enhanced_tracking_protection_custom_info_button
|
||||||
|
)
|
||||||
|
}
|
|
@ -57,6 +57,16 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), UserInt
|
||||||
private lateinit var trackingProtectionStore: TrackingProtectionStore
|
private lateinit var trackingProtectionStore: TrackingProtectionStore
|
||||||
private lateinit var trackingProtectionView: TrackingProtectionPanelView
|
private lateinit var trackingProtectionView: TrackingProtectionPanelView
|
||||||
private lateinit var trackingProtectionInteractor: TrackingProtectionPanelInteractor
|
private lateinit var trackingProtectionInteractor: TrackingProtectionPanelInteractor
|
||||||
|
private lateinit var trackingProtectionUseCases: TrackingProtectionUseCases
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
val components = requireComponents
|
||||||
|
trackingProtectionUseCases = TrackingProtectionUseCases(
|
||||||
|
sessionManager = components.core.sessionManager,
|
||||||
|
engine = components.core.engine
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
@ -85,47 +95,34 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), UserInt
|
||||||
)
|
)
|
||||||
trackingProtectionView =
|
trackingProtectionView =
|
||||||
TrackingProtectionPanelView(view.fragment_tp, trackingProtectionInteractor)
|
TrackingProtectionPanelView(view.fragment_tp, trackingProtectionInteractor)
|
||||||
updateTrackers()
|
session?.let { updateTrackers(it) }
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
private val sessionObserver = object : Session.Observer {
|
private val sessionObserver = object : Session.Observer {
|
||||||
override fun onUrlChanged(session: Session, url: String) {
|
override fun onUrlChanged(session: Session, url: String) {
|
||||||
trackingProtectionStore.dispatch(
|
trackingProtectionStore.dispatch(TrackingProtectionAction.UrlChange(url))
|
||||||
TrackingProtectionAction.UrlChange(url)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTrackerBlocked(session: Session, tracker: Tracker, all: List<Tracker>) {
|
override fun onTrackerBlocked(session: Session, tracker: Tracker, all: List<Tracker>) {
|
||||||
updateTrackers()
|
updateTrackers(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTrackerLoaded(session: Session, tracker: Tracker, all: List<Tracker>) {
|
override fun onTrackerLoaded(session: Session, tracker: Tracker, all: List<Tracker>) {
|
||||||
updateTrackers()
|
updateTrackers(session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateTrackers() {
|
private fun updateTrackers(session: Session) {
|
||||||
context?.let { context ->
|
trackingProtectionUseCases.fetchTrackingLogs(
|
||||||
val session =
|
session,
|
||||||
context.components.core.sessionManager.findSessionById(args.sessionId) ?: return
|
onSuccess = {
|
||||||
val useCase = TrackingProtectionUseCases(
|
trackingProtectionStore.dispatch(TrackingProtectionAction.TrackerLogChange(it))
|
||||||
sessionManager = context.components.core.sessionManager,
|
},
|
||||||
engine = context.components.core.engine
|
onError = {
|
||||||
)
|
Logger.error("TrackingProtectionUseCases - fetchTrackingLogs onError", it)
|
||||||
|
}
|
||||||
useCase.fetchTrackingLogs(
|
)
|
||||||
session,
|
|
||||||
onSuccess = {
|
|
||||||
trackingProtectionStore.dispatch(
|
|
||||||
TrackingProtectionAction.TrackerLogChange(it)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
onError = {
|
|
||||||
Logger.error("TrackingProtectionUseCases - fetchTrackingLogs onError", it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
@ -150,17 +147,13 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), UserInt
|
||||||
|
|
||||||
private fun toggleTrackingProtection(isEnabled: Boolean) {
|
private fun toggleTrackingProtection(isEnabled: Boolean) {
|
||||||
context?.let { context ->
|
context?.let { context ->
|
||||||
val useCase = TrackingProtectionUseCases(
|
|
||||||
sessionManager = context.components.core.sessionManager,
|
|
||||||
engine = context.components.core.engine
|
|
||||||
)
|
|
||||||
val session = context.components.core.sessionManager.findSessionById(args.sessionId)
|
val session = context.components.core.sessionManager.findSessionById(args.sessionId)
|
||||||
session?.let {
|
session?.let {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
useCase.removeException(it)
|
trackingProtectionUseCases.removeException(it)
|
||||||
} else {
|
} else {
|
||||||
context.metrics.track(Event.TrackingProtectionException)
|
context.metrics.track(Event.TrackingProtectionException)
|
||||||
useCase.addException(it)
|
trackingProtectionUseCases.addException(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
with(context.components) {
|
with(context.components) {
|
||||||
|
|
|
@ -77,11 +77,18 @@ class TrackingProtectionPanelView(
|
||||||
|
|
||||||
private var shouldFocusAccessibilityView: Boolean = true
|
private var shouldFocusAccessibilityView: Boolean = true
|
||||||
|
|
||||||
fun update(state: TrackingProtectionState) {
|
init {
|
||||||
if (state.mode != mode) {
|
protection_settings.setOnClickListener {
|
||||||
mode = state.mode
|
interactor.selectTrackingProtectionSettings()
|
||||||
}
|
}
|
||||||
|
details_back.setOnClickListener {
|
||||||
|
interactor.onBackPressed()
|
||||||
|
}
|
||||||
|
setCategoryClickListeners()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(state: TrackingProtectionState) {
|
||||||
|
mode = state.mode
|
||||||
bucketedTrackers.updateIfNeeded(state.listTrackers)
|
bucketedTrackers.updateIfNeeded(state.listTrackers)
|
||||||
|
|
||||||
when (val mode = state.mode) {
|
when (val mode = state.mode) {
|
||||||
|
@ -103,16 +110,31 @@ class TrackingProtectionPanelView(
|
||||||
not_blocking_header.isGone = bucketedTrackers.loadedIsEmpty()
|
not_blocking_header.isGone = bucketedTrackers.loadedIsEmpty()
|
||||||
bindUrl(state.url)
|
bindUrl(state.url)
|
||||||
bindTrackingProtectionInfo(state.isTrackingProtectionEnabled)
|
bindTrackingProtectionInfo(state.isTrackingProtectionEnabled)
|
||||||
protection_settings.setOnClickListener {
|
|
||||||
interactor.selectTrackingProtectionSettings()
|
|
||||||
}
|
|
||||||
|
|
||||||
blocking_header.isGone = bucketedTrackers.blockedIsEmpty()
|
blocking_header.isGone = bucketedTrackers.blockedIsEmpty()
|
||||||
updateCategoryVisibility()
|
updateCategoryVisibility()
|
||||||
setCategoryClickListeners()
|
|
||||||
focusAccessibilityLastUsedCategory(state.lastAccessedCategory)
|
focusAccessibilityLastUsedCategory(state.lastAccessedCategory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setUIForDetailsMode(
|
||||||
|
category: TrackingProtectionCategory,
|
||||||
|
categoryBlocked: Boolean
|
||||||
|
) {
|
||||||
|
normal_mode.visibility = View.GONE
|
||||||
|
details_mode.visibility = View.VISIBLE
|
||||||
|
category_title.setText(category.title)
|
||||||
|
blocking_text_list.text = bucketedTrackers.get(category, categoryBlocked).joinToString("\n")
|
||||||
|
category_description.setText(category.description)
|
||||||
|
details_blocking_header.setText(if (categoryBlocked) {
|
||||||
|
R.string.enhanced_tracking_protection_blocked
|
||||||
|
} else {
|
||||||
|
R.string.enhanced_tracking_protection_allowed
|
||||||
|
})
|
||||||
|
|
||||||
|
details_back.requestFocus()
|
||||||
|
details_back.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will force accessibility focus to last entered details category.
|
* Will force accessibility focus to last entered details category.
|
||||||
* Called when user returns from details_mode.
|
* Called when user returns from details_mode.
|
||||||
|
@ -180,32 +202,6 @@ class TrackingProtectionPanelView(
|
||||||
interactor.openDetails(category, categoryBlocked = !isLoaded(v))
|
interactor.openDetails(category, categoryBlocked = !isLoaded(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUIForDetailsMode(
|
|
||||||
category: TrackingProtectionCategory,
|
|
||||||
categoryBlocked: Boolean
|
|
||||||
) {
|
|
||||||
val context = view.context
|
|
||||||
|
|
||||||
normal_mode.visibility = View.GONE
|
|
||||||
details_mode.visibility = View.VISIBLE
|
|
||||||
category_title.text = context.getString(category.title)
|
|
||||||
blocking_text_list.text = bucketedTrackers.get(category, categoryBlocked).joinToString("\n")
|
|
||||||
category_description.text = context.getString(category.description)
|
|
||||||
details_blocking_header.text = context.getString(
|
|
||||||
if (categoryBlocked) {
|
|
||||||
R.string.enhanced_tracking_protection_blocked
|
|
||||||
} else {
|
|
||||||
R.string.enhanced_tracking_protection_allowed
|
|
||||||
}
|
|
||||||
)
|
|
||||||
details_back.setOnClickListener {
|
|
||||||
interactor.onBackPressed()
|
|
||||||
}
|
|
||||||
|
|
||||||
details_back.requestFocus()
|
|
||||||
details_back.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindUrl(url: String) {
|
private fun bindUrl(url: String) {
|
||||||
this.url.text = url.toUri().hostWithoutCommonPrefixes
|
this.url.text = url.toUri().hostWithoutCommonPrefixes
|
||||||
}
|
}
|
||||||
|
@ -239,9 +235,9 @@ class TrackingProtectionPanelView(
|
||||||
ViewCompat.setAccessibilityDelegate(view2, object : AccessibilityDelegateCompat() {
|
ViewCompat.setAccessibilityDelegate(view2, object : AccessibilityDelegateCompat() {
|
||||||
override fun onInitializeAccessibilityNodeInfo(
|
override fun onInitializeAccessibilityNodeInfo(
|
||||||
host: View?,
|
host: View?,
|
||||||
info: AccessibilityNodeInfoCompat?
|
info: AccessibilityNodeInfoCompat
|
||||||
) {
|
) {
|
||||||
info?.setTraversalAfter(view1)
|
info.setTraversalAfter(view1)
|
||||||
super.onInitializeAccessibilityNodeInfo(host, info)
|
super.onInitializeAccessibilityNodeInfo(host, info)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.trackingprotection
|
package org.mozilla.fenix.trackingprotection
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
import mozilla.components.concept.engine.content.blocking.TrackerLog
|
import mozilla.components.concept.engine.content.blocking.TrackerLog
|
||||||
import mozilla.components.lib.state.Action
|
import mozilla.components.lib.state.Action
|
||||||
|
@ -73,7 +74,10 @@ data class TrackingProtectionState(
|
||||||
/**
|
/**
|
||||||
* The 5 categories of Tracking Protection to display
|
* The 5 categories of Tracking Protection to display
|
||||||
*/
|
*/
|
||||||
enum class TrackingProtectionCategory(val title: Int, val description: Int) {
|
enum class TrackingProtectionCategory(
|
||||||
|
@StringRes val title: Int,
|
||||||
|
@StringRes val description: Int
|
||||||
|
) {
|
||||||
SOCIAL_MEDIA_TRACKERS(
|
SOCIAL_MEDIA_TRACKERS(
|
||||||
R.string.etp_social_media_trackers_title,
|
R.string.etp_social_media_trackers_title,
|
||||||
R.string.etp_social_media_trackers_description
|
R.string.etp_social_media_trackers_description
|
||||||
|
|
|
@ -188,7 +188,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="20dp"
|
android:layout_marginStart="20dp"
|
||||||
android:tint="?attr/primaryText"
|
app:tint="?attr/primaryText"
|
||||||
android:contentDescription="@string/etp_back_button_content_description"
|
android:contentDescription="@string/etp_back_button_content_description"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/category_description"
|
app:layout_constraintBottom_toBottomOf="@+id/category_description"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
|
|
@ -696,10 +696,11 @@
|
||||||
</dialog>
|
</dialog>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/trackingProtectionBlockingFragment"
|
android:id="@+id/trackingProtectionBlockingFragment"
|
||||||
android:name="org.mozilla.fenix.trackingprotection.TrackingProtectionBlockingFragment">
|
android:name="org.mozilla.fenix.trackingprotection.TrackingProtectionBlockingFragment"
|
||||||
|
tools:layout="@layout/fragment_tracking_protection_blocking">
|
||||||
<argument
|
<argument
|
||||||
android:name="protectionMode"
|
android:name="protectionMode"
|
||||||
app:argType="string" />
|
app:argType="org.mozilla.fenix.trackingprotection.TrackingProtectionMode" />
|
||||||
</fragment>
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/deleteBrowsingDataOnQuitFragment"
|
android:id="@+id/deleteBrowsingDataOnQuitFragment"
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/* 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.trackingprotection
|
||||||
|
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import kotlinx.android.synthetic.main.component_tracking_protection_panel.*
|
||||||
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
|
import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory.SOCIAL_MEDIA_TRACKERS
|
||||||
|
|
||||||
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
|
class TrackingProtectionPanelViewTest {
|
||||||
|
|
||||||
|
private lateinit var container: ViewGroup
|
||||||
|
private lateinit var interactor: TrackingProtectionPanelInteractor
|
||||||
|
private lateinit var view: TrackingProtectionPanelView
|
||||||
|
private val baseState = TrackingProtectionState(
|
||||||
|
session = null,
|
||||||
|
url = "",
|
||||||
|
isTrackingProtectionEnabled = false,
|
||||||
|
listTrackers = emptyList(),
|
||||||
|
mode = TrackingProtectionState.Mode.Normal,
|
||||||
|
lastAccessedCategory = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
container = FrameLayout(testContext)
|
||||||
|
interactor = mockk(relaxUnitFun = true)
|
||||||
|
view = TrackingProtectionPanelView(container, interactor)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNormalModeUi() {
|
||||||
|
view.update(baseState.copy(mode = TrackingProtectionState.Mode.Normal))
|
||||||
|
assertFalse(view.details_mode.isVisible)
|
||||||
|
assertTrue(view.normal_mode.isVisible)
|
||||||
|
assertTrue(view.protection_settings.isVisible)
|
||||||
|
assertFalse(view.not_blocking_header.isVisible)
|
||||||
|
assertFalse(view.blocking_header.isVisible)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPrivateModeUi() {
|
||||||
|
view.update(baseState.copy(
|
||||||
|
mode = TrackingProtectionState.Mode.Details(
|
||||||
|
selectedCategory = TrackingProtectionCategory.TRACKING_CONTENT,
|
||||||
|
categoryBlocked = false
|
||||||
|
)
|
||||||
|
))
|
||||||
|
assertTrue(view.details_mode.isVisible)
|
||||||
|
assertFalse(view.normal_mode.isVisible)
|
||||||
|
assertEquals(
|
||||||
|
testContext.getString(R.string.etp_tracking_content_title),
|
||||||
|
view.category_title.text
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
testContext.getString(R.string.etp_tracking_content_description),
|
||||||
|
view.category_description.text
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
testContext.getString(R.string.enhanced_tracking_protection_allowed),
|
||||||
|
view.details_blocking_header.text
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testProtectionSettings() {
|
||||||
|
view.protection_settings.performClick()
|
||||||
|
verify { interactor.selectTrackingProtectionSettings() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDetailsBack() {
|
||||||
|
view.details_back.performClick()
|
||||||
|
verify { interactor.onBackPressed() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSocialMediaTrackerClick() {
|
||||||
|
view.social_media_trackers.performClick()
|
||||||
|
verify { interactor.openDetails(SOCIAL_MEDIA_TRACKERS, categoryBlocked = true) }
|
||||||
|
|
||||||
|
view.social_media_trackers_loaded.performClick()
|
||||||
|
verify { interactor.openDetails(SOCIAL_MEDIA_TRACKERS, categoryBlocked = false) }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue